"""The understanding bundle (goal 24 task 2): the project Understanding ledger — the /api/saddle/understanding insert/read callback pair, the immutable history rows, and the current document riding the assignment payload.""" 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() print("== understanding: the migration ==") # A fresh database: M0001..M0004 ran at startup, so the table # exists with the goal-24 shape. tables = [r[0] for r in db_rows( "select name from sqlite_master where type = 'table'")] check("project_understandings" in tables, "M0004 creates the project_understandings table on a fresh DB") columns = [r[1] for r in db_rows("pragma table_info(project_understandings)")] check(columns == ["id", "project_id", "body", "commit_hash", "task_id", "created_at"], "the table carries the goal-24 columns (%s)" % columns) print("== understanding: POST auth + validation ==") status, _ = saddle_api("POST", "/api/saddle/understanding", None, {"project": "demo", "body": "x"}) check(status == 401, "POST rejects a missing token") status, _ = saddle_api("POST", "/api/saddle/understanding", "saddle-bogus", {"project": "demo", "body": "x"}) check(status == 401, "POST rejects a wrong token") status, body = saddle_api("POST", "/api/saddle/understanding", fake_token, {"project": "no-such-project", "body": "x"}) check(status == 400 and body.get("ok") is False, "POST rejects an unknown project") status, body = saddle_api("POST", "/api/saddle/understanding", fake_token, {"project": "demo", "body": " "}) check(status == 400 and body.get("ok") is False, "POST rejects an empty body") print("== understanding: inserts append history ==") status, body = saddle_api("POST", "/api/saddle/understanding", fake_token, {"project": "demo", "body": "# Demo understanding\n\nFirst revision.", "commit_hash": "abc1000", "task_id": 11}) check(status == 200 and body.get("ok") is True and int(body.get("understanding_id", 0)) > 0, "POST inserts and returns the understanding id") first_id = int(body["understanding_id"]) status, body = saddle_api("POST", "/api/saddle/understanding", fake_token, {"project": "demo", "body": "# Demo understanding\n\nSecond revision.", "commit_hash": "def2000"}) check(status == 200 and int(body["understanding_id"]) > first_id, "a refresh appends a LATER history row") second_id = int(body["understanding_id"]) rows = db_rows("select id, body, commit_hash, task_id" " from project_understandings order by id") check([r[0] for r in rows] == [first_id, second_id], "history rows are immutable appends in insert order") check(rows[0][2] == "abc1000" and rows[0][3] == 11 and rows[1][2] == "def2000" and rows[1][3] == 0, "rows keep the commit hash and the optional task id") print("== understanding: GET reads the current revision ==") status, _ = saddle_api("GET", "/api/saddle/understanding?project=demo", None) check(status == 401, "GET rejects a missing token") status, body = saddle_api( "GET", "/api/saddle/understanding?project=no-such-project", fake_token) check(status == 400, "GET rejects an unknown project") status, body = saddle_api("GET", "/api/saddle/understanding", fake_token) check(status == 400, "GET requires the project query parameter") status, body = saddle_api("GET", "/api/saddle/understanding?project=demo", fake_token) check(status == 200 and body.get("ok") is True, "GET answers with the current understanding") current = body.get("understanding") or {} check(current.get("body") == "# Demo understanding\n\nSecond revision.", "GET returns the NEWEST revision (%r)" % current.get("body", "")[:40]) check(current.get("commit_hash") == "def2000" and (current.get("created") or "").endswith("Z"), "GET carries the commit hash and an ISO-8601 stamp") # A project without any understanding answers null, not an error. state = slot_public(auth, "/projects", "projects") act(auth, state["create"], {"name": "plain", "git_url": "https://example.com/plain.git"}) status, body = saddle_api("GET", "/api/saddle/understanding?project=plain", fake_token) check(status == 200 and body.get("ok") is True and body.get("understanding") is None, "GET answers understanding null for a project with none") print("== understanding: rides the assignment payload ==") payload_count = len(fake.start_payloads) create_queued(auth, { "project_id": "1", "title": "Understanding dispatch", "description": "The current understanding rides the /start payload.", "priority": "2", }) check(wait_for(lambda: len(fake.start_payloads) > payload_count or False, timeout=30, what="understanding /start push") is not None, "dispatcher pushes the understanding task") payload = fake.start_payloads[-1] check("understanding" in payload, "the assignment payload carries an understanding member") check(payload.get("understanding") == "# Demo understanding\n\nSecond revision.", "the payload's understanding is the project's CURRENT revision") # A giant revision is head-clamped at 16000 chars (the payload cap). # created_at goes in as a raw epoch INTEGER like every other bundle # fixture: the ORM materialises DateTime columns from int64 (a text # value in a DATETIME column fails the element conversion, which # the project page read surfaces as a 500). conn = db() conn.execute("insert into project_understandings" " (project_id, body, commit_hash, task_id, created_at)" " values (1, ?, 'big0000', 0, strftime('%s','now'))", ("giant!" + "y" * 25000,)) conn.commit() conn.close() payload_count = len(fake.start_payloads) create_queued(auth, { "project_id": "1", "title": "Understanding cap dispatch", "priority": "2", }) check(wait_for(lambda: len(fake.start_payloads) > payload_count or False, timeout=30, what="cap /start push") is not None, "dispatcher pushes the cap task") shipped = fake.start_payloads[-1].get("understanding", "") check(len(shipped) == 16000 and shipped.startswith("giant!"), "the payload caps the understanding at 16000 chars, head kept (%d)" % len(shipped)) # No understanding yet: the member is present but empty. plain_id = int([p["id"] for p in slot_public(auth, "/projects", "projects")["projects"] if p["name"] == "plain"][0]) payload_count = len(fake.start_payloads) create_queued(auth, { "project_id": str(plain_id), "title": "No-understanding dispatch", "priority": "2", }) check(wait_for(lambda: len(fake.start_payloads) > payload_count or False, timeout=30, what="empty /start push") is not None, "dispatcher pushes the no-understanding task") check(fake.start_payloads[-1].get("understanding") == "", "a project without an understanding ships an empty string") print("== understanding: the project page section ==") # 'plain' has no understanding: empty current row, empty history, # but the refresh action is authored. plain_state = slot_public(auth, "/projects/%d" % plain_id, "project") check(plain_state.get("refresh_understanding") is not None, "the project slot authors the refresh action") check((plain_state.get("understanding_current") or {}).get("body", "x") == "", "a project without an understanding shows an empty current row") check(plain_state.get("understanding_history") == [], "a project without an understanding shows no history rows") # 'demo' (project 1) has three revisions by now (two API inserts + # the giant direct row): current is the giant, history is the two # API revisions newest first. demo_state = slot_public(auth, "/projects/1", "project") current_row = demo_state.get("understanding_current") or {} check(current_row.get("body", "").startswith("giant!"), "the page's current understanding is the newest revision") check(current_row.get("commit_hash") == "big0000" and current_row.get("has_commit") is True, "the current row carries the commit hash stamp flag") history = demo_state.get("understanding_history") or [] check([h["commit_hash"] for h in history] == ["def2000", "abc1000"], "the history lists the older revisions newest first (current not repeated)") check(history[0]["body"].endswith("Second revision.") and history[1]["body"].endswith("First revision."), "history rows keep their markdown bodies") print("== understanding: Refresh spins up the special task ==") # The 'plain' project: no notes, no understanding — a first refresh. result = act(auth, plain_state["refresh_understanding"], {}) check(any(d.get("type") == "notify" and d.get("kind") == "success" for d in result), "the first refresh notifies success") rows = db_rows("select id, title, status, mode, kind, description from tasks" " where title like 'Understanding refresh: plain'") check(len(rows) == 1, "refresh created exactly one task") refresh_id = rows[0][0] check(rows[0][2] == "queued" and rows[0][3] == "investigate" and rows[0][4] == "task", "the refresh task is queued, investigate mode, kind task (%s)" % (rows[0][2:5],)) brief = rows[0][5] or "" check("none — first refresh" in brief, "a first refresh embeds 'none — first refresh' as the previous hash") check("Previous document:" not in brief, "a first refresh carries no previous document") check("save_understanding" in brief and "git rev-parse HEAD" in brief, "the brief mandates the save_understanding finishing move") check("do not edit any files" in brief, "the brief states the investigate-mode no-edit constraint") # A system comment marks the refresh on the task thread. conn = db() marker = conn.execute( "select count(*) from task_comments where task_id = ? and author = 'system'" " and body like 'Understanding refresh queued%'", (refresh_id,)).fetchone()[0] conn.close() check(marker == 1, "the refresh task carries the system comment marker") print("== understanding: a live refresh refuses a second ==") plain_state = slot_public(auth, "/projects/%d" % plain_id, "project") refused = act(auth, plain_state["refresh_understanding"], {}) check(any(d.get("type") == "notify" and d.get("kind") == "error" and "already running" in (d.get("message") or "") for d in refused), "a second refresh while the task is live refuses") rows = db_rows("select count(*) from tasks" " where title like 'Understanding refresh: plain'") check(rows[0][0] == 1, "the refused refresh created no second task") print("== understanding: refresh against an existing document ==") # The demo project has a current understanding + project notes: # the brief must embed the old hash, the old document and the notes. conn = db() conn.execute("insert into project_notes (project_id, source_task_id, body," " created_at) values (1, 0, ?, strftime('%s','now'))", ("Demo note one: the test harness lives in test/.",)) conn.execute("insert into project_notes (project_id, source_task_id, body," " created_at) values (1, 0, ?, strftime('%s','now') + 1)", ("Demo note two: meson builds everything.",)) conn.commit() conn.close() demo_state = slot_public(auth, "/projects/1", "project") result = act(auth, demo_state["refresh_understanding"], {}) check(any(d.get("type") == "notify" and d.get("kind") == "success" for d in result), "refreshing a project with an understanding succeeds") row = db_rows("select id, description from tasks" " where title like 'Understanding refresh: demo'")[0] demo_brief = row[1] check("Previous commit hash: big0000" in demo_brief, "the brief embeds the previous document's commit hash") check("```markdown" in demo_brief and "giant!" in demo_brief, "the brief embeds the previous document in a markdown fence") check("git log" in demo_brief and "..HEAD" in demo_brief, "the brief directs the git-history review since the old hash") check("Project notes from other agents:" in demo_brief and "Demo note one: the test harness lives in test/." in demo_brief and "Demo note two: meson builds everything." in demo_brief, "the brief embeds every project note") print("== understanding: the refresh task runs, saves, refresh works again ==") # The fake saddle picks the queued plain refresh up (it asks when # idle), runs it to done, and the understanding lands via the API. check(wait_for(lambda: any( int(p.get("task", {}).get("id") or 0) == refresh_id for p in fake.start_payloads) or False, timeout=30, what="refresh task assignment") is not None, "the dispatcher assigns the refresh task to the saddle") fake.push_results("done", summary="explored and saved the understanding") 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": "plain", "body": "# Plain understanding\n\nFirst map.", "commit_hash": "fff3000", "task_id": refresh_id}) check(status == 200 and body.get("ok") is True, "the completed refresh saves its understanding via the API") plain_state = slot_public(auth, "/projects/%d" % plain_id, "project") current_row = plain_state.get("understanding_current") or {} check(current_row.get("body") == "# Plain understanding\n\nFirst map." and current_row.get("commit_hash") == "fff3000", "the page shows the new current understanding after the save") check(plain_state.get("understanding_history") == [], "the saved revision is current, not duplicated into history") # Terminal refresh task: a new refresh is allowed again. result = act(auth, plain_state["refresh_understanding"], {}) check(any(d.get("type") == "notify" and d.get("kind") == "success" for d in result), "after the refresh task completes a new refresh is allowed") rows = db_rows("select count(*) from tasks" " where title like 'Understanding refresh: plain'") check(rows[0][0] == 2, "the second refresh created its task") # The new live task blocks again, and the new current doc is now # the previous one in the fresh brief. plain_state = slot_public(auth, "/projects/%d" % plain_id, "project") refused = act(auth, plain_state["refresh_understanding"], {}) check(any(d.get("type") == "notify" and d.get("kind") == "error" and "already running" in (d.get("message") or "") for d in refused), "the new live refresh blocks a third") row = db_rows("select description from tasks" " where title like 'Understanding refresh: plain'" " order by id desc")[0] check("Previous commit hash: fff3000" in (row[0] or "") and "First map." in (row[0] or ""), "the refreshed brief embeds the new previous hash and document")