From d13559f9a2903ebc6345166af49b2950dcb8900b Mon Sep 17 00:00:00 2001 From: reachableceo Date: Sat, 29 Aug 2026 05:26:50 -0500 Subject: [PATCH] =?UTF-8?q?ops(redmine):=20roadmap=20build-out=20=E2=80=94?= =?UTF-8?q?=20versions,=20categories,=20fleet=20children,=20relations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Versions: V1 Core (closed), Beta 8/31, Production 9/1, Phase 3 9/7. Categories for all majors; 490-499 versioned+categorized+estimated; 490 blocks 492/493; 15 integration-fleet children (500-514) under 498; 515 ITAR provider routing; 516 session/context quality. --- logs/q-pdf.log | 2 +- logs/q-quota.log | 2 +- scripts/roadmap-buildout.py | 124 ++++++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 scripts/roadmap-buildout.py diff --git a/logs/q-pdf.log b/logs/q-pdf.log index e59ab4a..ae235fe 100644 --- a/logs/q-pdf.log +++ b/logs/q-pdf.log @@ -4,4 +4,4 @@ Failed to override models: large model: model "glm-5.2" found in multiple providers: litellm and zai. Please specify provider using 'provider/model' format. -I have the family patterns. Setting up the task list and starting.Typst stdin→stdout works. Testing image resolution with stdin input: \ No newline at end of file +I have the family patterns. Setting up the task list and starting.Typst stdin→stdout works. Testing image resolution with stdin input:Engine eval conclusive: typst 0.94s vs pandoc+xelatex 7.7s, typst supports stdin/file→stdout PDF with `--root` image resolution. Typst wins. Now building the Go implementation.go-chart vendored. Writing core packages:Now the markdown parser (AST):Now the typst renderer (AST → typst markup + document composition): \ No newline at end of file diff --git a/logs/q-quota.log b/logs/q-quota.log index 41aa7d6..df0673b 100644 --- a/logs/q-quota.log +++ b/logs/q-quota.log @@ -5,4 +5,4 @@ Tickets confirmed. Now researching the z.ai usage API surface. Agent processing failed: failed to start agent processing stream: failed to fetch URL: Post "https://sourcegraph.com/.api/graphql": context deadline exceeded (Client.Timeout exceeded while awaiting headers). -Codebase understood. Now researching the z.ai usage endpoint.Documented findings: coding plan has 5-hour + weekly credit buckets; **peak hours = Mon–Fri 14:00–18:00 SGT ≈ 01:00–05:00 CST** (Charles's guess confirmed). No documented usage REST endpoint — probing for the undocumented one with a real key.Gateway responds under `/api/coding/*` but no public usage route. One final probe batch, plus checking LiteLLM's own documented spend API (master key in container env):Research complete. Now checking dev workflow, git state, and test conventions before writing code.All context gathered. Checking the TOML subset parser's number handling before writing the config surface:Writing the implementation now — config surface first:Now the `[quota]` + `[resources]` config structs:Now the `internal/quota` package — snapshot + parser:Estimator + schedule:Resource monitor (ticket 491):Shared state — minimal stdlib RESP client:Usage poller:The decision gate:Loop integration — the gate wiring:Now wire the gate into the Conductor struct and daemon flow:Now the daemon: gate consultation before dispatch, usage recording after turn, startup status line. Also state.go extensions:Now add usage aggregation to `loopState`:Now the CLI `harness quota` subcommand:Adding an exported usage accessor in the loop package, then the CLI:Now the CLI subcommand in main.go:Now the test suite — quota package first:Resources + fake-redis tests:Config load test + loop integration tests:Extend the fakeRedmine fixture with per-issue classes:First build pass to catch compile errors: \ No newline at end of file +Codebase understood. Now researching the z.ai usage endpoint.Documented findings: coding plan has 5-hour + weekly credit buckets; **peak hours = Mon–Fri 14:00–18:00 SGT ≈ 01:00–05:00 CST** (Charles's guess confirmed). No documented usage REST endpoint — probing for the undocumented one with a real key.Gateway responds under `/api/coding/*` but no public usage route. One final probe batch, plus checking LiteLLM's own documented spend API (master key in container env):Research complete. Now checking dev workflow, git state, and test conventions before writing code.All context gathered. Checking the TOML subset parser's number handling before writing the config surface:Writing the implementation now — config surface first:Now the `[quota]` + `[resources]` config structs:Now the `internal/quota` package — snapshot + parser:Estimator + schedule:Resource monitor (ticket 491):Shared state — minimal stdlib RESP client:Usage poller:The decision gate:Loop integration — the gate wiring:Now wire the gate into the Conductor struct and daemon flow:Now the daemon: gate consultation before dispatch, usage recording after turn, startup status line. Also state.go extensions:Now add usage aggregation to `loopState`:Now the CLI `harness quota` subcommand:Adding an exported usage accessor in the loop package, then the CLI:Now the CLI subcommand in main.go:Now the test suite — quota package first:Resources + fake-redis tests:Config load test + loop integration tests:Extend the fakeRedmine fixture with per-issue classes:First build pass to catch compile errors:Build clean. Running the full test suite: \ No newline at end of file diff --git a/scripts/roadmap-buildout.py b/scripts/roadmap-buildout.py new file mode 100644 index 0000000..c6e3b15 --- /dev/null +++ b/scripts/roadmap-buildout.py @@ -0,0 +1,124 @@ +import os, json, urllib.request + +URL = os.environ["REDMINE_URL"] +KEY = os.environ["REDMINE_API_KEY"] + +def api(method, path, body=None): + data = json.dumps(body).encode() if body is not None else None + req = urllib.request.Request(URL + path, data=data, + headers={"X-Redmine-API-Key": KEY, "Content-Type": "application/json"}, + method=method) + resp = urllib.request.urlopen(req, timeout=15) + raw = resp.read().decode() + return json.loads(raw) if raw.strip() else {} + +# 1. Versions (roadmap milestones) +versions = {} +for name, due, status in [ + ("V1 Core", "2026-08-28", "closed"), + ("Beta", "2026-08-31", "open"), + ("Production", "2026-09-01", "open"), + ("Phase 3 - Integrations", "2026-09-07", "open"), +]: + try: + v = api("POST", "/projects/MOPAC/versions.json", {"version": {"name": name, "due_date": due, "status": status, "sharing": "descendants"}}) + versions[name] = v["version"]["id"] + print("version created:", name, v["version"]["id"]) + except Exception as e: + print("version exists/err:", name, getattr(e, "code", e)) + +if not versions: + for v in api("GET", "/projects/MOPAC/versions.json")["versions"]: + versions[v["name"]] = v["id"] +print("versions:", versions) + +# 2. Categories +cats = {} +for name in ["Quota & Backpressure", "Model Selection", "Task Management", + "Deployment", "Briefing", "Secrets", "Integrations", + "Infrastructure", "Documentation"]: + try: + c = api("POST", "/projects/MOPAC/issue_categories.json", {"issue_category": {"name": name}}) + cats[name] = c["issue_category"]["id"] + print("cat created:", name) + except Exception: + pass +for c in api("GET", "/projects/MOPAC/issue_categories.json")["issue_categories"]: + cats[c["name"]] = c["id"] +print("cats:", len(cats)) + +# 3. Update majors: category, version, estimates +updates = [ + (490, "Quota & Backpressure", "Beta", 8), + (491, "Quota & Backpressure", "Beta", 3), + (492, "Model Selection", "Production", 5), + (493, "Task Management", "Production", 5), + (494, "Deployment", "Beta", 6), + (495, "Briefing", "Beta", 8), + (496, "Task Management", "Phase 3 - Integrations", 12), + (497, "Secrets", "Beta", 5), + (498, "Integrations", "Phase 3 - Integrations", 40), + (499, "Documentation", "Phase 3 - Integrations", 6), +] +for iid, cat, ver, hrs in updates: + api("PUT", "/issues/%d.json" % iid, {"issue": { + "category_id": cats[cat], "fixed_version_id": versions[ver], + "estimated_hours": hrs}}) + print("updated", iid, cat, ver, str(hrs) + "h") + +# 4. Relations: quota blocks dispatcher pieces +for to in (492, 493): + try: + api("POST", "/issues/490/relations.json", {"relation": {"issue_to_id": to, "relation_type": "blocks"}}) + print("relation 490 blocks", to) + except Exception: + pass + +# 5. Children of 498 (integration fleet) +children = [ + ("Google suite (docs/tasks/keep/gmail) MCP/CLI", "Normal", 8), + ("IMAP client integration", "Low", 5), + ("Linkwarden integration (tag-driven intake)", "Normal", 5), + ("Google Chat integration", "Low", 5), + ("Signal integration (QR login)", "Normal", 8), + ("Discord integration", "Low", 5), + ("Redmine Go CLI (replaces bash/python glue)", "Normal", 8), + ("Discourse Go client (tracked in 495, child for roadmap)", "Normal", 4), + ("Gitea Go client", "Normal", 5), + ("Browser automation (Chrome/Firefox/WebKit)", "Low", 12), + ("Linux SSH/MCP fleet (Kali, OpenVAS for security queue)", "Normal", 12), + ("Generic REST API driver", "Normal", 5), + ("Cloudron API integration", "Normal", 5), + ("HomeAssistant integration", "Low", 4), + ("Kubernetes integration", "Low", 8), +] +for subject, prio, hrs in children: + prio_id = 4 if prio == "Normal" else 3 + body = { + "issue": { + "project_id": "MOPAC", "subject": "[fleet] " + subject, + "priority_id": prio_id, + "category_id": cats["Integrations"], + "fixed_version_id": versions["Phase 3 - Integrations"], + "estimated_hours": hrs, + "parent_issue_id": 498, + "tracker_id": 2, + "description": "Child of umbrella #498 (MCP/CLI outbound integration fleet). One integration = one standalone ukrrs repo; loose coupling, config-driven, exec+JSON contracts. OAuth one-time browser flow preferred; QR for Signal. Language tiers apply (node = last resort + consult Charles). See SPEC-20260829-charles-brief.md.", + } + } + r = api("POST", "/issues.json", body) + print("child:", r["issue"]["id"], subject) + +# 6. Two brief items not yet ticketed +extra = [ + ("High-security provider routing (ITAR/TS-SCI: dedicated LiteLLM + internal models)", "Infrastructure", "Phase 3 - Integrations", 3, 8, + "Spec: Provider routing section. Some orchestrated work is ITAR/TS-SCI/proprietary and must route to internally hosted models via dedicated OpenWebUI instances; likely needs a dedicated high-security LiteLLM instance. Low priority, KEY requirement - design constraint to respect while building everything else."), + ("Session/context quality: long-running rapport + auto-compact handling", "Model Selection", "Production", 3, 8, + "Spec: workflow section. Crush+GLM-5.2 rapport: agents working hours-long bodies of work with auto-compaction. Meaty projects need bigger active working memory. Design how MOPAC conductor sessions persist/compact/resume across long work."), +] +for subject, cat, ver, prio, hrs, desc in extra: + r = api("POST", "/issues.json", {"issue": { + "project_id": "MOPAC", "subject": subject, "priority_id": prio, + "category_id": cats[cat], "fixed_version_id": versions[ver], + "estimated_hours": hrs, "tracker_id": 2, "description": desc}}) + print("extra:", r["issue"]["id"], subject[:50])