ops(redmine): roadmap build-out — versions, categories, fleet children, relations
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.
This commit is contained in:
+1
-1
@@ -4,4 +4,4 @@
|
|||||||
Failed to override models: large model: model "glm-5.2" found in multiple providers: litellm and zai. Please specify
|
Failed to override models: large model: model "glm-5.2" found in multiple providers: litellm and zai. Please specify
|
||||||
provider using 'provider/model' format.
|
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:
|
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):
|
||||||
+1
-1
@@ -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
|
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).
|
"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:
|
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:
|
||||||
@@ -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])
|
||||||
Reference in New Issue
Block a user