Skip to content

Declare the Fleet Label Set and Apply It Through configure.sh - #1334

Merged
ptr727 merged 5 commits into
developfrom
feature/fleet-labels
Sep 5, 2026
Merged

Declare the Fleet Label Set and Apply It Through configure.sh#1334
ptr727 merged 5 commits into
developfrom
feature/fleet-labels

Conversation

@ptr727

@ptr727 ptr727 commented Sep 5, 2026

Copy link
Copy Markdown
Owner

Summary

  • repo-config/labels.json declares the fleet label set: the triage kinds gate, script, prose, decision, and chore, the review classes introduced and pre-existing, and the labels every fleet repo already shares.
  • repo-config/configure.sh apply creates or updates every declared label by name and deletes nothing, so a label a repo adds of its own stays. check asserts each declared label on name, color, and description, and reports undeclared labels without judging them.
  • The repo-config README, docs/repo-config.md, OPERATIONS.md, STANDUP.md, and AUDIT.md section 6 name the label set where they enumerate what the script applies or checks. labels.json gets its retire entry in spec/divergences.json and the prose gate's hub-hosted set, like the other hub-only repo-config/ files.

Part of #1315, and the script half of #1271. Applying the labels to the hub and the fleet, labelling the issues, the per-unit trackers, and the decision list are GitHub writes tracked on #1315.

Verification

  • shellcheck and shfmt -d clean on repo-config/configure.sh. scripts/tests/test_prose_lint.py and test_spec_validate.py pass (278 tests), covering the hub-hosted set against the ledger.
  • repo-config/configure.sh check ptr727/ProjectTemplate release, run read-only from this branch, reports the nine labels the hub already carries as ok and the seven new ones as FAIL, which is the drift the apply mode closes.
  • apply has not been run against a live repository from this branch. check_labels has, and apply_labels runs the same gh label create --force per declared label that P0: Triage the Open Backlog Into a Label Set, One Tracker Per Canonical Unit, and One Decision List #1315's own label step runs on the hub first, which is the live exercise it gets before any fleet apply.
  • The .husky/pre-commit chain passes (ruff format, ruff check, mypy, prose_lint, repo_gate eol), and spec/validate.py passes.
  • The carried-content pass is recorded for AUDIT.md > 6. Validate Settings, Rulesets, and Secrets. Its pre-existing findings go to that unit's tracker under P0: Triage the Open Backlog Into a Label Set, One Tracker Per Canonical Unit, and One Decision List #1315.

Review record

Two maintainer-granted rounds beyond the push's budget: 0ebd9d4 took the eight prose and script findings the first reads left open, and 466af94, code only, took Copilot's empty-payload thread plus the field-contract and header items. Counts per read, introduced over total: carried-content pass on AUDIT.md > 6, 3/18, 2/4, 2/2, 2/2; diff pass, 12/13, 6/6, 4/5, 7/9. Copilot's three rounds raised seven findings, six fixed and one disproven with a constructed check in the PR conversation. Every read's introduced count stayed above zero, which is the pilot's curve again, and on this branch the last two reads' findings were on the previous round's own text. Both budgets are spent, so what stands is recorded here:

  • On AUDIT.md section 6, on Tracker: AUDIT.md > 6. Validate Settings, Rulesets, and Secrets #1356 (its tracker): the lead-in omits the Dependabot security features, and "the registry description" over-claims a conditional assertion.
  • On configure.sh, from the last read, each one line if wanted: the validator admits two entries with the same name (check then fails the first against the second's live values) and uppercase hex (which check compares byte-exact against what GitHub stores), it collapses its five refusal causes into one message, and the payload is read twice, once to validate and once to apply, so the "cannot be the first to find it malformed" comment overstates. The read also asks whether spec/audit.py should assert the label floor, which today only check does, as it does for the Dependabot features.
  • On carried prose, for the maintainer: audit-a-repo step 25 still routes configure.sh check "for settings and rulesets" where the command now asserts labels, one edit in a carried skill unit, so it owes a whole-unit pass of its own. README.md line 26's "exactly one of these five, beside whatever surface labels" does not name the class labels line 34 adds, and decision names a state rather than a kind of work.
  • On spec/divergences.json, a contradiction between two reads: the first diff read required a retire entry for labels.json beside its six repo-config/ siblings, and a later read calls it inert since no downstream carries the file. The six siblings have the same shape, so it is a convention call on all seven rows.
  • Pre-existing, OPERATIONS.md line 90: the blast-radius sentence omits the computed has_discussions and description writes.

🤖 Generated with Claude Code

ptr727 and others added 3 commits September 4, 2026 18:29
repo-config/labels.json holds the fleet label set, the triage kinds
gate, script, prose, decision, and chore, the review classes
introduced and pre-existing, and the labels every fleet repo already
shares. configure.sh apply creates or updates each declared label by
name and deletes nothing, and check asserts each on name, color, and
description while reporting undeclared labels without judging them.

Part of #1315.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…gure.sh applies

The two procedures and the script header each list what apply writes
and check compares, so the label set is added to each list. The
carried-content pass over AUDIT.md section 6 is recorded in the ledger.

Part of #1315.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…weep

configure.sh strips the CR a native Windows jq leaves on the undeclared
label list, guards that read under set -e like every other check read,
and refuses a label whose name, color, or description is not a string,
so a missing description is never written as the literal null. The
class label descriptions now point at the Skill that defines the
classes rather than restating them. labels.json gets its retire entry
in the divergence ledger and the prose gate's hub-hosted set, and the
OPERATIONS.md, README, and docs enumerations of what apply writes and
check asserts each name the labels.

Part of #1315.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 5, 2026 02:06
@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing

@coderabbitai

coderabbitai Bot commented Sep 5, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: 13416ece-f06f-4042-b6d8-16a46eab269d


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

configure.sh apply can still partially mutate a repo before failing on malformed label payloads, and the label TSV parsing needs explicit tab/newline validation to prevent corrupted apply/check behavior.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR introduces a hub-declared fleet label set and extends the hub-hosted repo-config/configure.sh to apply and validate those labels across repositories, with documentation updates to keep the repo-config and audit procedures consistent.

Changes:

  • Add repo-config/labels.json as the canonical fleet label payload.
  • Extend repo-config/configure.sh to apply and check labels (create-or-update by name, report undeclared labels without deleting them).
  • Update standup/audit/repo-config documentation and the prose gate’s hub-hosted path allowlist to include the new payload.
File summaries
File Description
STANDUP.md Updates standup steps to include applying the label set.
spec/divergences.json Marks repo-config/labels.json as hub-hosted/retired for downstream copies.
reports/canonical-review.json Records the canonical review ledger entry for the updated AUDIT unit.
repo-config/README.md Documents the new label payload and explains intended label semantics.
repo-config/labels.json Declares the fleet label set (name/color/description).
repo-config/configure.sh Implements apply/check of labels via GitHub CLI and updates script header docs.
OPERATIONS.md Updates operational guidance to reflect labels are applied by configure.sh apply.
docs/repo-config.md Documents labels.json as part of the hub-only repo-config payload set.
AUDIT.md Updates the audit procedure narrative for what configure.sh check asserts.
.github/actions/prose-gate/prose_lint.py Adds repo-config/labels.json to the hub-hosted reference allowlist.
Review details

Suppressed comments (3)

repo-config/configure.sh:202

  • Label payload validation happens inside apply_labels(), but cmd_apply() performs settings and Dependabot writes before calling it. If labels.json is malformed, apply will abort after already mutating the repo, leaving a partially-applied configuration. Pre-validate labels.json (parse + required string fields + non-empty) before any writes.
cmd_apply() {
    local f private disc payload
    # Pre-flight every required payload before any write, so a partial carry aborts before it half-applies.
    for f in "$settings_file" "$labels_file" "$develop_ruleset" "$main_ruleset"; do
        if [ ! -e "$f" ]; then

repo-config/configure.sh:185

  • apply_labels() encodes each label as a tab-separated row, then splits on newlines and tabs. A label name/color/description containing a tab or newline will corrupt parsing and can cause a mid-loop abort after some labels were already written. Validate that these fields do not contain tab/newline (or switch to a safer encoding).
    local rows lname color desc
    # Every field is required, since a missing description would otherwise render as the literal string null and be written fleet-wide.
    if ! jq -e 'all(.[]; (.name|type=="string") and (.color|type=="string") and (.description|type=="string"))' "$labels_file" >/dev/null; then
        echo "Label payload $labels_file did not parse, or a label lacks a string name, color, or description. Aborting to avoid a partially-applied configuration." >&2
        exit 1

repo-config/configure.sh:432

  • check_labels() uses the same tab/newline row encoding as apply_labels(), but it does not reject tabs/newlines inside label fields either. That can break drift detection or make the jq parsing fail in confusing ways. Apply the same tab/newline validation here for symmetry.
    fi
    if ! jq_has 'all(.[]; (.name|type=="string") and (.color|type=="string") and (.description|type=="string"))' <"$labels_file"; then
        fail "label payload $labels_file did not parse, or a label lacks a string name, color, or description"
        return
    fi
  • Files reviewed: 10/10 changed files
  • Comments generated: 3
  • Review effort level: Lite

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread AUDIT.md Outdated
Comment thread repo-config/README.md Outdated
Comment thread repo-config/configure.sh Outdated
The label payload is validated in cmd_apply's pre-flight, before the
settings and Dependabot writes, and the shared validator also rejects a
tab or line break that would split the tab-joined rows both label loops
read. The header names the undeclared labels among what is unaudited.
The README no longer claims the class labels compute a metric, and its
triage sentence names the five kinds and the enhancement exception
without contradiction. AUDIT.md section 6 names labels in its lead-in
and lists what check asserts, ruleset by ruleset.

Part of #1315.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@ptr727

ptr727 commented Sep 5, 2026

Copy link
Copy Markdown
Owner Author

Answering the three suppressed findings from Copilot's first round, all on repo-config/configure.sh:

  • Label payload validation happens inside apply_labels(), after the settings and Dependabot writes. Fixed in 0ebd9d4: a shared labels_payload_ok validator runs in cmd_apply's pre-flight before any write, and check_labels calls the same one.
  • A tab or newline in a label field corrupts the row parsing in apply_labels(). Fixed in 0ebd9d4: the validator rejects a tab, CR, or LF in any of the three fields.
  • check_labels() should apply the same validation for symmetry. Fixed in 0ebd9d4: it calls the same validator and fails the run on a bad payload.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

repo-config/configure.sh has two apply-mode correctness issues (empty labels payload can cause partial apply, and the “Applied N labels” count undercounts).

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

repo-config/configure.sh:197

  • apply_labels reports the number of labels using wc -l <<<"$rows", but command substitution strips the final newline from $rows, so wc -l undercounts by 1 for any non-empty payload. Use a line-count that doesn't depend on a trailing newline (or derive the count from the JSON).
  • Files reviewed: 10/10 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread repo-config/configure.sh
@ptr727

ptr727 commented Sep 5, 2026

Copy link
Copy Markdown
Owner Author

Answering the suppressed finding from the second round, on repo-config/configure.sh line 197 (wc -l <<<"$rows" undercounts by one because command substitution strips the final newline):

Disproven. A here-string appends a newline of its own to the word it feeds, so the count is exact. Constructed check, run on this host: a two-row value built with printf 'a\tb\tc\nd\te\tf', which has no trailing newline after command substitution, gives wc -l <<<"$rows" a count of 2. The applied-count line reports the number of declared labels, which is what it says.

The shared validator now refuses an empty payload and a label whose
name is empty, whose color is not six hex digits, or whose description
exceeds 100 characters, so apply cannot reach the API partway through
the loop with a label the API will reject. The two now-unreachable
empty-payload checks are gone. The header states the payload direction
accurately, since the rulesets are payload-driven too.

Part of #1315.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings September 5, 2026 02:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

configure.sh label payload validation permits duplicate label names (leading to guaranteed drift), and AUDIT.md overstates when the registry description is asserted.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

AUDIT.md:101

  • This bullet says configure.sh check asserts "the registry description", but configure.sh only asserts the About description when spec/resolve_description.py returns a non-empty value (otherwise it prints a manual-verify note). Reword this list item to make the description assertion conditional, so the audit procedure matches the script behavior.
  • Files reviewed: 10/10 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread repo-config/configure.sh
@ptr727

ptr727 commented Sep 5, 2026

Copy link
Copy Markdown
Owner Author

Answering the suppressed finding from the third round, on AUDIT.md line 101 (the bullet says check asserts "the registry description" where the script asserts it only when the registry declares one):

No change needed in this change. The same finding came from the whole-unit read after the granted round and is recorded on the unit's tracker, #1356 item 16, together with the lead-in omitting the Dependabot security features, per the Merge Gate's tracker rule. The unit is rewritten there rather than in a further round here.

@ptr727
ptr727 merged commit 00832f3 into develop Sep 5, 2026
9 checks passed
@ptr727
ptr727 deleted the feature/fleet-labels branch September 5, 2026 03:14
ptr727 added a commit that referenced this pull request Sep 7, 2026
…sh the WORKFLOW.md Reshape (#1397)

Closes #1205.
Closes #1212.
Closes #1240.
Closes #1250.
Closes #1267.
Closes #1268.
Closes #1271.
Closes #1288.
Closes #1305.
Closes #1314.

Sixteen commits, ten issues. Each was driven as its own feature pull
request into `develop`,
reviewed by the PR-hosted reviewers, and merged only with CI green and
every finding disposed of
by one of the five outcomes: fixed, declined on evidence, decided by the
maintainer, deferred
behind a filed issue, or fixed as a class.

## What this promotes

**The one-home include mechanism and its first six classes** (#1317).
`scripts/build_dist.py`
gained include regions filled from a rule's home and checked by
`--check` (#1378), so a Skill
carries a rule's whole text without a copy that can drift. Classes 2 to
6 then converted the
restatements: `agent-conduct`'s three conduct sections (#1382),
`pr-review-conduct`'s five
outcomes into `drive-pr` with every step-ref renamed to a heading
(#1383),
`backlog-burndown`'s two narrowing rows cut to the narrowing with
fourteen restatements
pointered (#1384), `WORKFLOW.md` section 4 into `workflow-ci-contract`
(#1385), and section 2
cut to a pointer at `GOVERNANCE.md` "Workflow YAML Conventions" (#1388).

**The `WORKFLOW.md` reshape** (#1311 step 14's six-pull-request
sequence, now finished). The
verdict clause aligned with section 5's Assessment (#1390), sections 3
and 5 carried into
`workflow-ci-contract` as generated includes (#1392), 5A collapsed to a
procedure and an evidence
rule (#1394), and the preamble decisions settled alongside the reshape
of section 4, section 6 and
the YAML conventions (#1395). Section 4's two longest items shrank to
their outcomes with the
displaced knowledge moved rather than deleted, and section 6 now states
only what each type adds,
carrying no N/A list at all.

**The review loop's stop rule and disposition policy** (#1330),
rewriting disposal by deletion and
committing the condition under which a whole-unit loop ends, which #1267
filed as missing.

**The Merge Gate's bound on an out-of-diff prose finding**, with the
reviewer footing recorded
(#1333), and reviewer bots scoped away from the generated Skill mirrors
(#1329) so a mirror's diff
is never reviewed in place of its source.

**The fleet label set**, declared and applied through `configure.sh`
(#1334).

**The review ledger and skills digest decoupled from the working tree**
(#1328), so concurrent
branches no longer conflict in a generated report that cannot be
hand-merged.

Plus one grouped Dependabot bump, `docker/setup-qemu-action` 4.2.0 to
4.3.0 (#1325).

## What is deliberately not closed

`#1311`, `#1317`, `#1206`, `#1367`, `#1369`, `#1370`, `#1371`, `#1386`
and `#1237` each still
hold findings this work did not settle. #1317 stands at class 6 of
fourteen, and #1311's step 17
comment records what the reshape filed rather than fixed.

## Owed on merge

`spec/files.json` declares both edited `GOVERNANCE.md` sections at
`verbatim` fidelity, so every
downstream copy goes stale on this promotion and a fleet resync follows
it.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants