ops(redmine): 497 scale+cloudron corrections, two-level identity ticket filed

This commit is contained in:
2026-08-29 06:20:16 -05:00
parent 725c184511
commit b9035f28ba
3 changed files with 53 additions and 1 deletions
+3
View File
@@ -82,3 +82,6 @@
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 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
2026-08-29T05:29:53-05:00 | PMO | trackers corrected (Bug=defects only), bodies -> CommonMark; committed+pushed 2026-08-29T05:29:53-05:00 | PMO | trackers corrected (Bug=defects only), bodies -> CommonMark; committed+pushed
2026-08-29T05:45:03-05:00 | Work | ukrrs/mopac-pdf v0 done+pushed: Go md->PDF via digest-pinned typst 0.15.1, templates report/brief, pure-Go bar charts (go-chart), docker-only dev, tests+smoke green; REPORT-20260829-1300-pdf.md filed; task archived 2026-08-29T05:45:03-05:00 | Work | ukrrs/mopac-pdf v0 done+pushed: Go md->PDF via digest-pinned typst 0.15.1, templates report/brief, pure-Go bar charts (go-chart), docker-only dev, tests+smoke green; REPORT-20260829-1300-pdf.md filed; task archived
2026-08-29T06:03:06-05:00 | PMO | 3 turns verified+archived (quota fc518c4, deploy b7799ea, pdf 10e930e); Redmine 490/491/494/499 -> Done 100%; briefing RUNNING; dispatcher gated
2026-08-29T06:19:13-05:00 | PMO | 497 amended: per-account BW scale (100+ refs), one bootstrap seed per account, batch warm + memory cache
2026-08-29T06:19:29-05:00 | PMO | 497 corrected: BW machine accounts map to CLOUDRON accounts (per-vertical API identities), not raw Linux accounts
+1 -1
View File
@@ -1 +1 @@
Context gathered. Setting up the task list, then finishing recon (Redmine 495, deploy template, remotes).Redmine 495 confirms scope and repo name `ukrrs/mopac-discourse-go`. Creating the Gitea repo now.Repo created (id 428). Cloning and checking the push credential pattern.Recon complete. Building the client repo now.Now the typed surfaces: categories, topics, posts.Now the fake-server test suite:Now the CLI:Now the fake server for the smoke test, plus dev.sh/Makefile/env.example:The smoke.sh has ordering bugs — rewriting it cleanly: Context gathered. Setting up the task list, then finishing recon (Redmine 495, deploy template, remotes).Redmine 495 confirms scope and repo name `ukrrs/mopac-discourse-go`. Creating the Gitea repo now.Repo created (id 428). Cloning and checking the push credential pattern.Recon complete. Building the client repo now.Now the typed surfaces: categories, topics, posts.Now the fake-server test suite:Now the CLI:Now the fake server for the smoke test, plus dev.sh/Makefile/env.example:The smoke.sh has ordering bugs — rewriting it cleanly:Check gate green. Running the end-to-end smoke:Smoke OK. Writing the README and pushing the client:Now the live verification (before the README's claims stand):Live checks match the known state (reads 200, create 403). Committing and pushing the client:Part A complete. Wiring the dependency into the harness:Expected — nothing imports it yet. Writing Part B code first, then vendoring. Checking the TOML helpers:Now adding `BriefConfig` to the harness config:Now the Default, apply, and Validate entries:Now the Validate block — checking the current tail of Validate first:Extending the intake client with the windowed issue listing:Now the brief package core:Now delivery + orchestration:Now the Run orchestrator:Wiring the subcommand into main.go:Now the brief package test suite — fake Redmine, Gitea, and Discourse:Now config tests for `[brief]`, then vendoring and the check gate:
+49
View File
@@ -0,0 +1,49 @@
import os, json, urllib.request
URL = os.environ["REDMINE_URL"]
KEY = os.environ["REDMINE_API_KEY"]
cats = {c["name"]: c["id"] for c in
json.load(urllib.request.urlopen(urllib.request.Request(
URL + "/projects/MOPAC/issue_categories.json",
headers={"X-Redmine-API-Key": KEY}), timeout=15))["issue_categories"]}
vers = {v["name"]: v["id"] for v in
json.load(urllib.request.urlopen(urllib.request.Request(
URL + "/projects/MOPAC/versions.json",
headers={"X-Redmine-API-Key": KEY}), timeout=15))["versions"]}
print("cats:", cats, "versions:", vers)
desc = """# Two-level identity model: Linux account + Cloudron accounts
## Objective (Charles, 2026-08-29)
The harness must model TWO identity levels everywhere it acts:
- **Linux account** = runtime identity (where the daemon runs: reachableceo, TSGBOD, ..., COSWFO). Drives: state dirs, quota/usage attribution (the $200/mo breakdown is per vertical), Redmine scope, briefing rollup.
- **Cloudron accounts** = acting identities (N per Linux account, e.g. a dozen+). All actions in TSYS systems happen via API under Cloudron SSO identities; their credentials live in per-cloudron-account Bitwarden machine accounts (#497).
## Scope
- harness.toml gains an identity section: linux account name + cloudron account map (label -> credential refs via keyproxy mpk_ placeholders, per system: redmine, discourse, gitea, linkwarden, ...).
- Attribution stamped on every outbound action: loop JSONL + REPORT headers record linux account + cloudron identity used.
- deploy/accounts.tsv (from #494) gains a cloudron-accounts column; installer templates the identity section.
- Usage accounting (from #490) rolls up per linux account AND per cloudron identity.
- keyproxy ref lookup stays instance-local; cloudron label selects the BW machine account context (#497).
## Acceptance criteria
- A turn executed under a fake 2-account config attributes actions correctly at both levels.
- REPORT/JSONL show both identities; README documents the model.
## References
SPEC-20260829-charles-brief.md (cloudron accounts section); #497 scale amendment.
"""
body = json.dumps({"issue": {
"project_id": "MOPAC",
"subject": "Two-level identity model: Linux account (runtime) + Cloudron accounts (acting)",
"tracker_id": 2, "priority_id": 4,
"category_id": cats["Infrastructure"],
"fixed_version_id": vers["Production"],
"estimated_hours": 5,
"description": desc}}).encode()
req = urllib.request.Request(URL + "/issues.json", data=body,
headers={"X-Redmine-API-Key": KEY, "Content-Type": "application/json"}, method="POST")
r = json.load(urllib.request.urlopen(req, timeout=15))
print("ticket", r["issue"]["id"], "created")