From 23ca361025add30295c2637c9117fa866c8ae182 Mon Sep 17 00:00:00 2001 From: reachableceo Date: Sat, 29 Aug 2026 05:29:52 -0500 Subject: [PATCH] ops(redmine): re-track tickets (features/studies out of Bug), CommonMark bodies Bug tracker now reserved for actual defects: builds/designs -> Feature, studies/selftests -> Support. All major ticket bodies rewritten in CommonMark (# headers, fenced refs) replacing Textile syntax. --- log.md | 1 + logs/q-pdf.log | 2 +- logs/q-quota.log | 2 +- scripts/markdown-convert.py | 198 ++++++++++++++++++++++++++++++++++++ 4 files changed, 201 insertions(+), 2 deletions(-) create mode 100644 scripts/markdown-convert.py diff --git a/log.md b/log.md index 169a866..06f669b 100644 --- a/log.md +++ b/log.md @@ -79,3 +79,4 @@ 2026-08-29T05:18:52-05:00 | PMO | MAX PLAN: quota reset; default model back to glm-5.2; pdf turn dispatched parallel (q13); snapshot amended 2026-08-29T05:20:40-05:00 | PMO | language policy tiered: rust ok / python avoid-but-ok in supply chain / node last-resort + consult Charles (workers must stop-and-ask) 2026-08-29T05:24:29-05:00 | PMO | tickets 490-499 fleshed (objective/background/scope/acceptance/status structure); mopac-pmo repo live on Gitea, 7 atomic commits pushed; commit+push-as-we-go now standing practice +2026-08-29T05:26:51-05:00 | PMO | Redmine full-power: 4 versions, 9 categories, 10 majors updated, 15 fleet children (500-514), 515/516 added, relations set; roadmap-buildout.py committed diff --git a/logs/q-pdf.log b/logs/q-pdf.log index ae235fe..8b866ec 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: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 +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):Fixing several issues in the renderer (link parsing mid-sentence, table columns parens, image staging, header fill):Now the chart package (go-chart bar renderer):Now the engine (docker typst runner) and pdfinfo (page counter):Now the two typst templates:Now the CLI orchestration, embedded templates, and main: \ No newline at end of file diff --git a/logs/q-quota.log b/logs/q-quota.log index df0673b..9582e66 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:Build clean. Running the full test suite: \ 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:Fixing the five test issues (JSON escaping, non-numeric ids, float epsilon, shared-state wiring, zone semantics, credit math): \ No newline at end of file diff --git a/scripts/markdown-convert.py b/scripts/markdown-convert.py new file mode 100644 index 0000000..8354606 --- /dev/null +++ b/scripts/markdown-convert.py @@ -0,0 +1,198 @@ +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. Re-track: builds/designs -> Feature (2), studies/selftests -> Support (3) +for iid in (490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 483, 484, 486): + api("PUT", "/issues/%d.json" % iid, {"issue": {"tracker_id": 2}}) +for iid in (480, 481, 482, 485, 487): + api("PUT", "/issues/%d.json" % iid, {"issue": {"tracker_id": 3}}) +print("re-tracked: majors->Feature, studies->Support") + +# 2. Rewrite major bodies in CommonMark +MD = {} +MD[490] = """# Quota monitoring + back-pressure + usage management + +## Objective +Never again lose turns to a blind quota wall (8/28 19:00 incident killed two dispatched turns). Maximize 24x7 utilization of the z.ai MAX plan, with automatic tier-down before exhaustion and full visibility into bucket state. + +## Background +Spec of record: `docs/SPEC-20260829-charles-brief.md` (section "It's a marathon"). Charles upgraded to the MAX plan 8/29 (all buckets zeroed). Legacy-plan economics end 9/22 ($200/mo budget after: 2x z.ai + OpenRouter). Confirmed by build turn: peak hours = Mon-Fri 14:00-18:00 SGT (01:00-05:00 CST); buckets = 5-hour + weekly credits. + +## Scope +- Poll the z.ai coding-plan usage/limits endpoint; parse per-bucket used/limit/reset into a `QuotaSnapshot` (auth via key_ref, never logged). +- Central quota state shared by 9 harness instances on 2 hosts: decide Redis container vs LiteLLM-native (postgres spend DB already live at 192.168.3.78:4001) with documented rationale. +- Back-pressure in the loop: peak window = flash-tier classes only, heavy classes deferred with logged reason; quota-low = defer + surface, never hard-fail. +- All thresholds/schedule/TZ in the `[quota]` harness.toml section (CST default). +- Per vertical/class token+model accounting into the JSONL state (feeds future per-instance Discourse usage reports). + +## Acceptance criteria +- The 8/28 wall scenario replayed as a test: loop defers instead of dying. +- MAX-plan bucket shapes parse correctly (upgraded plan). +- Config surface documented in README per docs standard. + +## References / Status +TASK-20260829-0500-quota.md (mopac-pmo repo) — **IN PROGRESS** (work-q9).""" + +MD[491] = """# System resource monitoring + cgroup control + +## Objective +The loop must not dispatch builds into an overloaded host; wall-clock waste from resource contention is a real cost per the spec. + +## Scope +- Read-only monitor: load avg, mem available, disk free, IO delay (from /proc + /sys), polled alongside quota. +- Busy thresholds configurable (quota/resources config section); loop defers dispatch when busy, reason logged in JSONL. +- cgroup enforcement documented as deploy-time runbook section (deploy ticket #494 consumes it). + +## Acceptance criteria +- Injected fake /proc fixtures drive defer/pass decisions in tests. +- README documents thresholds + how to tune. + +## Status +IN PROGRESS (bundled with #490 in work-q9 turn).""" + +MD[492] = """# Phase-aware model selection + +## Objective +Route work *phases* to tiers: planning on a heavy model, chunk work on flash — per spec Roadmap 2. Quota-optimal without sacrificing plan quality. + +## Scope +- Phase source precedence: (1) Redmine custom field (configurable name, values plan/implement/review/grind), (2) `models.phases` config map phase-to-class, (3) fallback existing class map (behavior unchanged). +- REPORT header records model + phase + class used (telemetry for the future auto-classifier, v2, out of scope). +- Unknown phase value = hard config error naming valid phases. + +## Acceptance criteria +- Table-driven tests: custom-field phase beats fallback; unknown phase errors loudly. +- README config tables updated. + +## Status +QUEUED (TASK-20260829-0700-dispatcher.md; runs after deploy+briefing). Blocked by #490.""" + +MD[493] = """# Queue selection: priority / due-date / relations / quota / resources + +## Objective +The loop picks the *right* next task, not just the next task (spec Roadmap 3). + +## Scope +- Intake sorted priority desc, due_date asc (`redmine.selection` config). +- Redmine relations: skip issues blocked by open related issues, log reason. +- Quota + resource gates consulted before dispatch (builds on #490/#491). +- Every selection/deferral decision appended to loop JSONL (auditable). + +## Acceptance criteria +- Test proves a priority-5 due-today ticket beats priority-3 no-due. +- Blocked-relation skip covered by fake-Redmine test. + +## Status +QUEUED (same turn as #492). Blocked by #490.""" + +MD[494] = """# Multi-account harness deployment: 9 accounts, 2 hosts + +## Objective +MOPAC runs one Go daemon per Linux account across both VMs. PMO runtime cannot ssh/sudo, so this ticket ships everything needed for a ~10-minute Charles execution window. + +## Accounts +- ultix-streaming: reachableceo, TSGBOD, TSGCOO, TSGCTO, TSGCCO +- ultix-offstage (via ssh reachableceo-offstage): reachableceo-offstage, COSRCEO-Personal, COSRCEO-Biz, COSWFO + +## Scope +- `deploy/accounts.tsv` (account, host, vertical, redmine scope, port scheme). +- `deploy/install-account.sh` — idempotent, runs as target user, `~/.mopac` layout, template-substituted harness.toml, refuses to overwrite existing config/secrets. +- Static release binary via docker builder (Makefile `release` target, CGO=0). +- Distinct state dirs + ports per account (collision-free co-hosting). +- `deploy/runbook.md` — exact Charles sequence per host, verify steps (healthz + first `loop --once`), rollback. + +## Acceptance criteria +- Install script idempotence tested in a fake HOME. +- Port-derivation + template substitution tested. + +## Status +QUEUED next after quota turn (TASK-20260829-0900-deploy.md).""" + +MD[495] = """# COS morning briefing pipeline (0630 CST daily) + +## Objective +Charles gets a daily 0630 CST briefing from all three COS instances via Discourse (Redmine fallback). Beta 8/31 0600; first live briefing 9/1 0630. + +## Scope +- Part A: `ukrrs/mopac-discourse-go` client (categories/topics/posts, key via key_ref, fake-server tests; note current key 403s on category creation — admin key on the 1900 list). +- Part B: `harness brief` subcommand: digest window since last marker; sources = Redmine scope activity + Gitea open PRs + quota snapshot; clean markdown (per-vertical shipped/moved/incoming/PRs/quota); post to Discourse category, fallback = journal note on configured Redmine issue, never silent drop; idempotent per window. + +## Acceptance criteria +- Sample briefing rendered with fake data in the REPORT. +- Delivery verified both paths (discourse + fallback). + +## Status +QUEUED after deploy (TASK-20260829-1100-briefing.md).""" + +MD[496] = """# Review chain agents + kick-back protocol + +## Objective +Work ascends: IC builder > IC reviewer > manager > director > VP > SVP > COO/CTO/CCO review; any level can kick back down/across. Foundation of the morning briefing quality. + +## Scope +DESIGN FIRST (post-beta iteration): state machine for review levels, kick-back semantics, how it maps to Redmine workflows/statuses, agent-per-level prompts. Implementation tickets spawn from the design. + +## Status +BACKLOG (design doc ticket to be filed post-beta).""" + +MD[497] = """# keyproxy: live Bitwarden/Vault backends + MCP/CLI frontend + +## Objective +Real credential material only ever lives in Bitwarden (Vaultwarden) + Hashicorp Vault. keyproxy resolves `mpk_` placeholders at the wire; harness/LLM see placeholders only. Secrets never on disk. + +## Scope +- Integrate `ukrrs/mopac-bitwarden-go` v0 client (shipped 8/28, fake-tested) into the keyproxy `bitwarden:` backend (currently 501 stub). +- Vault KV v2 + AppRole backend via official MPL-2.0 Go client. +- Bitwarden-held SSH keys via ssh-agent/BW socket for Linux connections. +- MCP/API/CLI frontend surface for the harness. + +## Acceptance criteria +- keyproxy resolves a BW-backed ref end-to-end with live creds. +- Redaction tests prove material never appears in logs/errors. + +## Status +BLOCKED on Charles connecting BW machine creds (1900 tonight).""" + +MD[498] = """# MCP/CLI outbound integration fleet (umbrella) + +## Objective +MOPAC acts on the whole TSYS software estate via API (Cloudron accounts): google suite, IMAP, Linkwarden, Google Chat, Signal, Discord, Redmine, Discourse, Gitea, browsers, Linux ssh/MCP (Kali/OpenVAS for the security queue), Cloudron, HomeAssistant, Kubernetes. + +## Scope +One integration = one standalone ukrrs repo (loose coupling, config-driven, exec+JSON contracts). OAuth one-time browser flow preferred; QR for Signal. Children #500-#514 carry per-integration scope. Language tiers apply (node = last resort + consult Charles first). + +## Status +BACKLOG umbrella — children #500-#514.""" + +MD[499] = """# Beautiful PDF generation pipeline + +## Objective +Client-grade PDFs from markdown: budgets, travel itineraries, project plans, proposals, consulting reports, multi-year financials, engineering docs, charts/diagrams. Feeds COS briefings + TSYS deliverables. + +## Scope +- New repo `ukrrs/mopac-pdf`: Go CLI/library, markdown + front-matter input. +- Engine decision typst vs pandoc+latex (dockerized, digest-pinned; prebuilt engines are supply chain — our code stays Go). +- Templates v0: "report" (title page, TOC, headers/footers) + "brief" (1-3 page exec summary). +- Charts: pure-Go rendering embedded from fenced data blocks (one type proven v0). +- Golden tests: fixture .md -> PDF (non-empty, page count). + +## Acceptance criteria +- Sample outputs committed; briefing pipeline call-path documented. + +## Status +IN PROGRESS (work-q13, TASK-20260829-1300-pdf.md).""" + +for iid, desc in MD.items(): + api("PUT", "/issues/%d.json" % iid, {"issue": {"description": desc}}) + print("markdown:", iid)