add flotilla-core/0004/SESSION-0004.0-TRANSCRIPT-2026-06-07T22-20--2026-06-07T22-57.md + replace placeholder/variant SESSION-0004.0-TRANSCRIPT-2026-06-07T22-20--INPROGRESS.md
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
# Session 0004.0 — Transcript
|
||||
|
||||
> App: flotilla-core
|
||||
> Start: 2026-06-07T22-20 (PST)
|
||||
> End: 2026-06-07T22-57 (PST)
|
||||
> Type: planning-and-executing
|
||||
> Status: **FINALIZED.**
|
||||
>
|
||||
> Patchwatch label-set provisioning (issue #10): shipped v0.12.0, corrected to
|
||||
> v0.12.1 after a live finding, and ran the retroactive backfill.
|
||||
|
||||
## Pre-state
|
||||
|
||||
On clean `origin/main` at v0.11.0 (after PR #9, the 0.11.0 dedicated issue token).
|
||||
476 tests at session 0003's close. A prior session 0003 (Phase 2A capture) was
|
||||
left `--INPROGRESS` (its work merged via PRs #8/#9); its conversational context was
|
||||
unrecoverable, so it was noted as an ended-unfinalized leftover rather than having
|
||||
its transcript fabricated. This session (0004) claimed its own ID for the distinct
|
||||
issue-#10 work.
|
||||
|
||||
## Session arc
|
||||
|
||||
1. **Discovery.** Read `gitea.py`, `patchwatch.py`, `webhooks.py`, `onboarding.py`,
|
||||
the deploy phases, SPEC §4/§12.5, the config-onboarding spec, and the Phase-2
|
||||
design doc §7. Confirmed the gap: capture's least-privilege `GITEA_ISSUE_TOKEN`
|
||||
soft-fails labels (422) → unlabeled issues on un-provisioned repos.
|
||||
2. **Docs first** (docs-lead-automation): resolved design-doc §7 open question; added
|
||||
SPEC §12.6 "Patchwatch label provisioning"; extended config-onboarding §4 with the
|
||||
doctor `--patchwatch-labels` report. Committed as the foundation.
|
||||
3. **TDD implementation** (v0.12.0): `gitea.py` label APIs; `patchwatch.py` taxonomy
|
||||
(`all_label_names` derived from `issue_labels`) + `ensure_repo_labels`/`ensure_labels`
|
||||
+ `label_status`; CLI `ensure-labels [--all]`, `config doctor --patchwatch-labels`,
|
||||
deploy-time best-effort hook; belt-and-suspenders marker-based dedup. 502 → 506.
|
||||
4. **Code review** (high effort, 3 finder agents): caught a real dedup-regression
|
||||
(unfiltered `list_issues` had no pagination → duplicates beyond 50), an `--all`
|
||||
abort-on-first-token-gap, a `.status` contract gap, and dead-code/duplication.
|
||||
Fixed all TDD-first (extracted a shared `_get_paginated`; resilient `--all`; wired
|
||||
`label_specs` into production; centralized result wording). PR #11 merged.
|
||||
5. **Live backfill → finding.** `ensure-labels --all` 403'd on EVERY repo. Diagnosed
|
||||
via the admin PAT: it reads `/branches` but 403s on `/issues` AND `/labels` →
|
||||
**Gitea gates label management on issue scope (`write:issue`), not
|
||||
`write:repository`.** The deploy `GITEA_BOT_TOKEN` and the admin PAT both lack it;
|
||||
only `GITEA_ISSUE_TOKEN` can manage labels. Stopped and asked the operator.
|
||||
6. **Correction** (v0.12.1, operator chose option A): provisioning resolves
|
||||
`resolve_issue_token`. Docs corrected. PR #12 merged. 507 tests.
|
||||
7. **Backfill succeeded:** created the 8 missing `lane:*`/`sev:*` labels on
|
||||
`ben.stull/rfc-app` + all 9 on `wiggleverse/flotilla-core`; `rfc-app-ppe`
|
||||
idempotent; `wiggle-snip` skipped (no token bound, graceful).
|
||||
|
||||
## Cut state
|
||||
|
||||
On clean `origin/main` at **v0.12.1**. PRs #11 and #12 merged, branches deleted,
|
||||
507 tests green. Labels provisioned live on the two reachable issue-target repos.
|
||||
No open PRs, no uncommitted work.
|
||||
|
||||
- **Plan archival:** the plan was just-in-time (the `## Plan` block below), not a
|
||||
standalone `writing-plans` file; flotilla-core also has **no content repo**
|
||||
(`CONTENT_REMOTE` empty) — so nothing to archive to a `plans/` collection. Gap:
|
||||
flotilla-core still needs a `contains:["content"]` repo (already tracked as
|
||||
out-of-scope: "flotilla-core-content = separate effort").
|
||||
- **Pipeline (§9):** flotilla-core is the operator CLI, not a deployable UI app — no
|
||||
PPE/E2E stage applies. The "ship" was the live `ensure-labels --all` backfill,
|
||||
which ran green.
|
||||
|
||||
## Launch prompt
|
||||
|
||||
```
|
||||
Build deploy-time + retroactive provisioning of the Patchwatch label set across all
|
||||
deployments, integrated with the config-onboarding model. Tracked as flotilla-core issue #10.
|
||||
|
||||
PROBLEM: `patchwatch sync` files issues with patchwatch/lane/sev labels, but the
|
||||
least-privilege GITEA_ISSUE_TOKEN (0.11.0) cannot create labels (soft-fails 422). On repos
|
||||
whose labels were never created, capture files UNLABELED issues -> breaks dedup-on-resync and
|
||||
surfacing. Bit the first sweep on ben.stull/rfc-app (#36-#40 filed unlabeled).
|
||||
|
||||
DESIRED: Label provisioning is the DEPLOY identity's job (GITEA_BOT_TOKEN, repo write), keeping
|
||||
capture least-privilege:
|
||||
1. gitea.py idempotent label APIs (list_labels + create_label/ensure_label) + faked-API tests
|
||||
2. single taxonomy source derived from patchwatch.issue_labels (patchwatch, patchwatch/lane:*, sev:*)
|
||||
3. ensure-labels over repos findings ROUTE to (issue_target routing: app_source_repo,
|
||||
wiggleverse/flotilla-core, app main repo for os-layer); idempotent; GITEA_BOT_TOKEN
|
||||
4. config-onboarding integration: doctor REPORTS missing labels + fix/heal path that CREATES them
|
||||
5. run at DEPLOY time (idempotent, non-fatal)
|
||||
6. RETROACTIVE --all sweep across every registered deployment; backfill rfc-app
|
||||
7. GRACEFUL DEGRADATION where deploy identity lacks repo-admin (ben.stull/*): report, don't fail
|
||||
|
||||
DISCIPLINE: docs-lead-automation (SPEC §4 + §12.5 + design doc first), TDD vs faked Gitea API,
|
||||
SemVer minor bump + CHANGELOG, branch->PR->merge. Consider capture dedup by body marker
|
||||
(belt-and-suspenders) so correctness no longer DEPENDS on the label.
|
||||
|
||||
```
|
||||
|
||||
## Plan
|
||||
|
||||
**Issue #10 — Patchwatch label provisioning (v0.12.0).** Label creation becomes the
|
||||
DEPLOY identity's job (`GITEA_BOT_TOKEN`), keeping capture least-privilege.
|
||||
|
||||
Design decisions made (autonomous):
|
||||
- **Verb, not `--fix`:** a dedicated `flotilla patchwatch ensure-labels <deployment> [--all]`
|
||||
does the create (uses `GITEA_BOT_TOKEN` via `resolve_token`); `config doctor --patchwatch-labels`
|
||||
surfaces the gap read-only. (Prompt left this "your call".)
|
||||
- **Taxonomy derived from `issue_labels`:** `all_label_names()` unions `issue_labels()` over
|
||||
`audit.LANES × (SEVERITY_BANDS + "unknown")` + base — no second hardcoded name list.
|
||||
- **Doctor label status is informational** (doesn't change exit code) — graceful degradation:
|
||||
personal-namespace repos (ben.stull/*) the bot can't admin must not fail the gate/deploy.
|
||||
- **Belt-and-suspenders dedup:** `patchwatch sync` fetches open issues without the label filter
|
||||
and relies on the body `<!-- patchwatch:key=… -->` marker — correctness no longer depends on
|
||||
the label. `list_issues` gains pagination.
|
||||
|
||||
Build order (docs-lead-automation, then TDD):
|
||||
1. Docs: design-doc §7 open question resolved; SPEC §12.5 "Label provisioning"; config-onboarding §4.
|
||||
2. `gitea.py`: `Label` + `list_labels` + `create_label` (faked-API tests).
|
||||
3. `patchwatch.py`: `SEVERITIES`, `all_label_names()`, `label_specs()`, `label_target_repos(dep)`,
|
||||
`ensure_repo_labels()`/`ensure_labels()` (auth → soft `ok=False`), `_GiteaClient` label methods.
|
||||
4. Belt-and-suspenders: paginate `list_issues`; sync fetch without label filter.
|
||||
5. CLI: `patchwatch ensure-labels <dep> [--all] [--json]`; `config doctor --patchwatch-labels`;
|
||||
deploy-time best-effort ensure in `_do_real_deploy` (non-fatal).
|
||||
6. Version → 0.12.0 (VERSION + pyproject); CHANGELOG.
|
||||
7. Branch → PR → merge; then run `ensure-labels --all` to backfill (expect lane/sev created on
|
||||
ben.stull/rfc-app).
|
||||
|
||||
## Deferred decisions
|
||||
|
||||
_Autonomous-mode low-confidence calls the driver made and would have
|
||||
liked operator input on. Appended as the session runs; surfaced at
|
||||
finalize. Empty if none._
|
||||
|
||||
### DD-1 — Label-provisioning identity: the live backfill 403'd everywhere (needs operator call)
|
||||
|
||||
v0.12.0 shipped label provisioning on the **`GITEA_BOT_TOKEN`** (deploy identity),
|
||||
per the task's premise that "creating a label needs repo-admin" and capture's
|
||||
`GITEA_ISSUE_TOKEN` (write:issue) "cannot create labels (422)."
|
||||
|
||||
Running `flotilla patchwatch ensure-labels --all` against live Gitea revealed the
|
||||
premise is **inverted on this Gitea instance**:
|
||||
- Both the deployment `GITEA_BOT_TOKEN` **and** the admin Keychain PAT
|
||||
(`wgl-gitea-token-git.wiggleverse.org`, scoped `write:repository`) get **HTTP 403
|
||||
on `GET /repos/.../labels`** — even on `wiggleverse/flotilla-core` (the org's own
|
||||
repo). Confirmed by: same PAT reads `/branches` fine (repo scope) but 403s on
|
||||
`/issues` AND `/labels` → **label management is gated by `write:issue` scope**,
|
||||
not `write:repository`.
|
||||
- The 0.11.0 "422 soft-fail" was therefore about **attaching** a nonexistent label
|
||||
when filing an issue — NOT proof that write:issue can't **create** labels. In
|
||||
Gitea's scope model, `write:issue` is exactly what manages labels.
|
||||
- Net: the only identity that can actually provision labels here is the
|
||||
**`GITEA_ISSUE_TOKEN`** (write:issue) — the one the design deliberately avoided.
|
||||
|
||||
Graceful degradation worked (exit 0, every repo reported, nothing failed), but the
|
||||
backfill **provisioned zero labels**. The task's expectation ("create lane/sev on
|
||||
ben.stull/rfc-app") can't be met by the bot token.
|
||||
|
||||
**Decision needed (presented to operator via AskUserQuestion):** which identity
|
||||
should provision labels —
|
||||
- **(A, recommended)** re-point provisioning to `GITEA_ISSUE_TOKEN`
|
||||
(`resolve_issue_token`) — one-line change in `_ensure_labels_for` + deploy hook +
|
||||
doctor; matches design-§7's "labels on first use"; no credential changes. Caveat:
|
||||
the issue token's Gitea user must have repo write on each target repo.
|
||||
- **(B)** keep `GITEA_BOT_TOKEN` but re-scope it / the bot user to include
|
||||
`write:issue` + repo write on the issue-target repos (operator credential gesture).
|
||||
- **(C)** accept human/admin out-of-band creation — but the admin PAT also lacks
|
||||
issue scope, so even that needs a re-scoped token first.
|
||||
|
||||
Did NOT autonomously reverse the just-shipped identity (B/C touch credentials =
|
||||
operator gesture; A reverses a deliberate design choice) — stopped to ask.
|
||||
|
||||
**RESOLVED — operator chose (A).** Shipped v0.12.1 (PR #12): `ensure-labels`, the
|
||||
deploy hook, and `config doctor --patchwatch-labels` resolve `GITEA_ISSUE_TOKEN`.
|
||||
Re-ran `ensure-labels --all` → backfill **succeeded**: created the 8 missing
|
||||
`lane:*`/`sev:*` labels on `ben.stull/rfc-app` (patchwatch already existed) and all
|
||||
9 on `wiggleverse/flotilla-core`; `rfc-app-ppe` idempotent. Docs corrected.
|
||||
|
||||
### DD-2 — `wiggle-snip` has no issue/bot token bound (follow-up)
|
||||
|
||||
The `--all` sweep skipped `wiggle-snip` (graceful, exit 0): it has **neither**
|
||||
`GITEA_ISSUE_TOKEN` nor `GITEA_BOT_TOKEN` bound, so capture *and* label
|
||||
provisioning are both blocked there until a token is bound (`flotilla secret
|
||||
set wiggle-snip GITEA_ISSUE_TOKEN`). Pre-existing provisioning gap, not introduced
|
||||
here. (Its WebhookConfigError message still references "the webhook verb / bot
|
||||
token" — cosmetically off in the issue-token context, but accurate that no token
|
||||
is bound.)
|
||||
@@ -1,44 +0,0 @@
|
||||
# Session 0004.0 — Transcript
|
||||
|
||||
> App: flotilla-core
|
||||
> Start: 2026-06-07T22-20 (PST)
|
||||
> Type: planning-and-executing
|
||||
> Status: **PLACEHOLDER — claimed at session start; finalized at session end.**
|
||||
>
|
||||
> This file reserves session ID 0004 for flotilla-core. The driver replaces this
|
||||
> body with the full transcript and renames the file to its final
|
||||
> SESSION-0004.0-TRANSCRIPT-2026-06-07T22-20--<end>.md form at session end.
|
||||
|
||||
## Launch prompt
|
||||
|
||||
```
|
||||
Build deploy-time + retroactive provisioning of the Patchwatch label set across all
|
||||
deployments, integrated with the config-onboarding model. Tracked as flotilla-core issue #10.
|
||||
|
||||
PROBLEM: `patchwatch sync` files issues with patchwatch/lane/sev labels, but the
|
||||
least-privilege GITEA_ISSUE_TOKEN (0.11.0) cannot create labels (soft-fails 422). On repos
|
||||
whose labels were never created, capture files UNLABELED issues -> breaks dedup-on-resync and
|
||||
surfacing. Bit the first sweep on ben.stull/rfc-app (#36-#40 filed unlabeled).
|
||||
|
||||
DESIRED: Label provisioning is the DEPLOY identity's job (GITEA_BOT_TOKEN, repo write), keeping
|
||||
capture least-privilege:
|
||||
1. gitea.py idempotent label APIs (list_labels + create_label/ensure_label) + faked-API tests
|
||||
2. single taxonomy source derived from patchwatch.issue_labels (patchwatch, patchwatch/lane:*, sev:*)
|
||||
3. ensure-labels over repos findings ROUTE to (issue_target routing: app_source_repo,
|
||||
wiggleverse/flotilla-core, app main repo for os-layer); idempotent; GITEA_BOT_TOKEN
|
||||
4. config-onboarding integration: doctor REPORTS missing labels + fix/heal path that CREATES them
|
||||
5. run at DEPLOY time (idempotent, non-fatal)
|
||||
6. RETROACTIVE --all sweep across every registered deployment; backfill rfc-app
|
||||
7. GRACEFUL DEGRADATION where deploy identity lacks repo-admin (ben.stull/*): report, don't fail
|
||||
|
||||
DISCIPLINE: docs-lead-automation (SPEC §4 + §12.5 + design doc first), TDD vs faked Gitea API,
|
||||
SemVer minor bump + CHANGELOG, branch->PR->merge. Consider capture dedup by body marker
|
||||
(belt-and-suspenders) so correctness no longer DEPENDS on the label.
|
||||
|
||||
```
|
||||
|
||||
## Deferred decisions
|
||||
|
||||
_Autonomous-mode low-confidence calls the driver made and would have
|
||||
liked operator input on. Appended as the session runs; surfaced at
|
||||
finalize. Empty if none._
|
||||
Reference in New Issue
Block a user