@codedrifters/configulator 0.0.260 → 0.0.262

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
@@ -4445,7 +4445,7 @@ var jestBundle = {
4445
4445
  // src/agent/bundles/maintenance-audit.ts
4446
4446
  var maintenanceAuditSubAgent = {
4447
4447
  name: "maintenance-audit",
4448
- description: "Audits documentation registries and cross-references for integrity (broken links, registry drift, stale indexes) and applies idempotent fixes. One phase per session, tracked by maint:* GitHub issue labels with filesystem-based durability between phases.",
4448
+ description: "Audits documentation registries and cross-references for integrity (broken links, registry drift, stale indexes), applies idempotent fixes, then re-runs the checks to confirm the fixes cleared the reported findings. One phase per session, tracked by maint:* GitHub issue labels with filesystem-based durability between phases.",
4449
4449
  model: AGENT_MODEL.POWERFUL,
4450
4450
  maxTurns: 80,
4451
4451
  platforms: { cursor: { exclude: true } },
@@ -4503,18 +4503,18 @@ var maintenanceAuditSubAgent = {
4503
4503
  "",
4504
4504
  "## State Machine Overview",
4505
4505
  "",
4506
- "Maintenance audits flow through **2 phases**:",
4506
+ "Maintenance audits flow through **3 phases**:",
4507
4507
  "",
4508
4508
  "```",
4509
- "\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
4510
- "\u2502 1. SCAN \u2502\u2500\u2500\u2500\u2500\u25B6\u2502 2. FIX \u2502",
4511
- "\u2502 Walk doc \u2502 \u2502 Read audit \u2502",
4512
- "\u2502 tree, check \u2502 \u2502 report, \u2502",
4513
- "\u2502 xrefs and \u2502 \u2502 apply safe \u2502",
4514
- "\u2502 indexes, \u2502 \u2502 idempotent \u2502",
4515
- "\u2502 write audit \u2502 \u2502 fixes, then \u2502",
4516
- "\u2502 report \u2502 \u2502 verify \u2502",
4517
- "\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
4509
+ "\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
4510
+ "\u2502 1. SCAN \u2502\u2500\u2500\u2500\u2500\u25B6\u2502 2. FIX \u2502\u2500\u2500\u2500\u2500\u25B6\u2502 3. VERIFY \u2502",
4511
+ "\u2502 Walk doc \u2502 \u2502 Read audit \u2502 \u2502 Re-run the \u2502",
4512
+ "\u2502 tree, check \u2502 \u2502 report, \u2502 \u2502 scan checks \u2502",
4513
+ "\u2502 xrefs and \u2502 \u2502 apply safe \u2502 \u2502 scoped to \u2502",
4514
+ "\u2502 indexes, \u2502 \u2502 idempotent \u2502 \u2502 fixed paths,\u2502",
4515
+ "\u2502 write audit \u2502 \u2502 fixes, write\u2502 \u2502 compare pre \u2502",
4516
+ "\u2502 report \u2502 \u2502 fix report \u2502 \u2502 and post \u2502",
4517
+ "\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
4518
4518
  "```",
4519
4519
  "",
4520
4520
  "**Issue labels encode the phase:**",
@@ -4522,18 +4522,22 @@ var maintenanceAuditSubAgent = {
4522
4522
  "| Label | Phase | Session work |",
4523
4523
  "|-------|-------|-------------|",
4524
4524
  "| `maint:scan` | 1. Scan | Walk the configured doc tree, check cross-references and registry indexes, write a durable audit report. |",
4525
- "| `maint:fix` | 2. Fix | Read the audit report, apply idempotent fixes, then verify the fixes cleared the reported findings. |",
4525
+ "| `maint:fix` | 2. Fix | Read the audit report, apply idempotent fixes, write a durable fix report. |",
4526
+ "| `maint:verify` | 3. Verify | Re-run the same checks from the parent `maint:scan` issue scoped to the paths and registries the fix phase touched, compare pre and post findings, close the parent scan issue when clean, and file a follow-up `maint:scan` for any residual findings. |",
4526
4527
  "",
4527
4528
  "All issues also carry `type:maintenance` and a `status:*` label.",
4528
4529
  "",
4529
- "**Issue count per audit cycle:** 1 scan + 1 fix = **2 sessions**.",
4530
+ "**Issue count per audit cycle:** 1 scan + 1 fix + 1 verify = **3 sessions**.",
4530
4531
  "",
4531
4532
  "**Shortened paths:**",
4532
4533
  "- Scan finds no issues \u2192 close scan issue with a justification,",
4533
- " do not create a fix issue \u2192 **1 session**.",
4534
+ " do not create a fix or verify issue \u2192 **1 session**.",
4534
4535
  "- Every reported finding requires a human judgment call \u2192 close",
4535
4536
  " scan with the report, open a `status:needs-attention` flag,",
4536
- " do not auto-create a fix issue \u2192 **1 session**.",
4537
+ " do not auto-create a fix or verify issue \u2192 **1 session**.",
4538
+ "- Fix phase applied only `flag-for-human` decisions (no auto-",
4539
+ " fixable findings landed) \u2192 close the fix issue with the",
4540
+ " skipped list and do not create a verify issue \u2192 **2 sessions**.",
4537
4541
  "",
4538
4542
  "---",
4539
4543
  "",
@@ -4563,7 +4567,9 @@ var maintenanceAuditSubAgent = {
4563
4567
  "Run this loop exactly once per session. Never start a second issue.",
4564
4568
  "",
4565
4569
  "1. Claim one open `type:maintenance` issue using phase priority:",
4566
- " `maint:scan` > `maint:fix`.",
4570
+ " `maint:verify` > `maint:fix` > `maint:scan`. Verify ahead of fix",
4571
+ " and scan so the oldest in-flight audit cycle finishes closing",
4572
+ " the loop before a new cycle starts.",
4567
4573
  "2. Transition `status:ready` \u2192 `status:in-progress` and create the",
4568
4574
  " branch per your project's branch-naming convention.",
4569
4575
  "3. Execute the phase handler that matches the issue's `maint:*`",
@@ -4675,24 +4681,30 @@ var maintenanceAuditSubAgent = {
4675
4681
  " - **All findings need human judgment** \u2192 commit the report,",
4676
4682
  " comment on the scan issue summarizing the findings, apply",
4677
4683
  " `status:needs-attention`, and close the issue. Do not create",
4678
- " a `maint:fix` issue.",
4684
+ " a `maint:fix` or `maint:verify` issue.",
4679
4685
  " - **At least one auto-fixable finding** \u2192 create a `maint:fix`",
4680
4686
  " issue (blocked on this scan issue via `Depends on: #N`). The",
4681
- " fix issue body must reference the audit report path and",
4682
- " enumerate the auto-fix categories to apply.",
4687
+ " fix issue body must reference the audit report path, enumerate",
4688
+ " the auto-fix categories to apply, and record the parent scan",
4689
+ " issue number so Phase 3 (Verify) can close the loop.",
4683
4690
  "",
4684
- "6. **Commit and push.**",
4691
+ "6. **Commit and push.** Leave the scan issue open so the downstream",
4692
+ " `maint:verify` phase can close it (or file a follow-up scan)",
4693
+ " after Phase 2 runs.",
4685
4694
  "",
4686
4695
  "---",
4687
4696
  "",
4688
4697
  "## Phase 2: Fix (`maint:fix`)",
4689
4698
  "",
4690
- "**Goal:** Read the audit report, apply idempotent fixes, verify",
4691
- "they cleared the reported findings, and commit the doc-tree changes.",
4699
+ "**Goal:** Read the audit report, apply idempotent fixes, write a",
4700
+ "fix report, and enqueue the verify phase so the audit cycle",
4701
+ "actually closes its loop.",
4692
4702
  "",
4693
- "**Budget:** Bounded edits to files under `<DOCS_ROOT>` plus a final",
4694
- "verification re-run of the checks from Phase 1. No new audit",
4695
- "categories. No fixes that require authoring new content.",
4703
+ "**Budget:** Bounded edits to files under `<DOCS_ROOT>` and one fix",
4704
+ "report file. No new audit categories. No fixes that require",
4705
+ "authoring new content. The formal re-scan lives in Phase 3 \u2014",
4706
+ "Phase 2 confirms only that it did not regress the files it touched",
4707
+ "(a smoke check, not the full pre/post comparison).",
4696
4708
  "",
4697
4709
  "### Fix Categories",
4698
4710
  "",
@@ -4726,11 +4738,13 @@ var maintenanceAuditSubAgent = {
4726
4738
  " mark it `flag-for-human` and skip. Authoring new docs belongs",
4727
4739
  " to the writer agent for that doc type, not this agent.",
4728
4740
  "",
4729
- "5. **Verify.** Re-run the same checks the scan phase ran, scoped",
4730
- " to the files the fix phase touched (plus any index files those",
4731
- " edits affect). Every finding the fix phase claimed to resolve",
4732
- " must now be gone. Any finding that remains is a regression \u2014",
4733
- " revert the corresponding edit and mark it `flag-for-human`.",
4741
+ "5. **Smoke check the touched files.** Before writing the fix",
4742
+ " report, spot-check that the specific findings the fix phase",
4743
+ " claimed to resolve are at least no longer present in the edited",
4744
+ " file(s). This is a narrow local check \u2014 not the full re-scan,",
4745
+ " which is Phase 3's job. If a finding the fix phase targeted",
4746
+ " still reproduces in the edited file, revert that edit and mark",
4747
+ " the finding `flag-for-human` in the fix report instead.",
4734
4748
  "",
4735
4749
  "6. **Write the fix report** to:",
4736
4750
  " ```",
@@ -4761,18 +4775,141 @@ var maintenanceAuditSubAgent = {
4761
4775
  "",
4762
4776
  " ## Skipped",
4763
4777
  " <findings that were stale, flagged for human, or reverted",
4764
- " during verification \u2014 one entry each, with the reason>",
4778
+ " during the smoke check \u2014 one entry each, with the reason>",
4765
4779
  "",
4766
- " ## Verification",
4767
- " - **Re-scan result:** clean / <N> residual findings",
4768
- " - **Residual findings:** <list, with reasons \u2014 each becomes a",
4769
- " follow-up `flag-for-human` note>",
4780
+ " ## Paths Touched",
4781
+ " <ordered list of files edited, plus any index files those edits",
4782
+ " affect. This is the Phase 3 re-scan scope \u2014 the verify phase",
4783
+ " reads this section to decide which paths to re-check.>",
4770
4784
  " ```",
4771
4785
  "",
4772
4786
  "7. **Comment on the scan issue** with a summary of what was fixed,",
4773
- " what was skipped, and any residual findings.",
4787
+ " what was skipped, and that Phase 3 (Verify) will close the loop.",
4788
+ "",
4789
+ "8. **Create the `maint:verify` issue.** Block it on this fix issue",
4790
+ " via `Depends on: #N` so it only runs after the fix PR lands.",
4791
+ " The verify issue body must reference:",
4792
+ " - The parent `maint:scan` issue number",
4793
+ " - The Phase 1 audit report path",
4794
+ " - The Phase 2 fix report path",
4795
+ " - The `Paths Touched` list (so Phase 3 scopes the re-scan",
4796
+ " correctly)",
4797
+ " - The same check catalog the scan phase used",
4798
+ "",
4799
+ " If the fix phase applied **zero** auto-fixes (every finding was",
4800
+ " `stale-finding` or `flag-for-human`), skip the verify issue \u2014",
4801
+ " there is nothing to verify. Close the fix issue with a summary,",
4802
+ " comment on the scan issue, and let a human decide whether to",
4803
+ " re-scan.",
4804
+ "",
4805
+ "9. **Commit and push.**",
4774
4806
  "",
4775
- "8. **Commit and push.**",
4807
+ "---",
4808
+ "",
4809
+ "## Phase 3: Verify (`maint:verify`)",
4810
+ "",
4811
+ "**Goal:** Close the loop on the audit cycle. Re-run the same checks",
4812
+ "the scan phase ran, scoped to the paths and registries the fix",
4813
+ "phase actually touched, compare pre and post findings, and record",
4814
+ "the result in a durable verify report.",
4815
+ "",
4816
+ "**Budget:** Filesystem reads + registry parsing, just like Phase 1,",
4817
+ "but bounded to the paths enumerated in the fix report's",
4818
+ "`Paths Touched` section (plus any index files those paths transit).",
4819
+ "No edits to source docs in this phase \u2014 if the re-scan surfaces a",
4820
+ "regression, record it and file a follow-up `maint:scan` issue,",
4821
+ "but do not attempt to re-fix in-session.",
4822
+ "",
4823
+ "### Steps",
4824
+ "",
4825
+ "1. **Read the verify scope** from the issue body. Confirm the parent",
4826
+ " scan issue number, the audit report path, the fix report path,",
4827
+ " and the `Paths Touched` list. If any of these are missing or",
4828
+ " the files they reference do not exist, close the verify issue",
4829
+ " with `status:needs-attention` and stop.",
4830
+ "",
4831
+ "2. **Re-run the same checks the scan phase ran**, scoped to the",
4832
+ " paths the fix phase touched plus any index or registry files",
4833
+ " those paths transit. Use the identical check catalog that the",
4834
+ " parent scan issue declared \u2014 do not add or remove checks",
4835
+ " between scan and verify.",
4836
+ "",
4837
+ "3. **Compare pre and post findings.** For each finding in the Phase 1",
4838
+ " audit report that fell within the re-scan scope, classify it as:",
4839
+ " - **resolved** \u2014 absent from the re-scan; the fix worked.",
4840
+ " - **still-failing** \u2014 still present in the re-scan; the fix did",
4841
+ " not clear it.",
4842
+ " - **regressed** \u2014 was not in the Phase 1 audit report but appears",
4843
+ " now; the fix introduced it.",
4844
+ " - **out-of-scope** \u2014 was in the Phase 1 audit report but its",
4845
+ " path was not in the fix phase's `Paths Touched` list, so this",
4846
+ " verify pass cannot speak to it.",
4847
+ "",
4848
+ "4. **Write the verify report** to:",
4849
+ " ```",
4850
+ " <AUDIT_ROOT>/maint-verify-<AUDIT_SLUG>-<YYYY-MM-DD>.md",
4851
+ " ```",
4852
+ "",
4853
+ " Format:",
4854
+ " ```markdown",
4855
+ " ---",
4856
+ ' title: "Maintenance Verify: <AUDIT_SLUG>"',
4857
+ " date: YYYY-MM-DD",
4858
+ " parent_issue: <N>",
4859
+ " scan_issue: <N>",
4860
+ " fix_issue: <N>",
4861
+ " audit_report: <path to Phase 1 scan report>",
4862
+ " fix_report: <path to Phase 2 fix report>",
4863
+ " status: complete",
4864
+ " ---",
4865
+ "",
4866
+ " # Maintenance Verify: <AUDIT_SLUG>",
4867
+ "",
4868
+ " ## Source Reports",
4869
+ " - Scan report: <link>",
4870
+ " - Fix report: <link>",
4871
+ "",
4872
+ " ## Re-scan Scope",
4873
+ " - **Paths re-checked:** <list \u2014 from the fix report's",
4874
+ " `Paths Touched` section>",
4875
+ " - **Checks re-run:** <same catalog the scan phase used>",
4876
+ "",
4877
+ " ## Pre/Post Comparison",
4878
+ " | Status | Count | Findings |",
4879
+ " |--------|-------|----------|",
4880
+ " | resolved | N | <one line per finding: category + file:line> |",
4881
+ " | still-failing | N | <one line per finding> |",
4882
+ " | regressed | N | <one line per finding> |",
4883
+ " | out-of-scope | N | <one line per finding> |",
4884
+ "",
4885
+ " ## Verdict",
4886
+ " - **clean** \u2014 every in-scope finding resolved and no regressions;",
4887
+ " the parent scan issue will be closed.",
4888
+ " - **residual** \u2014 one or more still-failing or regressed findings;",
4889
+ " a follow-up `maint:scan` issue is filed and the parent scan",
4890
+ " issue is closed with a reference to the follow-up.",
4891
+ " ```",
4892
+ "",
4893
+ "5. **Decide the next step:**",
4894
+ " - **Clean verdict** (every in-scope finding resolved, no",
4895
+ " regressions, no still-failing entries) \u2192 comment on the parent",
4896
+ " `maint:scan` issue summarizing the result and **close it**.",
4897
+ " Do not file a follow-up scan.",
4898
+ " - **Residual verdict** (one or more `still-failing` or",
4899
+ " `regressed` entries) \u2192 file a new `maint:scan` issue for the",
4900
+ " residual scope, blocked on nothing (it is ready to run on its",
4901
+ " own schedule), and link the verify report from its body. Then",
4902
+ " comment on the parent scan issue with the residual summary and",
4903
+ " **close it**.",
4904
+ " - **Out-of-scope-only verdict** (every finding fell outside the",
4905
+ " fix phase's `Paths Touched`) \u2192 comment on the parent scan",
4906
+ " issue explaining that the fix phase did not cover those paths",
4907
+ " and leave it open with `status:needs-attention` so a human can",
4908
+ " re-scope the cycle. Do not auto-close the parent scan issue",
4909
+ " in this case.",
4910
+ "",
4911
+ "6. **Commit and push.** Close the verify issue with a one-line",
4912
+ " summary of the verdict.",
4776
4913
  "",
4777
4914
  "---",
4778
4915
  "",
@@ -4782,11 +4919,13 @@ var maintenanceAuditSubAgent = {
4782
4919
  "|-----------|-------|------|",
4783
4920
  "| Downstream (last resort) | Writer agent for the audited doc type | When the audit surfaces findings that require authoring new content (missing target, partial coverage that can only be resolved by writing a new doc), the fix phase flags them for human \u2014 the human may then dispatch the appropriate writer agent. This agent never opens writer-agent issues itself. |",
4784
4921
  "",
4785
- "**File boundaries:** Writes audit and fix reports to",
4922
+ "**File boundaries:** Writes audit, fix, and verify reports to",
4786
4923
  "`<AUDIT_ROOT>/`. Applies bounded, idempotent edits under",
4787
- "`<DOCS_ROOT>/` per the fix-policy declared in the fix issue body.",
4788
- "Never writes to source code, never writes to doc trees outside",
4789
- "`<DOCS_ROOT>`, never authors new document files to close a gap.",
4924
+ "`<DOCS_ROOT>/` only in Phase 2 (Fix), per the fix-policy declared",
4925
+ "in the fix issue body. Phase 3 (Verify) never edits doc files \u2014",
4926
+ "it only reads and re-scans. Never writes to source code, never",
4927
+ "writes to doc trees outside `<DOCS_ROOT>`, never authors new",
4928
+ "document files to close a gap.",
4790
4929
  "",
4791
4930
  "---",
4792
4931
  "",
@@ -4798,6 +4937,10 @@ var maintenanceAuditSubAgent = {
4798
4937
  "- All findings are `flag-for-human` and the fix issue has nothing",
4799
4938
  " to auto-apply \u2014 resolve by closing the fix issue with a summary",
4800
4939
  " instead",
4940
+ "- A `maint:verify` issue references a fix report whose",
4941
+ " `Paths Touched` list is empty \u2014 there is nothing to re-scan, so",
4942
+ " close the verify issue with a summary and let a human decide",
4943
+ " whether to re-run the scan",
4801
4944
  "",
4802
4945
  "---",
4803
4946
  "",
@@ -4812,13 +4955,24 @@ var maintenanceAuditSubAgent = {
4812
4955
  " Record out-of-scope observations in the report for human review.",
4813
4956
  "- **No authoring.** Do not invent new document content to close a",
4814
4957
  " finding. That work belongs to the writer agent for the doc type.",
4815
- "- **Verify before closing.** Always re-run the checks after",
4816
- " applying fixes and record the result in the fix report."
4958
+ "- **Verify closes the loop.** Every fix-phase run that lands at",
4959
+ " least one auto-fix must enqueue a `maint:verify` issue. Phase 3",
4960
+ " is the only phase that closes the parent `maint:scan` issue.",
4961
+ " Phase 2 never closes the scan issue itself.",
4962
+ "- **Pre/post comparison is required.** The verify report must",
4963
+ " classify every in-scope finding from the scan report as",
4964
+ " `resolved`, `still-failing`, `regressed`, or `out-of-scope`.",
4965
+ " An unclassified finding means the re-scan was incomplete \u2014 re-",
4966
+ " run the missing checks before writing the verdict.",
4967
+ "- **Residual findings get their own cycle.** When the verify phase",
4968
+ " finds `still-failing` or `regressed` entries, file a follow-up",
4969
+ " `maint:scan` issue rather than attempting to re-fix in-session.",
4970
+ " The new scan starts its own audit cycle with a fresh report."
4817
4971
  ].join("\n")
4818
4972
  };
4819
4973
  var maintenanceAuditSkill = {
4820
4974
  name: "audit-docs",
4821
- description: "Kick off a documentation-maintenance audit cycle (scan \u2192 fix). Creates a maint:scan issue for the supplied scope and dispatches Phase 1.",
4975
+ description: "Kick off a documentation-maintenance audit cycle (scan \u2192 fix \u2192 verify). Creates a maint:scan issue for the supplied scope and dispatches Phase 1.",
4822
4976
  disableModelInvocation: true,
4823
4977
  userInvocable: true,
4824
4978
  context: "fork",
@@ -4830,7 +4984,8 @@ var maintenanceAuditSkill = {
4830
4984
  "Kick off a maintenance-audit cycle against a configurable doc",
4831
4985
  "tree. Creates a `maint:scan` issue targeted at the requested",
4832
4986
  "scope and dispatches Phase 1 (Scan) in the maintenance-audit",
4833
- "agent.",
4987
+ "agent. Subsequent phases (`maint:fix`, `maint:verify`) are",
4988
+ "created automatically as the cycle progresses.",
4834
4989
  "",
4835
4990
  "## Usage",
4836
4991
  "",
@@ -4857,30 +5012,102 @@ var maintenanceAuditSkill = {
4857
5012
  "2. Execute Phase 1 (Scan) of the maintenance-audit agent.",
4858
5013
  "3. If auto-fixable findings exist, a `maint:fix` issue is created",
4859
5014
  " automatically.",
5015
+ "4. When the fix phase lands, a `maint:verify` issue is created",
5016
+ " automatically so Phase 3 can re-run the checks and close the",
5017
+ " parent scan issue.",
4860
5018
  "",
4861
5019
  "## Output",
4862
5020
  "",
4863
5021
  "- A `maint-audit-<slug>-<YYYY-MM-DD>.md` report under",
4864
5022
  " `<AUDIT_ROOT>`.",
4865
- "- A `maint:fix` issue if auto-fixable findings were found."
5023
+ "- A `maint:fix` issue if auto-fixable findings were found.",
5024
+ "- A `maint:verify` issue after the fix phase lands (Phase 3",
5025
+ " produces a `maint-verify-<slug>-<YYYY-MM-DD>.md` report)."
5026
+ ].join("\n")
5027
+ };
5028
+ var maintenanceVerifySkill = {
5029
+ name: "verify-audit",
5030
+ description: "Kick off the verify phase of a documentation-maintenance audit cycle. Creates a maint:verify issue that re-runs the scan checks scoped to the paths a fix phase touched, compares pre/post findings, and closes the parent maint:scan issue when clean or files a follow-up maint:scan for residual findings.",
5031
+ disableModelInvocation: true,
5032
+ userInvocable: true,
5033
+ context: "fork",
5034
+ agent: "maintenance-audit",
5035
+ platforms: { cursor: { exclude: true } },
5036
+ instructions: [
5037
+ "# Verify Audit",
5038
+ "",
5039
+ "Close the loop on a maintenance-audit cycle. Creates a",
5040
+ "`maint:verify` issue and dispatches Phase 3 (Verify) in the",
5041
+ "maintenance-audit agent.",
5042
+ "",
5043
+ "Phase 3 re-runs the same checks the scan phase ran, scoped to the",
5044
+ "paths the fix phase actually touched, compares pre and post",
5045
+ "findings, and writes a verify report. Based on the verdict the",
5046
+ "phase either closes the parent `maint:scan` issue or files a",
5047
+ "follow-up `maint:scan` for residual findings.",
5048
+ "",
5049
+ "## Usage",
5050
+ "",
5051
+ "/verify-audit <scan-issue-number>",
5052
+ "",
5053
+ "Where `<scan-issue-number>` is the `maint:scan` issue that kicked",
5054
+ "off the audit cycle. The skill resolves the scan report, the",
5055
+ "Phase 2 fix report, and the `Paths Touched` list from that scan",
5056
+ "issue's downstream `maint:fix` issue.",
5057
+ "",
5058
+ "Most cycles do not need this skill \u2014 Phase 2 (Fix) creates the",
5059
+ "verify issue automatically. Use this skill when:",
5060
+ "- Phase 2 ran on an older audit cycle that predates the verify",
5061
+ " phase and never enqueued a verify issue, or",
5062
+ "- A human wants to re-run the verify phase after a manual fix",
5063
+ " applied on top of the Phase 2 PR.",
5064
+ "",
5065
+ "## Steps",
5066
+ "",
5067
+ "1. Create a `maint:verify` issue with `type:maintenance`,",
5068
+ " `priority:medium`, and `status:ready`. Body must list:",
5069
+ " - The parent `maint:scan` issue number",
5070
+ " - The Phase 1 audit report path",
5071
+ " - The Phase 2 fix report path (if one exists)",
5072
+ " - The `Paths Touched` list (copied from the fix report)",
5073
+ " - The audit check catalog (copied from the scan issue)",
5074
+ "2. Execute Phase 3 (Verify) of the maintenance-audit agent.",
5075
+ "",
5076
+ "## Output",
5077
+ "",
5078
+ "- A `maint-verify-<slug>-<YYYY-MM-DD>.md` report under",
5079
+ " `<AUDIT_ROOT>` containing the pre/post comparison.",
5080
+ "- The parent `maint:scan` issue is closed (clean verdict) or a",
5081
+ " follow-up `maint:scan` issue is filed (residual verdict)."
4866
5082
  ].join("\n")
4867
5083
  };
4868
5084
  var maintenanceAuditBundle = {
4869
5085
  name: "maintenance-audit",
4870
- description: "Documentation-maintenance agent bundle. 2-phase pipeline (scan, fix) with maint:* phase labels for auditing registries and cross-references and applying idempotent fixes. Enabled by default.",
5086
+ description: "Documentation-maintenance agent bundle. 3-phase pipeline (scan, fix, verify) with maint:* phase labels for auditing registries and cross-references, applying idempotent fixes, and confirming the fixes cleared the originally-flagged findings. Enabled by default.",
4871
5087
  appliesWhen: () => true,
4872
5088
  rules: [
4873
5089
  {
4874
5090
  name: "maintenance-audit-workflow",
4875
- description: "Describes the 2-phase documentation-maintenance pipeline, the maint:* label taxonomy, and the audit-before-fix boundary.",
5091
+ description: "Describes the 3-phase documentation-maintenance pipeline, the maint:* label taxonomy, the audit-before-fix boundary, and the verify-closes-the-loop rule.",
4876
5092
  scope: AGENT_RULE_SCOPE.ALWAYS,
4877
5093
  content: [
4878
5094
  "# Maintenance Audit Workflow",
4879
5095
  "",
4880
5096
  "Use `/audit-docs <scope>` to kick off a documentation-maintenance",
4881
- "audit cycle. The pipeline runs in 2 phases \u2014 scan and fix \u2014 each",
4882
- "tracked by its own GitHub issue labeled `maint:scan` or",
4883
- "`maint:fix`. All issues carry `type:maintenance`.",
5097
+ "audit cycle. The pipeline runs in 3 phases \u2014 scan, fix, and",
5098
+ "verify \u2014 each tracked by its own GitHub issue labeled",
5099
+ "`maint:scan`, `maint:fix`, or `maint:verify`. All issues carry",
5100
+ "`type:maintenance`.",
5101
+ "",
5102
+ "One additional user-invocable skill drives the verify phase",
5103
+ "on demand:",
5104
+ "",
5105
+ "- `/verify-audit <scan-issue-number>` \u2014 re-run the scan checks",
5106
+ " scoped to the paths the fix phase touched, compare pre/post",
5107
+ " findings, and close the parent `maint:scan` issue (or file a",
5108
+ " follow-up for residual findings). Phase 2 (Fix) normally",
5109
+ " enqueues the verify issue automatically \u2014 this skill is the",
5110
+ " explicit entry point for re-running the phase on demand.",
4884
5111
  "",
4885
5112
  "The maintenance-audit agent *audits doc registries and applies",
4886
5113
  "idempotent fixes*; it does **not** author new document content.",
@@ -4896,7 +5123,7 @@ var maintenanceAuditBundle = {
4896
5123
  tags: ["workflow"]
4897
5124
  }
4898
5125
  ],
4899
- skills: [maintenanceAuditSkill],
5126
+ skills: [maintenanceAuditSkill, maintenanceVerifySkill],
4900
5127
  subAgents: [maintenanceAuditSubAgent],
4901
5128
  labels: [
4902
5129
  {
@@ -4913,6 +5140,11 @@ var maintenanceAuditBundle = {
4913
5140
  name: "maint:fix",
4914
5141
  color: "BFDADC",
4915
5142
  description: "Phase 2: apply idempotent fixes from a maintenance audit report"
5143
+ },
5144
+ {
5145
+ name: "maint:verify",
5146
+ color: "D4C5F9",
5147
+ description: "Phase 3: re-run the scan checks scoped to the paths the fix phase touched, compare pre/post findings, and close or re-queue the parent scan"
4916
5148
  }
4917
5149
  ]
4918
5150
  };
@@ -14126,7 +14358,7 @@ var slackBundle = {
14126
14358
  // src/agent/bundles/software-profile.ts
14127
14359
  var softwareProfileAnalystSubAgent = {
14128
14360
  name: "software-profile-analyst",
14129
- description: "Researches a software product (competitor, adjacent, incumbent, enabler, infrastructure, or ecosystem-tool) from public sources, produces a structured markdown profile, and contributes rows to a shared feature matrix ranked against configurable segment-importance weights, then enqueues downstream `company:research` and `people:research` issues for the vendor company and primary-attribution founders/leaders surfaced during profiling. One product per session, tracked by software:* GitHub issue labels.",
14361
+ description: "Researches a software product (competitor, adjacent, incumbent, enabler, infrastructure, or ecosystem-tool) from public sources, produces a structured markdown profile, contributes rows to a shared feature matrix ranked against configurable segment-importance weights, maps features back to the BCM capability model and flags unmapped features, then enqueues downstream `bcm:outline`, `company:research`, and `people:research` issues for new sub-capabilities, the vendor company, and primary-attribution founders/leaders surfaced during profiling. One product per session, tracked by software:* GitHub issue labels.",
14130
14362
  model: AGENT_MODEL.POWERFUL,
14131
14363
  maxTurns: 80,
14132
14364
  platforms: { cursor: { exclude: true } },
@@ -14136,8 +14368,9 @@ var softwareProfileAnalystSubAgent = {
14136
14368
  "You research a single software product from public sources and write",
14137
14369
  "a structured markdown profile. Each profile cycle runs across a small",
14138
14370
  "sequence of GitHub issues \u2014 one per phase \u2014 and produces a single",
14139
- "profile file on disk, a set of feature-matrix rows, and optional",
14140
- "follow-up research issues for adjacent products.",
14371
+ "profile file on disk, a set of feature-matrix rows, a back-mapping",
14372
+ "onto the BCM capability model, and optional follow-up research",
14373
+ "issues for adjacent products.",
14141
14374
  "",
14142
14375
  "This agent is **domain-neutral**. It makes no assumptions about what",
14143
14376
  "the consuming project sells, which industry it serves, or which",
@@ -14182,6 +14415,14 @@ var softwareProfileAnalystSubAgent = {
14182
14415
  " weights belong in `docs/src/content/docs/project-context.md` (or an override",
14183
14416
  " passed in the issue body). This agent reads them; it never",
14184
14417
  " invents them.",
14418
+ "8. **Map back to the capability model.** The BCM capability model is",
14419
+ " the single source of truth for what the business does. Every",
14420
+ " feature on every profile is mapped to the owning capability in the",
14421
+ " BCM tree during the map phase. Features that match nothing in the",
14422
+ " tree are candidates for new BCM sub-capabilities \u2014 they are",
14423
+ " flagged and handed off to the `bcm-writer` bundle via",
14424
+ " `bcm:outline` issues. This agent never authors BCM documents",
14425
+ " itself.",
14185
14426
  "",
14186
14427
  "---",
14187
14428
  "",
@@ -14247,14 +14488,15 @@ var softwareProfileAnalystSubAgent = {
14247
14488
  "## State Machine Overview",
14248
14489
  "",
14249
14490
  "```",
14250
- "\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
14251
- "\u2502 1. RESEARCH \u2502\u2500\u2500\u25B6\u2502 2. PROFILE \u2502\u2500\u2500\u25B6\u2502 3. MATRIX \u2502\u2500\u2500\u25B6\u2502 4. FOLLOWUP \u2502",
14252
- "\u2502 Collect \u2502 \u2502 Write the \u2502 \u2502 Extract \u2502 \u2502 Enqueue \u2502",
14253
- "\u2502 public \u2502 \u2502 structured \u2502 \u2502 feature rows \u2502 \u2502 research for \u2502",
14254
- "\u2502 sources into \u2502 \u2502 markdown \u2502 \u2502 and score \u2502 \u2502 adjacent \u2502",
14255
- "\u2502 bounded \u2502 \u2502 profile to \u2502 \u2502 against the \u2502 \u2502 products \u2502",
14256
- "\u2502 notes file \u2502 \u2502 <PROFILES>/ \u2502 \u2502 weights \u2502 \u2502 surfaced \u2502",
14257
- "\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
14491
+ "\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510",
14492
+ "\u25021.RESEARCH\u2502\u2500\u25B6\u25022.PROFILE \u2502\u2500\u25B6\u25023.MATRIX \u2502\u2500\u25B6\u25024.MAP \u2502\u2500\u25B6\u25025.FOLLOWUP\u2502",
14493
+ "\u2502Collect \u2502 \u2502Write the \u2502 \u2502Extract \u2502 \u2502Map each \u2502 \u2502Enqueue \u2502",
14494
+ "\u2502public \u2502 \u2502structured\u2502 \u2502feature \u2502 \u2502feature to\u2502 \u2502research \u2502",
14495
+ "\u2502sources \u2502 \u2502markdown \u2502 \u2502rows and \u2502 \u2502BCM \u2502 \u2502for \u2502",
14496
+ "\u2502into \u2502 \u2502profile to\u2502 \u2502score \u2502 \u2502capability\u2502 \u2502adjacent \u2502",
14497
+ "\u2502bounded \u2502 \u2502<PROFILES>\u2502 \u2502against \u2502 \u2502and flag \u2502 \u2502products \u2502",
14498
+ "\u2502notes file\u2502 \u2502 \u2502 \u2502weights \u2502 \u2502gaps \u2502 \u2502surfaced \u2502",
14499
+ "\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518",
14258
14500
  "```",
14259
14501
  "",
14260
14502
  "**Issue labels encode the phase:**",
@@ -14263,20 +14505,22 @@ var softwareProfileAnalystSubAgent = {
14263
14505
  "|-------|-------|-------------|",
14264
14506
  "| `software:research` | 1. Research | Gather public sources. Write a bounded research-notes file. Create the profile issue. |",
14265
14507
  "| `software:profile` | 2. Profile | Read the research notes. Write the structured profile to `<PROFILES_DIR>`. Create the matrix issue. |",
14266
- "| `software:matrix` | 3. Matrix | Read the profile. Extract feature rows into `<MATRIX_FILE>`. Score against segment weights. Create the follow-up issue if warranted. |",
14267
- "| `software:followup` | 4. Followup | Read the profile. Enqueue software-research issues for adjacent products surfaced in the profile. |",
14508
+ "| `software:matrix` | 3. Matrix | Read the profile. Extract feature rows into `<MATRIX_FILE>`. Score against segment weights. Create the map issue. |",
14509
+ "| `software:map` | 4. Map | Read the profile and matrix rows. Map each feature to the owning BCM capability. Write the mapping back onto the profile. Enqueue `bcm:outline` follow-ups for unmapped features above the configured threshold. Create the followup issue. |",
14510
+ "| `software:followup` | 5. Followup | Read the profile. Enqueue software-research issues for adjacent products surfaced in the profile. |",
14268
14511
  "",
14269
14512
  "All issues also carry `type:software-profile` and a `status:*` label.",
14270
14513
  "",
14271
14514
  "**Issue count per product cycle:** 1 research + 1 profile + 1 matrix +",
14272
- "0\u20131 followup = **3\u20134 sessions**. The followup phase is skipped when",
14273
- "the profile did not surface any adjacent product worth researching.",
14515
+ "1 map + 0\u20131 followup = **4\u20135 sessions**. The followup phase is",
14516
+ "skipped when the profile did not surface any adjacent product worth",
14517
+ "researching.",
14274
14518
  "",
14275
14519
  "**Shortened paths:**",
14276
14520
  "- Research phase determines the product is out of scope (not",
14277
14521
  " relevant, insufficient public material) \u2192 research issue closes",
14278
14522
  " with a justification and no downstream issues are created \u2192 **1 session**.",
14279
- "- Narrow product with no adjacent candidates \u2192 **3 sessions**.",
14523
+ "- Narrow product with no adjacent candidates \u2192 **4 sessions**.",
14280
14524
  "",
14281
14525
  "---",
14282
14526
  "",
@@ -14295,11 +14539,25 @@ var softwareProfileAnalystSubAgent = {
14295
14539
  "| `<PRODUCT_SLUG>` | Short kebab-case slug identifying the product | derived from the product name |",
14296
14540
  "| `<COMPANY_PROFILES_DIR>` | Where existing company profiles live (for duplicate detection during followup) | `docs/companies/profiles/` |",
14297
14541
  "| `<PEOPLE_PROFILES_DIR>` | Where existing people profiles live (for duplicate detection during followup) | `docs/people/profiles/` |",
14542
+ `| \`<BCM_DOC_ROOT>\` | Root folder for BCM capability-model documents (used by Phase 4 to locate capabilities) | \`${DEFAULT_AGENT_PATHS.bcmRoot}/\` |`,
14543
+ "| `<BCM_CAPABILITY_MAP>` | Capability-map file that lists the L1/L2/L3 hierarchy | `<BCM_DOC_ROOT>/capability-map.md` |",
14544
+ "| `<UNMAPPED_THRESHOLD>` | Minimum number of unmapped features on a single profile that triggers a `bcm:outline` follow-up for that feature cluster | `1` (every unmapped feature triggers a `bcm:outline`) |",
14298
14545
  "",
14299
14546
  "If `docs/src/content/docs/project-context.md` specifies a different software-research",
14300
14547
  "tree (for example by reusing the research-pipeline deliverables",
14301
14548
  "folder), prefer that. Otherwise fall back to the defaults above.",
14302
14549
  "",
14550
+ "The `<BCM_DOC_ROOT>` default above is sourced from configulator's",
14551
+ "`DEFAULT_AGENT_PATHS.bcmRoot`. If the consuming project's capability",
14552
+ "model lives somewhere else, pass an override in the invoking issue",
14553
+ "body or extend this rule in `agentConfig.rules` \u2014 reading",
14554
+ "`agentConfig.paths.bcmRoot` directly is not currently wired through",
14555
+ "to rule content at synth time. Override `<UNMAPPED_THRESHOLD>` the",
14556
+ "same way when the default (one `bcm:outline` per unmapped feature)",
14557
+ "is too noisy \u2014 for example, raise it to `3` to require at least",
14558
+ "three unmapped features on a single profile before any follow-ups",
14559
+ "are filed.",
14560
+ "",
14303
14561
  "---",
14304
14562
  "",
14305
14563
  "## Agent Loop",
@@ -14308,7 +14566,7 @@ var softwareProfileAnalystSubAgent = {
14308
14566
  "",
14309
14567
  "1. Claim one open `type:software-profile` issue using phase priority:",
14310
14568
  " `software:research` > `software:profile` > `software:matrix` >",
14311
- " `software:followup`.",
14569
+ " `software:map` > `software:followup`.",
14312
14570
  "2. Transition `status:ready` \u2192 `status:in-progress` and create the",
14313
14571
  " branch per your project's branch-naming convention.",
14314
14572
  "3. Execute the phase handler that matches the issue's `software:*`",
@@ -14443,7 +14701,12 @@ var softwareProfileAnalystSubAgent = {
14443
14701
  "",
14444
14702
  " ## Features",
14445
14703
  " <grouped bullet list of notable features, each cited. These become",
14446
- " the rows in the feature matrix during Phase 3.>",
14704
+ " the rows in the feature matrix during Phase 3 and the rows of the",
14705
+ " capability mapping during Phase 4.>",
14706
+ "",
14707
+ " ## Capability Mapping",
14708
+ " _To be filled in during Phase 4 (Map). Leave as",
14709
+ " `_Pending capability mapping \u2014 filled in Phase 4._` until then._",
14447
14710
  "",
14448
14711
  " ## Technology Signals",
14449
14712
  " <stack hints from docs, integrations, and public engineering",
@@ -14549,18 +14812,141 @@ var softwareProfileAnalystSubAgent = {
14549
14812
  "",
14550
14813
  "5. **Update the matrix front-matter** (`updated: YYYY-MM-DD`).",
14551
14814
  "",
14552
- "6. **Decide whether a follow-up issue is warranted.** Create a",
14553
- " `software:followup` issue (depending on this matrix issue) only",
14554
- " if the profile lists at least one adjacent product candidate.",
14555
- " Otherwise, note in the matrix issue's closing comment that no",
14556
- " follow-up is needed.",
14815
+ "6. **Create the `software:map` issue** with",
14816
+ " `Depends on: #<matrix-issue>`. Its body references the profile",
14817
+ " path, the matrix file path, the BCM document root",
14818
+ " (`<BCM_DOC_ROOT>`), the capability map file",
14819
+ " (`<BCM_CAPABILITY_MAP>` if it exists), and the unmapped-feature",
14820
+ " threshold (`<UNMAPPED_THRESHOLD>`). The map phase always runs \u2014",
14821
+ " every profile is mapped back to the capability model regardless",
14822
+ " of whether any adjacent products were surfaced.",
14557
14823
  "",
14558
14824
  "7. **Commit and push** the matrix file (and any profile updates).",
14559
14825
  " Close the matrix issue.",
14560
14826
  "",
14561
14827
  "---",
14562
14828
  "",
14563
- "## Phase 4: Followup (`software:followup`)",
14829
+ "## Phase 4: Map (`software:map`)",
14830
+ "",
14831
+ "**Goal:** Map each feature on the profile back to the owning",
14832
+ "capability in the BCM capability model, write the mapping onto the",
14833
+ "profile, and enqueue `bcm:outline` follow-ups for features that do",
14834
+ "not match any existing capability.",
14835
+ "",
14836
+ "**Budget:** No new web searches. Read the profile, matrix, and BCM",
14837
+ "tree; write the mapping section onto the profile; open",
14838
+ "`bcm:outline` issues for the gaps.",
14839
+ "",
14840
+ "### Capability Mapping Format",
14841
+ "",
14842
+ "The mapping lives in the `## Capability Mapping` section of the",
14843
+ "profile file. It is a table with one row per feature and explicit",
14844
+ "evidence for each mapping decision:",
14845
+ "",
14846
+ "```markdown",
14847
+ "## Capability Mapping",
14848
+ "",
14849
+ "_Mapped against `<BCM_CAPABILITY_MAP>` on YYYY-MM-DD._",
14850
+ "",
14851
+ "| feature | capability (id \xB7 name) | tier | confidence | notes |",
14852
+ "|---------|-----------------------|------|------------|-------|",
14853
+ "| <feature> | <bcm-id> \xB7 <capability name> | L1/L2/L3 | high/medium/low | <evidence or rationale> |",
14854
+ "| <feature> | _unmapped_ | \u2014 | \u2014 | Candidate for new BCM sub-capability. Tracked in #<bcm-outline-issue> |",
14855
+ "```",
14856
+ "",
14857
+ "Confidence levels:",
14858
+ "",
14859
+ "- **high** \u2014 the feature's jobs-to-be-done clearly match the",
14860
+ " capability's definition and business object.",
14861
+ "- **medium** \u2014 the feature plausibly maps to the capability, but the",
14862
+ " match is partial (e.g. the feature covers only one facet of the",
14863
+ " capability, or the capability's definition is broader than the",
14864
+ " feature).",
14865
+ "- **low** \u2014 the feature overlaps the capability only tangentially.",
14866
+ " Prefer `_unmapped_` over a low-confidence match when the feature",
14867
+ " is a genuine capability gap rather than a near-miss.",
14868
+ "",
14869
+ "### Steps",
14870
+ "",
14871
+ "1. **Load the BCM tree.** Read `<BCM_CAPABILITY_MAP>` if it exists,",
14872
+ " otherwise walk `<BCM_DOC_ROOT>/` for capability-model documents.",
14873
+ " Build an in-session index of `{ id, name, tier, business_object }`",
14874
+ " entries. If the tree is empty (no BCM documents yet), note the",
14875
+ " gap in the profile's `## Risks / Open Questions`, skip the",
14876
+ " per-feature mapping, and mark **every** feature as a candidate",
14877
+ " for a new sub-capability \u2014 subject to `<UNMAPPED_THRESHOLD>`.",
14878
+ "",
14879
+ "2. **Read the profile file** and extract the `## Features` bullets.",
14880
+ " Each bullet is one row in the mapping table.",
14881
+ "",
14882
+ "3. **Map each feature to the best-fit capability.** Preferred",
14883
+ " algorithm:",
14884
+ " - Match against the capability's **business object** first (the",
14885
+ " thing the capability acts on).",
14886
+ " - Then match against the capability's **definition** and",
14887
+ " jobs-to-be-done.",
14888
+ " - Tie-break in favor of the most specific (deepest tier)",
14889
+ " capability \u2014 an L3 match beats an L2 match that covers it.",
14890
+ "",
14891
+ "4. **Record low-confidence mappings explicitly** \u2014 never hide a weak",
14892
+ " match behind a high-confidence label. If the best available",
14893
+ " match is low-confidence, mark the feature `_unmapped_` instead",
14894
+ " and describe the near-miss in the `notes` column.",
14895
+ "",
14896
+ "5. **Count unmapped features.** If the count meets or exceeds",
14897
+ " `<UNMAPPED_THRESHOLD>` (default `1`), open one `bcm:outline`",
14898
+ " issue per unmapped feature. The issue must carry:",
14899
+ "",
14900
+ " - `type:bcm-document`",
14901
+ " - `bcm:outline`",
14902
+ " - `priority:medium`",
14903
+ " - `status:ready`",
14904
+ "",
14905
+ " The issue body must include:",
14906
+ " - A **discovery source** line naming this software profile",
14907
+ " (`Discovered while mapping: <product name>`)",
14908
+ " - A link to the software profile path",
14909
+ " (`Software profile: <PROFILES_DIR>/<PRODUCT_SLUG>.md`)",
14910
+ " - The feature name, its one-line description from the profile,",
14911
+ " and a candidate capability name framed as a noun (BIZBOK-aligned)",
14912
+ " - Enough identifying metadata that the `bcm-writer` agent can",
14913
+ " begin the outline phase without revisiting this software",
14914
+ " profile",
14915
+ "",
14916
+ "6. **Avoid duplicate `bcm:outline` issues.** Before opening one,",
14917
+ " scan `<BCM_DOC_ROOT>/` for an existing capability that covers",
14918
+ " the feature (in case the tree grew between the matrix and map",
14919
+ " phases) and scan open issues carrying `bcm:outline` so this",
14920
+ " phase never re-queues a capability that is already being",
14921
+ " outlined. If a match is found, reuse it as a cross-reference in",
14922
+ " the mapping table instead of opening a new issue.",
14923
+ "",
14924
+ "7. **Write the `## Capability Mapping` section** back onto the",
14925
+ " profile file, replacing the `_Pending capability mapping \u2014 filled",
14926
+ " in Phase 4._` placeholder. Preserve every other section of the",
14927
+ " profile verbatim \u2014 this phase only rewrites the mapping section.",
14928
+ "",
14929
+ "8. **Create the `software:followup` issue** with",
14930
+ " `Depends on: #<map-issue>`. Its body references the profile path",
14931
+ " and lists any adjacent products the profile's Follow-up",
14932
+ " Candidates section identified. Skip creating the followup issue",
14933
+ " only when the profile lists zero adjacent products, zero",
14934
+ " primary-attribution people, and the vendor already has a",
14935
+ " company profile \u2014 note the skip in the map issue's closing",
14936
+ " comment.",
14937
+ "",
14938
+ "9. **Assume the peer is present.** This phase assumes the",
14939
+ " `bcm-writer` bundle is enabled in the consuming project. If the",
14940
+ " bundle has been disabled, flag the map issue with",
14941
+ " `status:needs-attention` and list the unmapped features that",
14942
+ " could not be routed \u2014 never invent an alternative label",
14943
+ " taxonomy.",
14944
+ "",
14945
+ "10. **Commit and push** the updated profile. Close the map issue.",
14946
+ "",
14947
+ "---",
14948
+ "",
14949
+ "## Phase 5: Followup (`software:followup`)",
14564
14950
  "",
14565
14951
  "**Goal:** Create downstream research issues for the adjacent products,",
14566
14952
  "vendor company, and primary-attribution people surfaced in the",
@@ -14680,10 +15066,15 @@ var softwareProfileAnalystSubAgent = {
14680
15066
  "",
14681
15067
  "- `<NOTES_DIR>/` \u2014 research-notes files (Phase 1)",
14682
15068
  "- `<PROFILES_DIR>/` \u2014 software profiles (Phase 2, updated in later",
14683
- " phases)",
15069
+ " phases including the `## Capability Mapping` section in Phase 4)",
14684
15070
  "- `<MATRIX_FILE>` \u2014 shared feature matrix (Phase 3)",
14685
15071
  "",
14686
- "In Phase 4, this agent also **creates `company:research` and",
15072
+ "In Phase 4, this agent **creates `bcm:outline` issues** for every",
15073
+ "unmapped feature that meets the `<UNMAPPED_THRESHOLD>` so the",
15074
+ "`bcm-writer` bundle can author the new sub-capability. It never",
15075
+ "authors BCM capability-model documents itself.",
15076
+ "",
15077
+ "In Phase 5, this agent also **creates `company:research` and",
14687
15078
  "`people:research` issues** for the vendor company and primary-",
14688
15079
  "attribution people surfaced in the profile that are not already",
14689
15080
  "tracked under `<COMPANY_PROFILES_DIR>/` or `<PEOPLE_PROFILES_DIR>/`.",
@@ -14692,15 +15083,18 @@ var softwareProfileAnalystSubAgent = {
14692
15083
  "`people-profile-analyst` agents, which pick up the issues this",
14693
15084
  "pipeline creates.",
14694
15085
  "",
14695
- "The pipeline produces **software profiles, notes, and matrix rows",
14696
- "only**. Deeper research on adjacent products is delegated to new",
14697
- "cycles of this same pipeline via `software:research` issues. Deeper",
14698
- "research on the vendor company and primary-attribution people is",
14699
- "delegated to the `company-profile` and `people-profile` bundles via",
15086
+ "The pipeline produces **software profiles, notes, matrix rows, and capability mappings**.",
15087
+ "Deeper research on adjacent products is delegated to new cycles of",
15088
+ "this same pipeline via `software:research` issues. New BCM",
15089
+ "sub-capabilities for unmapped features are delegated to the",
15090
+ "`bcm-writer` bundle via `bcm:outline` issues. Deeper research on",
15091
+ "the vendor company and primary-attribution people is delegated to",
15092
+ "the `company-profile` and `people-profile` bundles via",
14700
15093
  "`company:research` and `people:research` issues. This agent never",
14701
- "writes company profiles, person profiles, formal requirement",
14702
- "documents, or comparative long-form analyses itself. Keep this",
14703
- "boundary clean so the software-profile pipeline stays generic.",
15094
+ "writes BCM documents, company profiles, person profiles, formal",
15095
+ "requirement documents, or comparative long-form analyses itself.",
15096
+ "Keep this boundary clean so the software-profile pipeline stays",
15097
+ "generic.",
14704
15098
  "",
14705
15099
  "---",
14706
15100
  "",
@@ -14715,31 +15109,41 @@ var softwareProfileAnalystSubAgent = {
14715
15109
  " `docs/src/content/docs/project-context.md` or an explicit issue-body override. If",
14716
15110
  " neither is available, fall back to the single-segment default and",
14717
15111
  " flag the gap \u2014 never guess.",
14718
- "- **Delegate, don't duplicate.** The vendor company and primary-",
14719
- " attribution people surfaced during profiling are handed off to the",
14720
- " `company-profile` and `people-profile` bundles via",
14721
- " `company:research` and `people:research` issues in Phase 4 \u2014 never",
14722
- " inlined as company or person profiles in this pipeline.",
14723
- "- **Check before enqueueing.** Before opening a `company:research`",
14724
- " or `people:research` issue, verify no existing profile or open",
14725
- " research issue already covers the candidate. Reuse existing",
14726
- " profiles as cross-references rather than re-queuing research.",
15112
+ "- **Delegate, don't duplicate.** Unmapped capabilities are handed off",
15113
+ " to the `bcm-writer` bundle via `bcm:outline` issues in Phase 4.",
15114
+ " The vendor company and primary-attribution people surfaced during",
15115
+ " profiling are handed off to the `company-profile` and",
15116
+ " `people-profile` bundles via `company:research` and",
15117
+ " `people:research` issues in Phase 5 \u2014 never inlined as BCM",
15118
+ " documents, company profiles, or person profiles in this pipeline.",
15119
+ "- **Check before enqueueing.** Before opening a `bcm:outline`,",
15120
+ " `company:research`, or `people:research` issue, verify no existing",
15121
+ " document or open issue already covers the candidate. Reuse",
15122
+ " existing BCM documents and profiles as cross-references rather",
15123
+ " than re-queuing work.",
15124
+ "- **Respect the threshold.** Phase 4 opens `bcm:outline` issues only",
15125
+ " when the count of unmapped features on a single profile meets or",
15126
+ " exceeds `<UNMAPPED_THRESHOLD>`. The default is `1` \u2014 one unmapped",
15127
+ " feature triggers one outline issue. Raise the threshold in the",
15128
+ " invoking issue body or in the consuming project's",
15129
+ " `agentConfig.rules` when the default is too noisy.",
14727
15130
  "- **Restrain the queue \u2014 people only.** The vendor company always",
14728
15131
  " qualifies (duplicate check aside). For people, only enqueue",
14729
15132
  " research for those with **primary attribution** \u2014 founders, the",
14730
15133
  " current CEO, principal creators, lead maintainers, or the head of",
14731
15134
  " product. Do not open issues for every name on the vendor's about",
14732
15135
  " page, every investor, or every advisor.",
14733
- "- **Produce profiles and matrix rows, not requirement or evaluation",
14734
- " documents.** Do not open `type:requirement` or formal evaluation",
14735
- " issues from this pipeline. Follow-up research is scoped through",
14736
- " `software:research`, `company:research`, and `people:research`",
14737
- " only."
15136
+ "- **Produce profiles, matrix rows, and capability mappings \u2014 not",
15137
+ " BCM documents, requirement documents, or evaluation documents.**",
15138
+ " Do not open `type:requirement` or formal evaluation issues from",
15139
+ " this pipeline, and never author BCM capability-model documents",
15140
+ " inline. Follow-up work is scoped through `software:research`,",
15141
+ " `bcm:outline`, `company:research`, and `people:research` only."
14738
15142
  ].join("\n")
14739
15143
  };
14740
15144
  var profileSoftwareSkill = {
14741
15145
  name: "profile-software",
14742
- description: "Kick off a software-profile pipeline. Creates a software:research issue for the given product and dispatches Phase 1 (Research) in the software-profile-analyst agent. Phase 4 (Followup) enqueues downstream `company:research` and `people:research` issues for the vendor company and primary-attribution founders/leaders surfaced in the profile.",
15146
+ description: "Kick off a software-profile pipeline. Creates a software:research issue for the given product and dispatches Phase 1 (Research) in the software-profile-analyst agent. Phase 4 (Map) writes a BCM capability mapping onto the profile and enqueues `bcm:outline` issues for unmapped features. Phase 5 (Followup) enqueues downstream `company:research` and `people:research` issues for the vendor company and primary-attribution founders/leaders surfaced in the profile.",
14743
15147
  disableModelInvocation: true,
14744
15148
  userInvocable: true,
14745
15149
  context: "fork",
@@ -14766,6 +15170,9 @@ var profileSoftwareSkill = {
14766
15170
  "- `weights: <table>` \u2014 override the segment-importance weights for",
14767
15171
  " this profile cycle (otherwise loaded from",
14768
15172
  " `docs/src/content/docs/project-context.md`)",
15173
+ "- `unmapped_threshold: <n>` \u2014 override the Phase 4 threshold for",
15174
+ " opening `bcm:outline` issues (default `1` \u2014 one unmapped feature",
15175
+ " triggers one outline issue)",
14769
15176
  "- `sources: <list>` \u2014 additional authorized sources beyond public web",
14770
15177
  "",
14771
15178
  "## Default Paths",
@@ -14785,16 +15192,20 @@ var profileSoftwareSkill = {
14785
15192
  "2. Execute Phase 1 (Research) of the software-profile-analyst",
14786
15193
  " agent.",
14787
15194
  "3. Phase 1 creates the `software:profile` issue. Phase 2 creates",
14788
- " the `software:matrix` issue. Phase 3 may create a",
14789
- " `software:followup` issue. Each downstream issue declares its",
14790
- " `Depends on:` predecessor.",
15195
+ " the `software:matrix` issue. Phase 3 creates the `software:map`",
15196
+ " issue. Phase 4 creates the `software:followup` issue (unless the",
15197
+ " profile surfaced zero follow-ups). Each downstream issue",
15198
+ " declares its `Depends on:` predecessor.",
14791
15199
  "",
14792
15200
  "## Output",
14793
15201
  "",
14794
15202
  "- A research-notes file under the project's notes directory",
14795
- "- A single software profile under the profiles directory",
15203
+ "- A single software profile under the profiles directory, including",
15204
+ " a `## Capability Mapping` section written in Phase 4",
14796
15205
  "- One or more rows appended to the shared feature-matrix file,",
14797
15206
  " scored against the configured segment weights",
15207
+ "- `bcm:outline` issues for each unmapped feature above the",
15208
+ " configured threshold (handed off to the `bcm-writer` bundle)",
14798
15209
  "- Optional follow-up `software:research` issues for adjacent",
14799
15210
  " products surfaced in the profile",
14800
15211
  "- `company:research` issue for the vendor company (handed off to",
@@ -14802,46 +15213,132 @@ var profileSoftwareSkill = {
14802
15213
  "- `people:research` issues for primary-attribution founders, CEOs,",
14803
15214
  " or principal creators (handed off to the `people-profile`",
14804
15215
  " bundle)",
14805
- "- This pipeline produces **software profiles, notes, and matrix",
14806
- " rows only** \u2014 it does not write company profiles, person",
14807
- " profiles, or formal requirement documents itself."
15216
+ "- This pipeline produces **software profiles, notes, matrix rows,",
15217
+ " and capability mappings** \u2014 it does not write BCM documents,",
15218
+ " company profiles, person profiles, or formal requirement",
15219
+ " documents itself."
15220
+ ].join("\n")
15221
+ };
15222
+ var mapSoftwareSkill = {
15223
+ name: "map-software",
15224
+ description: "Kick off a standalone software-capability mapping session. Creates a software:map issue for an already-profiled product and dispatches Phase 4 (Map) in the software-profile-analyst agent. Produces the `## Capability Mapping` section on the profile and enqueues `bcm:outline` issues for unmapped features above the configured threshold.",
15225
+ disableModelInvocation: true,
15226
+ userInvocable: true,
15227
+ context: "fork",
15228
+ agent: "software-profile-analyst",
15229
+ platforms: { cursor: { exclude: true } },
15230
+ instructions: [
15231
+ "# Map Software",
15232
+ "",
15233
+ "Kick off a standalone `software:map` session for a product that",
15234
+ "already has a profile file and matrix rows on disk. Creates a",
15235
+ "`software:map` issue carrying the profile path and dispatches Phase",
15236
+ "4 (Map) in the software-profile-analyst agent.",
15237
+ "",
15238
+ "Use this skill when:",
15239
+ "",
15240
+ "- A profile was written before the map phase existed and is still",
15241
+ " carrying the `_Pending capability mapping \u2014 filled in Phase 4._`",
15242
+ " placeholder.",
15243
+ "- The BCM tree has grown enough that a previously-mapped profile",
15244
+ " should be re-mapped against the updated capability model.",
15245
+ "- A profile's features were edited after the map phase ran and the",
15246
+ " mapping table is now out of date.",
15247
+ "",
15248
+ "## Usage",
15249
+ "",
15250
+ "/map-software <product-slug-or-profile-path>",
15251
+ "",
15252
+ "Optional extensions in the issue body:",
15253
+ "- `unmapped_threshold: <n>` \u2014 override the threshold for opening",
15254
+ " `bcm:outline` issues (default `1`)",
15255
+ "- `bcm_doc_root: <path>` \u2014 override the BCM document root",
15256
+ " (otherwise the configulator default at",
15257
+ " `DEFAULT_AGENT_PATHS.bcmRoot`)",
15258
+ "- `capability_map: <path>` \u2014 override the capability-map file",
15259
+ " (otherwise `<BCM_DOC_ROOT>/capability-map.md`)",
15260
+ "",
15261
+ "## Default Paths",
15262
+ "",
15263
+ "If the project has no override in `docs/src/content/docs/project-context.md` or",
15264
+ "`agentConfig.rules`, the mapping reads from:",
15265
+ "",
15266
+ `- \`${DEFAULT_AGENT_PATHS.bcmRoot}/\` \u2014 BCM capability-model documents`,
15267
+ `- \`${DEFAULT_AGENT_PATHS.bcmRoot}/capability-map.md\` \u2014 capability map`,
15268
+ "",
15269
+ "and writes back to `docs/software/profiles/<slug>.md` under the",
15270
+ "`## Capability Mapping` section only. No other section of the",
15271
+ "profile is rewritten.",
15272
+ "",
15273
+ "## Steps",
15274
+ "",
15275
+ "1. Create a `software:map` issue with `type:software-profile`,",
15276
+ " `priority:medium`, and `status:ready`. Body must include the",
15277
+ " profile path and any overrides.",
15278
+ "2. Execute Phase 4 (Map) of the software-profile-analyst agent.",
15279
+ "3. Phase 4 writes the `## Capability Mapping` section, enqueues",
15280
+ " `bcm:outline` issues for unmapped features above the threshold,",
15281
+ " and \u2014 when the profile lists adjacent products or",
15282
+ " primary-attribution people \u2014 creates the `software:followup`",
15283
+ " issue.",
15284
+ "",
15285
+ "## Output",
15286
+ "",
15287
+ "- An updated `## Capability Mapping` section on the target profile",
15288
+ "- `bcm:outline` issues for each unmapped feature above the",
15289
+ " configured threshold (handed off to the `bcm-writer` bundle)",
15290
+ "- An optional `software:followup` issue when the profile surfaced",
15291
+ " adjacent products, a vendor company without an existing profile,",
15292
+ " or primary-attribution people",
15293
+ "- This skill does not run Phase 1\u20133 \u2014 it assumes the profile and",
15294
+ " matrix rows already exist on disk."
14808
15295
  ].join("\n")
14809
15296
  };
14810
15297
  var softwareProfileBundle = {
14811
15298
  name: "software-profile",
14812
- description: "Software research, profiling, and feature-matrix pipeline: research, profile, matrix, followup. Enabled by default; domain-neutral; filesystem-durable between phases; ranks features against configurable segment-importance weights. Phase 4 (Followup) hands the vendor company and primary-attribution founders/leaders off to the `company-profile` and `people-profile` bundles via `company:research` and `people:research` issues.",
15299
+ description: "Software research, profiling, feature-matrix, and capability-mapping pipeline: research, profile, matrix, map, followup. Enabled by default; domain-neutral; filesystem-durable between phases; ranks features against configurable segment-importance weights and maps features back to the BCM capability model. Phase 4 (Map) hands unmapped features off to the `bcm-writer` bundle via `bcm:outline` issues. Phase 5 (Followup) hands the vendor company and primary-attribution founders/leaders off to the `company-profile` and `people-profile` bundles via `company:research` and `people:research` issues.",
14813
15300
  appliesWhen: () => true,
14814
15301
  rules: [
14815
15302
  {
14816
15303
  name: "software-profile-workflow",
14817
- description: "Describes the 4-phase software-profile pipeline, the software:* label taxonomy, the generic software-type taxonomy, and the segment-weights convention that drives feature-matrix scoring.",
15304
+ description: "Describes the 5-phase software-profile pipeline, the software:* label taxonomy, the generic software-type taxonomy, the segment-weights convention that drives feature-matrix scoring, and the capability-mapping hand-off to the bcm-writer bundle.",
14818
15305
  scope: AGENT_RULE_SCOPE.ALWAYS,
14819
15306
  content: [
14820
15307
  "# Software Profile Workflow",
14821
15308
  "",
14822
15309
  "Use `/profile-software <product-name>` to kick off a software",
14823
- "research, profiling, and feature-matrix pipeline. The pipeline",
14824
- "runs in up to 4 phases \u2014 research, profile, matrix, followup \u2014",
14825
- "each tracked by its own GitHub issue labeled",
14826
- "`software:research`, `software:profile`, `software:matrix`, or",
14827
- "`software:followup`. All issues carry `type:software-profile`.",
14828
- "",
14829
- "The pipeline produces **software profiles, research notes, and",
14830
- "rows in a shared feature matrix**. Features are ranked against",
14831
- "segment-importance weights declared in",
14832
- "`docs/src/content/docs/project-context.md` under a `## Segment Weights` section.",
14833
- "Deeper research on adjacent products surfaced in a profile is",
14834
- "delegated to new cycles of this same pipeline via",
14835
- "`software:followup` issues. Deeper research on the vendor",
14836
- "company and primary-attribution founders/product leaders is",
14837
- "delegated to the `company-profile` and `people-profile`",
14838
- "bundles via `company:research` and `people:research` issues",
14839
- "opened during Phase 4 (Followup).",
15310
+ "research, profiling, feature-matrix, and capability-mapping",
15311
+ "pipeline. The pipeline runs in up to 5 phases \u2014 research,",
15312
+ "profile, matrix, map, followup \u2014 each tracked by its own GitHub",
15313
+ "issue labeled `software:research`, `software:profile`,",
15314
+ "`software:matrix`, `software:map`, or `software:followup`. All",
15315
+ "issues carry `type:software-profile`.",
15316
+ "",
15317
+ "The pipeline produces **software profiles, research notes, rows",
15318
+ "in a shared feature matrix, and capability mappings onto the",
15319
+ "BCM tree**. Features are ranked against segment-importance",
15320
+ "weights declared in `docs/src/content/docs/project-context.md`",
15321
+ "under a `## Segment Weights` section. Features that do not map",
15322
+ "to any existing capability in the BCM tree are flagged during",
15323
+ "the map phase as candidates for new BCM sub-capabilities and",
15324
+ "handed off to the `bcm-writer` bundle via `bcm:outline` issues",
15325
+ "(subject to a configurable threshold). Deeper research on",
15326
+ "adjacent products surfaced in a profile is delegated to new",
15327
+ "cycles of this same pipeline via `software:followup` issues.",
15328
+ "Deeper research on the vendor company and primary-attribution",
15329
+ "founders/product leaders is delegated to the `company-profile`",
15330
+ "and `people-profile` bundles via `company:research` and",
15331
+ "`people:research` issues opened during Phase 5 (Followup).",
15332
+ "",
15333
+ "Use `/map-software <product-slug>` to kick off a standalone",
15334
+ "`software:map` session for a profile that already exists on",
15335
+ "disk \u2014 for example, when the BCM tree has grown enough that a",
15336
+ "previously-mapped profile should be re-mapped.",
14840
15337
  "",
14841
15338
  "See the `software-profile-analyst` agent definition for full",
14842
15339
  "workflow details, default paths, the software-type taxonomy,",
14843
- "the segment-weights convention, and phase-by-phase",
14844
- "instructions."
15340
+ "the segment-weights convention, the capability-mapping format,",
15341
+ "and phase-by-phase instructions."
14845
15342
  ].join("\n"),
14846
15343
  platforms: {
14847
15344
  cursor: { exclude: true }
@@ -14849,13 +15346,13 @@ var softwareProfileBundle = {
14849
15346
  tags: ["workflow"]
14850
15347
  }
14851
15348
  ],
14852
- skills: [profileSoftwareSkill],
15349
+ skills: [profileSoftwareSkill, mapSoftwareSkill],
14853
15350
  subAgents: [softwareProfileAnalystSubAgent],
14854
15351
  labels: [
14855
15352
  {
14856
15353
  name: "type:software-profile",
14857
15354
  color: "0E8A16",
14858
- description: "Work that produces or maintains a software profile, research notes, or feature-matrix rows"
15355
+ description: "Work that produces or maintains a software profile, research notes, feature-matrix rows, or capability mappings"
14859
15356
  },
14860
15357
  {
14861
15358
  name: "software:research",
@@ -14872,10 +15369,15 @@ var softwareProfileBundle = {
14872
15369
  color: "D4C5F9",
14873
15370
  description: "Phase 3: extract feature rows into the shared feature matrix and score them against segment weights"
14874
15371
  },
15372
+ {
15373
+ name: "software:map",
15374
+ color: "A2EEEF",
15375
+ description: "Phase 4: map each feature back to the BCM capability model, write the mapping onto the profile, and enqueue `bcm:outline` issues for unmapped features above the configured threshold"
15376
+ },
14875
15377
  {
14876
15378
  name: "software:followup",
14877
15379
  color: "FBCA04",
14878
- description: "Phase 4: enqueue follow-up research issues for adjacent products, the vendor company, and primary-attribution people surfaced in the profile"
15380
+ description: "Phase 5: enqueue follow-up research issues for adjacent products, the vendor company, and primary-attribution people surfaced in the profile"
14879
15381
  }
14880
15382
  ]
14881
15383
  };