@codedrifters/configulator 0.0.351 → 0.0.353

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.mjs CHANGED
@@ -11863,7 +11863,7 @@ function buildMeetingAnalystSubAgent(tier) {
11863
11863
  "| `planning` | Sprint/plan updates, task issues, requirement drafts | Extract every task assignment. Phase 4 updates the active sprint-plan doc directly and creates one issue per assigned task. |",
11864
11864
  "| `review` | Retro notes, follow-up issues, status updates, requirement revisions | Mark completed tasks in the active sprint-plan doc. Capture retrospective learnings inside the meeting notes \u2014 do not spawn a separate retro document. |",
11865
11865
  "| `brainstorm` | Future-feature candidates, research topics, very few Firm decisions | Lower the bar for Open Questions. Do **not** create requirement or ADR issues from brainstorm output unless the item is explicitly marked **Firm**. Prefer research/discovery issues for promising ideas. |",
11866
- "| `standup` | Action items, blockers, status updates | Do not produce requirement, ADR, or BDR drafts. Phase 3 (Draft) is almost always skipped. Focus on action-item issues and sprint-plan status updates. |",
11866
+ "| `standup` | Action items, blockers, status updates | Do not produce requirement, ADR, or BDR drafts. Phase 3 (Draft) is almost always skipped. Capture action items in the notes `## Action Items` table; file issues only for agent-workable doc deliverables (per the **Action-item filing policy**) and apply sprint-plan status updates. |",
11867
11867
  "| `external` | Customer/competitive intel, people/company profiles, lead capture | Default every attendee outside the team into **People of Interest**. Default every organization mentioned into **Companies of Interest** (signal threshold still applies). Capture stated customer pain points as candidate **BR** (business requirements), not FR. |",
11868
11868
  "| `other` | General meeting extraction | Apply the default workflow with no type-specific overrides. |",
11869
11869
  "",
@@ -11925,6 +11925,61 @@ function buildMeetingAnalystSubAgent(tier) {
11925
11925
  "",
11926
11926
  "---",
11927
11927
  "",
11928
+ "## Action-item filing policy",
11929
+ "",
11930
+ "Not every action item should become a GitHub issue. The pipeline",
11931
+ "can only ever close issues whose deliverable an automated agent",
11932
+ "(or this repo's existing channels) can produce. Filing an issue",
11933
+ "for a task only a human can do \u2014 in the real world or in a system",
11934
+ "this pipeline cannot touch \u2014 creates queue noise that no worker or",
11935
+ "orchestrator can ever resolve. Apply the **agent-workability",
11936
+ "test** below in phases 1, 3, and 4.",
11937
+ "",
11938
+ "### Agent-workability test",
11939
+ "",
11940
+ "An action item is **agent-workable** only when completing it",
11941
+ "produces a documentation deliverable an automated agent can author",
11942
+ "in this repo's docs tree \u2014 a requirement document, an ADR, a docs",
11943
+ "page, a BCM capability model, a research note, or a roadmap /",
11944
+ "product-doc update. Route agent-workable items through their",
11945
+ "**dedicated downstream channel** (`req:write`, `docs:write`,",
11946
+ "`bcm:*`, `research:scope`, roadmap/product-doc follow-up). Never",
11947
+ "file them as a generic `action-item` / `type:chore` issue.",
11948
+ "",
11949
+ "An action item is **human-owned** when it requires a person to act",
11950
+ "in the real world or in a system this pipeline cannot reach.",
11951
+ "Typical cues:",
11952
+ "",
11953
+ '- **send / email / schedule / invite / call** \u2014 e.g. "send out',
11954
+ ` company invoices", "invite X to next week's call".`,
11955
+ '- **install / configure / provision / set up** \u2014 e.g. "install and',
11956
+ ' configure Claude", "get codebase read access".',
11957
+ "- **decide / approve / choose / prioritise** (a human judgement",
11958
+ " call, not a documented decision record).",
11959
+ '- **communicate / notify / give a heads-up** \u2014 e.g. "give Dr. Y a',
11960
+ ' heads-up".',
11961
+ "- **get / request access or credentials**, **pay / invoice**.",
11962
+ "- **build or change code in another repo**, **design in an",
11963
+ " external tool** (Figma, etc.).",
11964
+ "",
11965
+ "Record human-owned items **only** in the notes `## Action Items`",
11966
+ "table (who / what / when) \u2014 that table is the **system of record**",
11967
+ "for human follow-ups. Do **not** file a GitHub issue for them.",
11968
+ "",
11969
+ "When an item is ambiguous, default to **human-owned**",
11970
+ "(notes-only): a missed issue is cheaper than queue noise the",
11971
+ "pipeline can never close.",
11972
+ "",
11973
+ "**Consumer tuning.** When the project supplies",
11974
+ "`AgentConfigOptions.meetings.actionItemFiling`, an",
11975
+ "**Action-item filing policy** subsection is rendered into the",
11976
+ "meetings taxonomy with any extra human-owned / agent-workable cues",
11977
+ "and a note when the split is disabled. Apply those overrides on",
11978
+ "top of the built-in cues above; if the split is disabled, fall",
11979
+ "back to filing a follow-up issue for every non-draft action item.",
11980
+ "",
11981
+ "---",
11982
+ "",
11928
11983
  ...PROJECT_CONTEXT_MAINTAINER_SECTION,
11929
11984
  "## Traceability",
11930
11985
  "",
@@ -11956,7 +12011,7 @@ function buildMeetingAnalystSubAgent(tier) {
11956
12011
  "",
11957
12012
  " | Artifact | Type | Issue/Path |",
11958
12013
  " |----------|------|------------|",
11959
- " | <title> | requirement / ADR / action-item / profile | #<N> or <path> |",
12014
+ " | <title> | requirement / ADR / docs / profile / research | #<N> or <path> |",
11960
12015
  " ```",
11961
12016
  "",
11962
12017
  "2. **Update the meeting notes** with a similar `## Related Issues` section",
@@ -12021,7 +12076,7 @@ function buildMeetingAnalystSubAgent(tier) {
12021
12076
  ` | **Decisions** | "We decided...", "Let's go with...", explicit choices |`,
12022
12077
  ' | **Requirements** | Feature descriptions, acceptance criteria, "it should..." |',
12023
12078
  " | **Technology discussions** | Platform comparisons, architecture options, tool evaluations |",
12024
- ' | **Action items** | "[Person] will...", "Next step is...", assigned tasks |',
12079
+ ' | **Action items** | "[Person] will...", "Next step is...", assigned tasks. Tag each with its **disposition** (`agent-workable` vs `human-owned`) per the **Action-item filing policy**. |',
12025
12080
  ' | **Open questions** | "We need to figure out...", unresolved debates |',
12026
12081
  " | **People of interest** | Industry contacts, domain experts mentioned |",
12027
12082
  " | **Companies of interest** | Competitors, vendors, partners discussed |",
@@ -12036,7 +12091,10 @@ function buildMeetingAnalystSubAgent(tier) {
12036
12091
  " - Decisions Made (with category and confidence: Firm / Tentative / Needs confirmation)",
12037
12092
  " - Requirements Identified (with category and priority estimate)",
12038
12093
  " - Technology Discussions (with status: Decided / Leaning toward / Open)",
12039
- " - Action Items (with assignee and due date if stated)",
12094
+ " - Action Items (with assignee and due date if stated, and a",
12095
+ " **disposition** tag \u2014 `agent-workable` or `human-owned` \u2014 per",
12096
+ " the **Action-item filing policy** so Phase 4 can route each",
12097
+ " item without re-classifying it)",
12040
12098
  " - Open Questions",
12041
12099
  " - People of Interest (with context and whether a profile exists)",
12042
12100
  " - Companies of Interest (with type and context)",
@@ -12166,7 +12224,11 @@ function buildMeetingAnalystSubAgent(tier) {
12166
12224
  " - Agenda / topics covered",
12167
12225
  " - Key Discussion Points (organized by topic)",
12168
12226
  " - Decisions (numbered, with rationale)",
12169
- " - Action Items (table: who, what, when)",
12227
+ " - Action Items (table: who, what, when). This table is the",
12228
+ " **system of record for human follow-ups** \u2014 human-owned",
12229
+ " action items live here and are never filed as GitHub issues",
12230
+ " (see the **Action-item filing policy**). Capture every",
12231
+ " action item here regardless of disposition.",
12170
12232
  " - Open Questions",
12171
12233
  " - Follow-up items",
12172
12234
  "4. **Plan the `notes/` tree index update \u2014 do not commit it",
@@ -12214,6 +12276,11 @@ function buildMeetingAnalystSubAgent(tier) {
12214
12276
  "This phase only exists if the extraction identified requirements, architectural",
12215
12277
  "decisions, or strategy changes. If this issue exists, execute it.",
12216
12278
  "",
12279
+ "Draft proposals only for **agent-workable** deliverables (per the",
12280
+ "**Action-item filing policy**). Action items tagged `human-owned`",
12281
+ "in the extraction are not drafted here \u2014 they stay in the notes",
12282
+ "`## Action Items` table and produce no follow-up issue.",
12283
+ "",
12217
12284
  "### Steps",
12218
12285
  "",
12219
12286
  "1. Read the extraction file from Phase 1 at",
@@ -12253,8 +12320,27 @@ function buildMeetingAnalystSubAgent(tier) {
12253
12320
  " gated by areas.",
12254
12321
  "3. Create ADR issues if technology decisions need formal records.",
12255
12322
  " Include a `## Traceability` section in each. Not gated by areas.",
12256
- "4. Create action item issues for tasks that are not document-related.",
12257
- " Include a `## Traceability` section in each. Not gated by areas.",
12323
+ "4. **Route action items per the Action-item filing policy \u2014 do",
12324
+ " not file a generic `action-item` issue per task.** Read each",
12325
+ " action item's `disposition` tag from the extraction (re-apply",
12326
+ " the **agent-workability test** if the tag is missing):",
12327
+ " - **Agent-workable** (yields a doc deliverable an agent can",
12328
+ " author): file it through its **dedicated downstream channel**",
12329
+ " \u2014 a `req:write` issue for a requirement, a `docs:write` issue",
12330
+ " for a docs page, `bcm:*` for a capability model, a",
12331
+ " `research:scope` issue for a research note, or a roadmap /",
12332
+ " product-doc follow-up. Use the matching template from the",
12333
+ " issue-templates page; include a `## Traceability` section.",
12334
+ " Issue creation is not gated by areas.",
12335
+ " - **Human-owned** (send/schedule/install/decide/communicate/",
12336
+ " get-access/build-elsewhere): record it **only** in the notes",
12337
+ " `## Action Items` table (step 8 already carries the table",
12338
+ " forward). **File no GitHub issue.** When ambiguous, treat the",
12339
+ " item as human-owned.",
12340
+ " If the project disabled the split via",
12341
+ " `meetings.actionItemFiling.enabled: false`, fall back to filing",
12342
+ " a follow-up issue for every action item not already covered by",
12343
+ " a Phase 3 draft.",
12258
12344
  "5. Cross-reference the meeting in any existing documents that were",
12259
12345
  " discussed **and that live under an in-scope `docRoot`**. For",
12260
12346
  " discussed documents under an out-of-scope `docRoot`, open a",
@@ -12291,7 +12377,10 @@ function buildMeetingAnalystSubAgent(tier) {
12291
12377
  "- Use `gh` CLI for all GitHub operations",
12292
12378
  "- Apply the appropriate `meeting:*` phase label to each phase issue",
12293
12379
  "- Use `type:docs` for documentation-producing issues, `type:chore` for",
12294
- " maintenance/organizational tasks",
12380
+ " maintenance/organizational tasks the pipeline can action",
12381
+ "- Do **not** file issues for human-owned action items \u2014 per the",
12382
+ " **Action-item filing policy** they live only in the notes",
12383
+ " `## Action Items` table",
12295
12384
  "- Use `status:` labels to track progress (`status:ready`, `status:in-progress`, `status:done`)",
12296
12385
  "- Reference the source meeting transcript in all created issues",
12297
12386
  "- Link phase issues with `Depends on: #N` to enforce ordering",
@@ -12362,7 +12451,10 @@ var processMeetingSkill = {
12362
12451
  "1. Resolve the basename, partition, and any sibling files using",
12363
12452
  " the **Basename-pairing algorithm** above",
12364
12453
  "2. Execute Phase 1 (Extract) \u2014 categorize the available content into",
12365
- " decisions, requirements, action items, open questions, and more",
12454
+ " decisions, requirements, action items, open questions, and more.",
12455
+ " Tag each action item's disposition (`agent-workable` vs",
12456
+ " `human-owned`) per the agent's **Action-item filing policy** so",
12457
+ " Phase 4 keeps human-owned tasks out of the issue queue",
12366
12458
  "3. Write the extraction to",
12367
12459
  " `<meetingsRoot>/insights/{type}/<basename>.md`",
12368
12460
  "4. Create downstream phase issues using `gh issue create`:",
@@ -12432,7 +12524,18 @@ function buildMeetingAnalysisBundle(tier = AGENT_MODEL.BALANCED) {
12432
12524
  "direct edits to the doc-root sub-folders declared in the project's",
12433
12525
  "**Area \u2192 doc-root mapping** table. When both fields are absent",
12434
12526
  "the pipeline falls back to the default workflow (kind `other`,",
12435
- "no area gating)."
12527
+ "no area gating).",
12528
+ "",
12529
+ "Phase 4 applies an **agent-workability split** to action items:",
12530
+ "items that yield a documentation deliverable an agent can author",
12531
+ "are filed through their dedicated downstream channel",
12532
+ "(`req:write`, `docs:write`, `bcm:*`, `research:scope`, roadmap",
12533
+ "follow-up); human-owned tasks (send / schedule / install /",
12534
+ "decide / communicate / get-access / build-elsewhere) are",
12535
+ "recorded **only** in the notes `## Action Items` table, which is",
12536
+ "the **system of record for human follow-ups** \u2014 no GitHub issue",
12537
+ "is filed for them. Consumers tune or disable the split via",
12538
+ "`AgentConfigOptions.meetings.actionItemFiling`."
12436
12539
  ].join("\n"),
12437
12540
  platforms: {
12438
12541
  cursor: { exclude: true }
@@ -13577,6 +13680,9 @@ var DEFAULT_BUNDLE_OVERRIDES = {
13577
13680
  "regulatory:research": {
13578
13681
  acceptanceCriteria: { smallMax: 3, mediumMax: 10 }
13579
13682
  },
13683
+ "standards:research": {
13684
+ acceptanceCriteria: { smallMax: 3, mediumMax: 10 }
13685
+ },
13580
13686
  "software:map": {
13581
13687
  acceptanceCriteria: { smallMax: 3, mediumMax: 12 },
13582
13688
  sources: { smallMax: 2, mediumMax: 15 }
@@ -13790,6 +13896,31 @@ function renderScopeGateSection(gate, excludeBundles = []) {
13790
13896
  "alphabetical order on the label name** \u2014 first-wins, deterministic."
13791
13897
  );
13792
13898
  }
13899
+ lines.push(
13900
+ "",
13901
+ "### Reconfiguring the thresholds",
13902
+ "",
13903
+ "Every threshold above is configurable per repo \u2014 the global",
13904
+ "`acceptance-criteria` / `sources` classification bands and each",
13905
+ "per-phase-label override. Retune them in the project's",
13906
+ "configulator config so the gate fits this repo's issue shapes:",
13907
+ "",
13908
+ "- `AgentConfigOptions.scopeGate.acceptanceCriteria` /",
13909
+ " `AgentConfigOptions.scopeGate.sources` \u2014 the global",
13910
+ " `smallMax` / `mediumMax` bands applied to every issue.",
13911
+ "- `AgentConfigOptions.scopeGate.bundleOverrides.<phase-label>` \u2014",
13912
+ " a per-phase-label override for **any** phase label, not just",
13913
+ " the ones shipped above. The map deep-merges with the shipped",
13914
+ " defaults (consumer-wins-per-key): add a key to raise a new",
13915
+ " label's AC / sources ceiling, set an existing key to replace a",
13916
+ " shipped default, or set a key to `undefined` to drop a shipped",
13917
+ " default and classify that label against the global bands.",
13918
+ "",
13919
+ "Each override entry's `acceptanceCriteria` and `sources` axes are",
13920
+ "independent \u2014 override one and the other falls through to the",
13921
+ "global band. Malformed thresholds (negative, non-integer, or",
13922
+ "`mediumMax <= smallMax`) fail the build at synth time."
13923
+ );
13793
13924
  lines.push(
13794
13925
  "",
13795
13926
  "### Decomposition-proposal template",
@@ -17656,7 +17787,11 @@ var prReviewerSubAgent = {
17656
17787
  "",
17657
17788
  "The PR is **eligible** only when **all** of the following hold:",
17658
17789
  "",
17659
- '1. `mergeable == "MERGEABLE"` (no merge conflicts).',
17790
+ '1. `mergeable == "MERGEABLE"` (no merge conflicts). A',
17791
+ ' `mergeable == "CONFLICTING"` PR is **not** an automatic',
17792
+ " disqualification \u2014 see the **already-`CONFLICTING` handling**",
17793
+ " below, which may auto-correct it via delegation before falling",
17794
+ " back to a hard reject.",
17660
17795
  "2. No **failing** required checks in `statusCheckRollup` \u2014 CI must be",
17661
17796
  " green or still pending. Any `FAILURE`, `TIMED_OUT`, `CANCELLED`, or",
17662
17797
  " `ERROR` conclusion on a required check disqualifies the PR. If the",
@@ -17668,8 +17803,9 @@ var prReviewerSubAgent = {
17668
17803
  "3. The PR body contains a linked issue via one of the closing keywords:",
17669
17804
  " `Closes #N`, `Fixes #N`, or `Resolves #N` (case-insensitive).",
17670
17805
  "",
17671
- "If **any** check fails, post a short comment explaining the reason and",
17672
- "stop. Do not proceed to full review.",
17806
+ "If the **CI** check (2) or the **linked-issue** check (3) fails, post",
17807
+ "a short comment explaining the reason and stop. Do not proceed to",
17808
+ "full review.",
17673
17809
  "",
17674
17810
  "```bash",
17675
17811
  "gh pr comment <pr-number> --body '<reason>'",
@@ -17677,10 +17813,50 @@ var prReviewerSubAgent = {
17677
17813
  "",
17678
17814
  "Typical reasons:",
17679
17815
  "",
17680
- "- `Not reviewable: merge conflicts \u2014 please rebase onto the default branch.`",
17681
17816
  "- `Not reviewable: required CI check <name> is failing.`",
17682
17817
  "- `Not reviewable: PR body is missing a linked issue (Closes #N / Fixes #N / Resolves #N).`",
17683
17818
  "",
17819
+ "### Already-`CONFLICTING` handling (auto-correct, then reject)",
17820
+ "",
17821
+ 'When the merge check (1) reports `mergeable == "CONFLICTING"`, do',
17822
+ "**not** unconditionally reject. A bot-authored PR that is already",
17823
+ "conflicting when the orchestrator finds it is exactly the case the",
17824
+ "conflict-resolution delegation flow exists to auto-correct \u2014 there",
17825
+ "is no reason to make a human rebase it by hand when `issue-worker`",
17826
+ "can. Before rejecting, evaluate checks (2) and (3) above first: a",
17827
+ "`CONFLICTING` PR that **also** has failing CI or no linked issue is",
17828
+ "rejected for that reason via the comment-and-stop path above, since",
17829
+ "the delegation cannot succeed without a linked issue and green-able",
17830
+ "CI anyway.",
17831
+ "",
17832
+ "Otherwise, hand off to the **Shared Procedure: Conflict-Resolution",
17833
+ "Delegation** section. It evaluates the guards (auto-merge mode, the",
17834
+ "delegation invocation guard, a free `review:fixing` lease, no",
17835
+ "generated / projen / lockfile conflicts), classifies the conflicting",
17836
+ "files, and either delegates a rebase to `issue-worker` or falls",
17837
+ "through to its own fallback. Invoke it with this entry point's",
17838
+ "parameters:",
17839
+ "",
17840
+ "- **Entry point:** `already-conflicting`. There is no failed",
17841
+ " `gh pr update-branch` to read conflicting paths from \u2014 identify",
17842
+ " the conflicting files from the PR's merge state as documented in",
17843
+ " the shared procedure's entry-point step (a local rebase attempt",
17844
+ " whose `<<<<<<<` / `=======` / `>>>>>>>` markers name the",
17845
+ " conflicting files). The guards and classification are identical to",
17846
+ " the Phase 4 entry point.",
17847
+ "- **On the procedure returning `delegated`:** a rebase has been",
17848
+ " delegated to `issue-worker`; stop this pass. A human re-invokes",
17849
+ " the reviewer once the worker pushes the rebased branch.",
17850
+ "- **On the procedure returning `skipped` (a guard denied delegation",
17851
+ " or the guards failed):** fall back to the original hard reject \u2014",
17852
+ " post the merge-conflict rejection comment and stop. Use this",
17853
+ " comment **only** in the skipped case, never before the shared",
17854
+ " procedure has had its chance to auto-correct:",
17855
+ "",
17856
+ "```bash",
17857
+ "gh pr comment <pr-number> --body 'Not reviewable: merge conflicts \u2014 please rebase onto the default branch.'",
17858
+ "```",
17859
+ "",
17684
17860
  "## Phase 2: Gather Context",
17685
17861
  "",
17686
17862
  "```bash",
@@ -18382,37 +18558,215 @@ var prReviewerSubAgent = {
18382
18558
  "##### Conflict-resolution delegation (BEHIND + conflicts)",
18383
18559
  "",
18384
18560
  "When `gh pr update-branch <pr-number>` fails because the merge would",
18385
- "produce conflicts, the reviewer **may** delegate conflict resolution to",
18386
- "`issue-worker` via the existing feedback-mode delegation contract (the",
18387
- "same path Phase 4's in-scope-fix delegation uses). The reviewer never",
18388
- "hand-resolves conflicts itself \u2014 branch mutations always belong to",
18389
- "`issue-worker`.",
18561
+ "produce conflicts, hand off to the **Shared Procedure:",
18562
+ "Conflict-Resolution Delegation** section below. That procedure owns",
18563
+ "the guards, the `shared-index` vs `generic` classification, the two",
18564
+ "typed recipes, and the fallback \u2014 defined once and shared with the",
18565
+ "Phase 1.5 already-`CONFLICTING` entry point. Invoke it with this",
18566
+ "entry point's parameters:",
18567
+ "",
18568
+ "- **Entry point:** `update-branch-conflict`. The set of conflicting",
18569
+ " files is the list reported by the failed `gh pr update-branch`",
18570
+ " (cross-referenced with `gh pr view <pr-number> --json files`).",
18571
+ "- **On the procedure returning `delegated`:** record",
18572
+ " `Branch updated: delegated (PR #<n>)` for the per-PR report.",
18573
+ "- **On the procedure returning `skipped` (a guard denied delegation",
18574
+ " or the guards failed):** the procedure has already posted the",
18575
+ " fallback comment and recorded",
18576
+ " `Branch updated: failed (conflicts; <short reason>)`. Stop.",
18577
+ "",
18578
+ "#### Mode `human-required`",
18579
+ "",
18580
+ "Do **not** run `gh pr merge --auto`. Instead, hand the PR off to a",
18581
+ "human reviewer:",
18582
+ "",
18583
+ "1. Apply the `review:awaiting-human` label so the PR is discoverable",
18584
+ " in the human-review queue:",
18585
+ "",
18586
+ " ```bash",
18587
+ " gh pr edit <pr-number> --add-label 'review:awaiting-human'",
18588
+ " ```",
18589
+ "",
18590
+ "2. **If `matched_rule == 6`** (size threshold was the sole trigger),",
18591
+ " run the `Update the branch when `mergeStateStatus` is `BEHIND``",
18592
+ " step from the `Mode auto-merge` branch above before exiting. The",
18593
+ " eligibility gate documented in that sub-section explicitly permits",
18594
+ " `gh pr update-branch` on size-only human-required PRs so the bot",
18595
+ " keeps the branch fresh against the default branch while the human",
18596
+ " reviews. Skip this sub-step for `matched_rule` in 2\u20135 \u2014 the gate",
18597
+ " denies `update-branch` there and the human owns branch-lifecycle.",
18598
+ "",
18599
+ "3. Exit cleanly after the acceptance-criteria check completes and any",
18600
+ " summary comment the reviewer posts. Proceed to Phase 5 only if a",
18601
+ " merge occurred \u2014 in `human-required` mode the reviewer stops at",
18602
+ " the hand-off and does not poll for merge.",
18603
+ "",
18604
+ "The reason captured in Phase 2.75 should be included in any summary",
18605
+ "comment so maintainers know why human review was required (path hit,",
18606
+ "issue type, size threshold, label, or default).",
18607
+ "",
18608
+ "### If any criterion is missing, partial, or CI is failing",
18609
+ "",
18610
+ "Post a plain comment (not a formal review block) with grouped findings:",
18611
+ "",
18612
+ "```bash",
18613
+ "gh pr comment <pr-number> --body '<grouped findings>'",
18614
+ "```",
18615
+ "",
18616
+ "Group findings by severity (**Blocking** / **Suggested** / **Nitpick**).",
18617
+ "For each blocking finding, cite the unmet acceptance criterion and the",
18618
+ "file or function the gap lives in. Do **not** merge, and do **not** push",
18619
+ "any commits to the PR's branch.",
18620
+ "",
18621
+ "Rationale for using a plain comment rather than `gh pr review",
18622
+ "--request-changes`: it is lighter-weight, doesn't require the author to",
18623
+ "dismiss a formal review, and composes cleanly with the multi-PR loop.",
18624
+ "",
18625
+ "## Phase 4.5: Update Sticky Summary",
18626
+ "",
18627
+ "On **every pass**, create or update a single **`## Reviewer notes`**",
18628
+ "comment on the PR. This sticky comment is the human-facing single",
18629
+ "source of truth for the PR's state \u2014 one comment per PR, edited in",
18630
+ "place across passes, never duplicated. Do not post a fresh",
18631
+ '"pass N summary" on each iteration.',
18632
+ "",
18633
+ "### Step 1: Find the existing sticky comment (if any)",
18634
+ "",
18635
+ "List PR-level comments and look for one authored by the reviewer",
18636
+ "whose body starts with `## Reviewer notes`:",
18637
+ "",
18638
+ "```bash",
18639
+ "gh api repos/{{repository.owner}}/{{repository.name}}/issues/<pr-number>/comments",
18640
+ "```",
18641
+ "",
18642
+ "If multiple candidates exist (an older run double-posted before this",
18643
+ "phase existed), keep the earliest and plan to delete the duplicates",
18644
+ "on a later pass. Never delete another author's comment.",
18645
+ "",
18646
+ "### Step 2: Compose the sticky body",
18647
+ "",
18648
+ "The body uses the following shape:",
18649
+ "",
18650
+ "```",
18651
+ "## Reviewer notes",
18652
+ "",
18653
+ "**Mode:** auto-merge | human-required \u2014 <reason from Phase 2.75>",
18654
+ "**AC status:** <met / partial / missing> (evidence links)",
18655
+ "**CI status:** green | pending | red",
18656
+ "**Outstanding:** <list of comments still open with their classification and author>",
18657
+ "**Pushbacks:** <list of disputes with reasons>",
18658
+ "**Last pass:** <ISO timestamp>",
18659
+ "```",
18660
+ "",
18661
+ "Populate each field from the phases above:",
18662
+ "",
18663
+ "- **Mode / reason** \u2014 the mode and reason recorded in Phase 2.75.",
18664
+ "- **AC status** \u2014 the checklist produced in Phase 3 (met, partial,",
18665
+ " or missing), with links to the files or tests that provide the",
18666
+ " evidence.",
18667
+ "- **CI status** \u2014 the verdict from the **CI Verification** section",
18668
+ " (primary check-runs read, or the Actions-runs fallback when",
18669
+ " check-runs returns a fine-grained-PAT 403).",
18670
+ "- **Outstanding** \u2014 the comments still carrying a non-terminal",
18671
+ " reviewer reaction from Phase 3.5 (typically `eyes` for queued",
18672
+ " in-scope items and `nit` / `question` items that remain open).",
18673
+ " List each as `<classification>: <author> \u2014 <short summary> (<url>)`.",
18674
+ "- **Pushbacks** \u2014 every comment the reviewer reacted",
18675
+ " `thinking_face` to on this or any prior pass, with the reason",
18676
+ " captured in the pushback reply. Empty list when there are none.",
18677
+ "- **Last pass** \u2014 the ISO 8601 timestamp of this run.",
18678
+ "",
18679
+ "### Step 3: Create or edit in place",
18680
+ "",
18681
+ "If no existing sticky comment was found in Step 1, create one:",
18682
+ "",
18683
+ "```bash",
18684
+ "gh pr comment <pr-number> --body '<sticky body>'",
18685
+ "```",
18686
+ "",
18687
+ "If an existing sticky comment was found, edit it in place using the",
18688
+ "comment id. Do not delete and re-create \u2014 editing preserves the",
18689
+ "comment's URL and any reactions humans have added to the summary:",
18690
+ "",
18691
+ "```bash",
18692
+ "gh api repos/{{repository.owner}}/{{repository.name}}/issues/comments/<sticky-comment-id> \\",
18693
+ " -X PATCH -f body='<sticky body>'",
18694
+ "```",
18695
+ "",
18696
+ "The sticky summary must be updated on every pass through Phase 4.5,",
18697
+ "including passes that ended in a pushback-gated skip, a",
18698
+ "`NEEDS_CHANGES` findings comment, or the `human-required` hand-off.",
18699
+ "Humans rely on the sticky comment to see the current state of the",
18700
+ "PR at a glance \u2014 it must never go stale while the reviewer is",
18701
+ "actively processing the PR.",
18702
+ "",
18703
+ "## Shared Procedure: Conflict-Resolution Delegation",
18704
+ "",
18705
+ "This procedure resolves a PR that cannot land because its head",
18706
+ "branch conflicts with the default branch. It is invoked from **two**",
18707
+ "entry points, both of which reuse the identical guards,",
18708
+ "classification, typed recipes, and fallback defined here \u2014 the flow",
18709
+ "is defined **once** and shared:",
18710
+ "",
18711
+ "- **Phase 4 `update-branch-conflict`** \u2014 a PR that was MERGEABLE at",
18712
+ " Phase 1.5 went BEHIND, and `gh pr update-branch` then failed",
18713
+ " because the merge would conflict.",
18714
+ "- **Phase 1.5 `already-conflicting`** \u2014 the orchestrator handed the",
18715
+ " reviewer a PR that is **already** `CONFLICTING` (its",
18716
+ ' `mergeable == "CONFLICTING"`) before any review work began.',
18717
+ "",
18718
+ "The reviewer **may** delegate conflict resolution to `issue-worker`",
18719
+ "via the feedback-mode delegation contract (the same path Phase 4's",
18720
+ "in-scope-fix delegation uses). The reviewer never hand-resolves",
18721
+ "conflicts itself \u2014 branch mutations always belong to `issue-worker`.",
18722
+ "",
18723
+ "### Entry-point parameters",
18724
+ "",
18725
+ "The caller supplies which entry point it is and how the conflicting",
18726
+ "files are identified. Everything after this step is identical across",
18727
+ "both entry points.",
18728
+ "",
18729
+ "- **`update-branch-conflict`** \u2014 the conflicting-file set is the",
18730
+ " list reported by the failed `gh pr update-branch` (cross-referenced",
18731
+ " with `gh pr view <pr-number> --json files`).",
18732
+ "- **`already-conflicting`** \u2014 there is no failed `update-branch` to",
18733
+ " read conflicting paths from. Identify the conflicting files from",
18734
+ " the PR's merge state instead: attempt a local rebase of the head",
18735
+ " branch onto the default branch in a scratch checkout (or read the",
18736
+ " conflicting paths git reports) and collect the files that carry",
18737
+ " `<<<<<<<` / `=======` / `>>>>>>>` conflict markers. Use that set",
18738
+ " as the conflicting-file list. The reviewer inspects these markers",
18739
+ " read-only to classify; it does **not** stage, commit, or push any",
18740
+ " resolution \u2014 the actual rebase-and-resolve is delegated to",
18741
+ " `issue-worker` exactly as in the other entry point.",
18742
+ "",
18743
+ "### Guards",
18390
18744
  "",
18391
18745
  "Delegate **only when all** of the following hold. If any guard fails,",
18392
- "fall through to the fallback at the end of this sub-section instead.",
18746
+ "fall through to the **Fallback** at the end of this procedure and",
18747
+ "return `skipped`.",
18393
18748
  "",
18394
18749
  "1. **Review mode is `auto-merge`.** Never delegate conflict",
18395
18750
  " resolution on `human-required` PRs \u2014 pushing worker-resolved",
18396
18751
  " merge content into them expands the diff under review without",
18397
- " the human reviewer's consent. (Unlike the `update-branch` step",
18398
- " above, which permits a size-only `human-required` carve-out, the",
18752
+ " the human reviewer's consent. (Unlike the `update-branch` step,",
18753
+ " which permits a size-only `human-required` carve-out, the",
18399
18754
  " conflict-resolution delegation flow is auto-merge-only across",
18400
18755
  " the board: a worker rebase push is a stronger branch mutation",
18401
18756
  " than the merge-commit `gh pr update-branch` performs.)",
18402
18757
  "2. **Delegation invocation guard permits the hand-off** \u2014 the PR",
18403
18758
  " carries the `origin:issue-worker` label, **or** the reviewer was",
18404
18759
  " invoked with `--allow-human-author`. The same guard used for the",
18405
- " in-scope-fix delegation flow above applies here unchanged.",
18760
+ " in-scope-fix delegation flow applies here unchanged.",
18406
18761
  "3. **The `review:fixing` lease is currently free.** If",
18407
18762
  " `review:fixing` is already on the PR, another delegation is",
18408
18763
  " in-flight; skip conflict-resolution delegation, log the contention",
18409
18764
  " to the sticky summary, and fall through to the fallback.",
18410
- "4. **No conflicting file is generated or projen-managed.** Run",
18411
- " `gh pr view <pr-number> --json files --jq '.files[].path'` and",
18412
- " inspect the conflicting paths reported by the failed",
18413
- " `update-branch`. If **any** conflicting path matches one of the",
18414
- " following globs, the conflict is unsafe to resolve mechanically",
18415
- " and the reviewer must skip delegation:",
18765
+ "4. **No conflicting file is generated or projen-managed.** Inspect",
18766
+ " the conflicting paths from the entry-point step above. If **any**",
18767
+ " conflicting path matches one of the following globs, the conflict",
18768
+ " is unsafe to resolve mechanically and the reviewer must skip",
18769
+ " delegation:",
18416
18770
  " - `**/*.lock` and `pnpm-lock.yaml` / `yarn.lock` / `package-lock.json`",
18417
18771
  " - `**/.projen/**`",
18418
18772
  " - any file whose first 5 lines contain the marker",
@@ -18423,17 +18777,18 @@ var prReviewerSubAgent = {
18423
18777
  " and conflicts there should be resolved by re-running synth, not by",
18424
18778
  " merging the conflict markers.",
18425
18779
  "",
18780
+ "### Classify each conflicting file",
18781
+ "",
18426
18782
  "When every guard above passes, **classify each conflicting file**",
18427
18783
  "before composing the fix-list. The classification picks one of two",
18428
18784
  "typed recipes \u2014 a precise `shared-index` resolver when every",
18429
18785
  "conflict is a row-insert race on a registry / index / feature-matrix",
18430
18786
  "file, or the generic rebase recipe in every other case.",
18431
18787
  "",
18432
- "**Classification step.** For each conflicting path reported by the",
18433
- "failed `update-branch`, decide whether the file is `shared-index` or",
18434
- "`generic` against these criteria (the shared-index glob set comes",
18435
- "from the `shared-editing-safety` rule \u2014 see the bundle's",
18436
- "`shared-editing.ts` for the canonical constant):",
18788
+ "**Classification step.** For each conflicting path, decide whether",
18789
+ "the file is `shared-index` or `generic` against these criteria (the",
18790
+ "shared-index glob set comes from the `shared-editing-safety` rule \u2014",
18791
+ "see the bundle's `shared-editing.ts` for the canonical constant):",
18437
18792
  "",
18438
18793
  "- `shared-index` \u2014 the path matches one of the shared-editing glob",
18439
18794
  " patterns:",
@@ -18468,6 +18823,8 @@ var prReviewerSubAgent = {
18468
18823
  " (see step 3 below). The worker performs a hand-merge of the",
18469
18824
  " conflict markers.",
18470
18825
  "",
18826
+ "### Hand off to `issue-worker`",
18827
+ "",
18471
18828
  "Hand off to `issue-worker` with the chosen single synthetic",
18472
18829
  "fix-list item:",
18473
18830
  "",
@@ -18555,146 +18912,24 @@ var prReviewerSubAgent = {
18555
18912
  "",
18556
18913
  "7. **Do not re-enable auto-merge in the same pass.** After delegation,",
18557
18914
  " exit and let a human re-invoke the reviewer. The next pass will",
18558
- " re-evaluate `mergeStateStatus` against the rebased branch and",
18559
- " re-enable auto-merge through the normal flow above.",
18915
+ " re-evaluate `mergeStateStatus` (or `mergeable`) against the",
18916
+ " rebased branch and re-enable auto-merge through the normal flow.",
18917
+ "",
18918
+ "Return `delegated` to the caller when delegation completes",
18919
+ "(regardless of the worker's outcome \u2014 the delegation itself is the",
18920
+ "action taken).",
18560
18921
  "",
18561
- "Record `Branch updated: delegated (PR #<n>)` for the per-PR report",
18562
- "when delegation completes (regardless of the worker's outcome \u2014 the",
18563
- "delegation itself is the action taken).",
18922
+ "### Fallback",
18564
18923
  "",
18565
18924
  "**Fallback when delegation is not permitted or guards fail.** Post a",
18566
18925
  "short comment explaining why the branch could not be updated",
18567
18926
  "automatically and stop. Do not push commits, do not force, do not",
18568
- "retry. Record `Branch updated: failed (conflicts; <short reason>)`.",
18569
- "",
18570
- "```bash",
18571
- "gh pr comment <pr-number> --body 'Auto-merge queued; branch is BEHIND <default-branch> with conflicts. <short reason delegation was skipped \u2014 e.g. human-required mode, generated-file conflicts, or in-flight review:fixing lease>. A human (or the next reviewer pass after rebase) will need to resolve.'",
18572
- "```",
18573
- "",
18574
- "#### Mode `human-required`",
18575
- "",
18576
- "Do **not** run `gh pr merge --auto`. Instead, hand the PR off to a",
18577
- "human reviewer:",
18578
- "",
18579
- "1. Apply the `review:awaiting-human` label so the PR is discoverable",
18580
- " in the human-review queue:",
18581
- "",
18582
- " ```bash",
18583
- " gh pr edit <pr-number> --add-label 'review:awaiting-human'",
18584
- " ```",
18585
- "",
18586
- "2. **If `matched_rule == 6`** (size threshold was the sole trigger),",
18587
- " run the `Update the branch when `mergeStateStatus` is `BEHIND``",
18588
- " step from the `Mode auto-merge` branch above before exiting. The",
18589
- " eligibility gate documented in that sub-section explicitly permits",
18590
- " `gh pr update-branch` on size-only human-required PRs so the bot",
18591
- " keeps the branch fresh against the default branch while the human",
18592
- " reviews. Skip this sub-step for `matched_rule` in 2\u20135 \u2014 the gate",
18593
- " denies `update-branch` there and the human owns branch-lifecycle.",
18594
- "",
18595
- "3. Exit cleanly after the acceptance-criteria check completes and any",
18596
- " summary comment the reviewer posts. Proceed to Phase 5 only if a",
18597
- " merge occurred \u2014 in `human-required` mode the reviewer stops at",
18598
- " the hand-off and does not poll for merge.",
18599
- "",
18600
- "The reason captured in Phase 2.75 should be included in any summary",
18601
- "comment so maintainers know why human review was required (path hit,",
18602
- "issue type, size threshold, label, or default).",
18603
- "",
18604
- "### If any criterion is missing, partial, or CI is failing",
18605
- "",
18606
- "Post a plain comment (not a formal review block) with grouped findings:",
18607
- "",
18608
- "```bash",
18609
- "gh pr comment <pr-number> --body '<grouped findings>'",
18610
- "```",
18611
- "",
18612
- "Group findings by severity (**Blocking** / **Suggested** / **Nitpick**).",
18613
- "For each blocking finding, cite the unmet acceptance criterion and the",
18614
- "file or function the gap lives in. Do **not** merge, and do **not** push",
18615
- "any commits to the PR's branch.",
18616
- "",
18617
- "Rationale for using a plain comment rather than `gh pr review",
18618
- "--request-changes`: it is lighter-weight, doesn't require the author to",
18619
- "dismiss a formal review, and composes cleanly with the multi-PR loop.",
18620
- "",
18621
- "## Phase 4.5: Update Sticky Summary",
18622
- "",
18623
- "On **every pass**, create or update a single **`## Reviewer notes`**",
18624
- "comment on the PR. This sticky comment is the human-facing single",
18625
- "source of truth for the PR's state \u2014 one comment per PR, edited in",
18626
- "place across passes, never duplicated. Do not post a fresh",
18627
- '"pass N summary" on each iteration.',
18628
- "",
18629
- "### Step 1: Find the existing sticky comment (if any)",
18630
- "",
18631
- "List PR-level comments and look for one authored by the reviewer",
18632
- "whose body starts with `## Reviewer notes`:",
18927
+ "retry. Record `Branch updated: failed (conflicts; <short reason>)`",
18928
+ "and return `skipped` to the caller.",
18633
18929
  "",
18634
18930
  "```bash",
18635
- "gh api repos/{{repository.owner}}/{{repository.name}}/issues/<pr-number>/comments",
18636
- "```",
18637
- "",
18638
- "If multiple candidates exist (an older run double-posted before this",
18639
- "phase existed), keep the earliest and plan to delete the duplicates",
18640
- "on a later pass. Never delete another author's comment.",
18641
- "",
18642
- "### Step 2: Compose the sticky body",
18643
- "",
18644
- "The body uses the following shape:",
18645
- "",
18931
+ "gh pr comment <pr-number> --body 'Branch is BEHIND <default-branch> with conflicts. <short reason delegation was skipped \u2014 e.g. human-required mode, generated-file conflicts, or in-flight review:fixing lease>. A human (or the next reviewer pass after rebase) will need to resolve.'",
18646
18932
  "```",
18647
- "## Reviewer notes",
18648
- "",
18649
- "**Mode:** auto-merge | human-required \u2014 <reason from Phase 2.75>",
18650
- "**AC status:** <met / partial / missing> (evidence links)",
18651
- "**CI status:** green | pending | red",
18652
- "**Outstanding:** <list of comments still open with their classification and author>",
18653
- "**Pushbacks:** <list of disputes with reasons>",
18654
- "**Last pass:** <ISO timestamp>",
18655
- "```",
18656
- "",
18657
- "Populate each field from the phases above:",
18658
- "",
18659
- "- **Mode / reason** \u2014 the mode and reason recorded in Phase 2.75.",
18660
- "- **AC status** \u2014 the checklist produced in Phase 3 (met, partial,",
18661
- " or missing), with links to the files or tests that provide the",
18662
- " evidence.",
18663
- "- **CI status** \u2014 the verdict from the **CI Verification** section",
18664
- " (primary check-runs read, or the Actions-runs fallback when",
18665
- " check-runs returns a fine-grained-PAT 403).",
18666
- "- **Outstanding** \u2014 the comments still carrying a non-terminal",
18667
- " reviewer reaction from Phase 3.5 (typically `eyes` for queued",
18668
- " in-scope items and `nit` / `question` items that remain open).",
18669
- " List each as `<classification>: <author> \u2014 <short summary> (<url>)`.",
18670
- "- **Pushbacks** \u2014 every comment the reviewer reacted",
18671
- " `thinking_face` to on this or any prior pass, with the reason",
18672
- " captured in the pushback reply. Empty list when there are none.",
18673
- "- **Last pass** \u2014 the ISO 8601 timestamp of this run.",
18674
- "",
18675
- "### Step 3: Create or edit in place",
18676
- "",
18677
- "If no existing sticky comment was found in Step 1, create one:",
18678
- "",
18679
- "```bash",
18680
- "gh pr comment <pr-number> --body '<sticky body>'",
18681
- "```",
18682
- "",
18683
- "If an existing sticky comment was found, edit it in place using the",
18684
- "comment id. Do not delete and re-create \u2014 editing preserves the",
18685
- "comment's URL and any reactions humans have added to the summary:",
18686
- "",
18687
- "```bash",
18688
- "gh api repos/{{repository.owner}}/{{repository.name}}/issues/comments/<sticky-comment-id> \\",
18689
- " -X PATCH -f body='<sticky body>'",
18690
- "```",
18691
- "",
18692
- "The sticky summary must be updated on every pass through Phase 4.5,",
18693
- "including passes that ended in a pushback-gated skip, a",
18694
- "`NEEDS_CHANGES` findings comment, or the `human-required` hand-off.",
18695
- "Humans rely on the sticky comment to see the current state of the",
18696
- "PR at a glance \u2014 it must never go stale while the reviewer is",
18697
- "actively processing the PR.",
18698
18933
  "",
18699
18934
  "## Phase 5: Branch Cleanup and Issue Closure Verification",
18700
18935
  "",
@@ -29975,13 +30210,20 @@ function renderFocusSection(focus) {
29975
30210
 
29976
30211
  // src/agent/bundles/meeting-types.ts
29977
30212
  var DEFAULT_AGENDA_TEMPLATE_ROOT = "<meetingsRoot>/_agenda-templates";
30213
+ function actionItemFilingHasOverride(filing) {
30214
+ if (!filing) {
30215
+ return false;
30216
+ }
30217
+ return filing.enabled === false || (filing.humanOwnedCues ?? []).length > 0 || (filing.agentWorkableCues ?? []).length > 0;
30218
+ }
29978
30219
  function renderMeetingTypesSection(meetings) {
29979
30220
  if (!meetings) {
29980
30221
  return "";
29981
30222
  }
29982
30223
  const types = meetings.meetingTypes ?? [];
29983
30224
  const areas = meetings.meetingAreas ?? [];
29984
- if (types.length === 0 && areas.length === 0) {
30225
+ const filingOverride = actionItemFilingHasOverride(meetings.actionItemFiling) ? meetings.actionItemFiling : void 0;
30226
+ if (types.length === 0 && areas.length === 0 && !filingOverride) {
29985
30227
  return "";
29986
30228
  }
29987
30229
  const sections = [];
@@ -29991,6 +30233,9 @@ function renderMeetingTypesSection(meetings) {
29991
30233
  if (areas.length > 0) {
29992
30234
  sections.push(renderMeetingAreas(areas));
29993
30235
  }
30236
+ if (filingOverride) {
30237
+ sections.push(renderActionItemFiling(filingOverride));
30238
+ }
29994
30239
  return sections.join("\n\n");
29995
30240
  }
29996
30241
  function renderMeetingTypes(types, agendaTemplateRoot) {
@@ -30044,6 +30289,54 @@ function renderMeetingAreas(areas) {
30044
30289
  }
30045
30290
  return lines.join("\n");
30046
30291
  }
30292
+ function renderActionItemFiling(filing) {
30293
+ const lines = [
30294
+ "## Action-item filing policy",
30295
+ "",
30296
+ "This project tunes the Phase 4 (Link) agent-workability split",
30297
+ "through `AgentConfigOptions.meetings.actionItemFiling`. See the",
30298
+ "**Action-item filing policy** section of the `meeting-analyst`",
30299
+ "agent for the full baked-in test.",
30300
+ ""
30301
+ ];
30302
+ if (filing.enabled === false) {
30303
+ lines.push(
30304
+ "- **Split disabled.** Phase 4 falls back to the legacy behaviour:",
30305
+ " file a follow-up issue for every action item that is not",
30306
+ " already covered by a requirement or ADR draft, including",
30307
+ " human-owned tasks. The notes `## Action Items` table is still",
30308
+ " written, but it is no longer the sole record for human",
30309
+ " follow-ups."
30310
+ );
30311
+ } else {
30312
+ lines.push(
30313
+ "- **Split enabled** (default). Agent-workable doc deliverables are",
30314
+ " filed through their dedicated downstream channel; human-owned",
30315
+ " tasks are recorded only in the notes `## Action Items` table."
30316
+ );
30317
+ }
30318
+ const humanCues = filing.humanOwnedCues ?? [];
30319
+ if (humanCues.length > 0) {
30320
+ lines.push(
30321
+ "",
30322
+ "**Additional human-owned cues** (recorded notes-only, never",
30323
+ "filed), in addition to the bundle's built-in list:",
30324
+ "",
30325
+ ...humanCues.map((cue) => `- ${cue}`)
30326
+ );
30327
+ }
30328
+ const agentCues = filing.agentWorkableCues ?? [];
30329
+ if (agentCues.length > 0) {
30330
+ lines.push(
30331
+ "",
30332
+ "**Additional agent-workable cues** (filed through the matching",
30333
+ "downstream channel), in addition to the bundle's built-in list:",
30334
+ "",
30335
+ ...agentCues.map((cue) => `- ${cue}`)
30336
+ );
30337
+ }
30338
+ return lines.join("\n");
30339
+ }
30047
30340
 
30048
30341
  // src/agent/bundles/priority-rules.ts
30049
30342
  function renderPriorityRulesSection(rules) {