{"version":3,"sources":["../../utils/src/aws/aws-types.ts","../../utils/src/git/git-utils.ts","../../utils/src/string/string-utils.ts","../../utils/src/index.ts","../src/agent/agent-config.ts","../src/agent/types.ts","../src/agent/bundles/claim-verification.ts","../src/agent/bundles/bundle-ownership.ts","../src/agent/bundles/issue-type.ts","../src/agent/bundles/origin-label.ts","../src/agent/bundles/project-context.ts","../src/agent/bundles/agenda.ts","../src/agent/bundles/utils.ts","../src/agent/bundles/aws-cdk.ts","../src/agent/bundles/issue-defaults.ts","../src/agent/bundles/issue-templates.ts","../src/agent/bundles/paths.ts","../src/agent/bundles/progress-files.ts","../src/agent/bundles/shared-editing.ts","../src/agent/bundles/skill-evals.ts","../src/agent/bundles/temporal-framing.ts","../src/agent/bundles/base.ts","../src/agent/bundles/issue-close.ts","../src/agent/bundles/bcm-writer.ts","../src/turbo/turbo-repo.ts","../src/turbo/turbo-repo-task.ts","../src/git/git-branch-env.ts","../src/agent/bundles/build-policy.ts","../src/agent/bundles/business-models.ts","../src/agent/bundles/company-profile.ts","../src/agent/bundles/customer-profile.ts","../src/agent/bundles/docs-sync.ts","../src/agent/bundles/github-workflow.ts","../src/agent/bundles/closing-keywords.ts","../src/agent/bundles/industry-discovery.ts","../src/agent/bundles/jest.ts","../src/agent/bundles/maintenance-audit.ts","../src/agent/bundles/meeting-analysis.ts","../src/agent/bundles/run-ratio.ts","../src/agent/bundles/scheduled-tasks.ts","../src/agent/bundles/scope-gate.ts","../src/agent/bundles/tiers.ts","../src/agent/bundles/unblock-dependents.ts","../src/agent/bundles/orchestrator.ts","../src/agent/bundles/people-profile.ts","../src/pnpm/pnpm-workspace.ts","../src/agent/bundles/pnpm.ts","../src/agent/bundles/pr-babysitting.ts","../src/agent/bundles/pr-review-policy.ts","../src/agent/bundles/pr-review.ts","../src/agent/bundles/projen.ts","../src/agent/bundles/regulatory-research.ts","../src/agent/bundles/requirements-taxonomy.ts","../src/agent/bundles/requirements-writer.ts","../src/agent/bundles/requirements-analyst.ts","../src/agent/bundles/requirements-reviewer.ts","../src/agent/bundles/research-pipeline.ts","../src/projects/project-metadata.ts","../src/agent/bundles/slack.ts","../src/agent/bundles/software-profile.ts","../src/agent/bundles/standards-research.ts","../src/agent/bundles/turborepo.ts","../src/agent/bundles/typescript.ts","../src/agent/bundles/upstream-configulator-docs.ts","../src/vitest/vitest-component.ts","../src/versions.ts","../src/agent/bundles/vitest.ts","../src/agent/bundles/agent-registry.ts","../src/agent/bundles/features.ts","../src/agent/bundles/focus.ts","../src/agent/bundles/meeting-types.ts","../src/agent/bundles/priority-rules.ts","../src/agent/bundles/index.ts","../src/agent/bundles/scope.ts","../src/agent/renderers/claude-renderer.ts","../src/agent/renderers/cursor-renderer.ts","../src/agent/template-resolver.ts","../src/agent/renderers/codex-renderer.ts","../src/agent/renderers/copilot-renderer.ts","../src/api-extractor/api-extractor-component.ts","../src/astro/astro-config.ts","../src/astro/astro-config-options.ts","../src/aws/aws-deployment-config.ts","../src/aws/cdk-cli.ts","../src/aws/cdk-cli-defaults.ts","../src/aws/cdk-cli-merge.ts","../src/aws/cdk-cli-renderer.ts","../src/turbo/turbo-run-enums.ts","../src/aws/aws-deployment-target.ts","../src/aws/cdk-cli-enums.ts","../src/docs-sync/reference-extraction/extraction.ts","../src/docs-sync/sample-compilation/compilation.ts","../src/docs-sync/sample-compilation/extraction.ts","../src/docs-sync/scan/audit-report.ts","../src/docs-sync/scan/checks/api-diff-check.ts","../src/docs-sync/scan/checks/reference-mismatch-check.ts","../src/docs-sync/scan/checks/tsdoc-coverage-check.ts","../src/docs-sync/scan/run-scan.ts","../src/docs-sync/tsdoc-coverage/coverage.ts","../src/latest-eligible-version.ts","../src/version-package-map.ts","../src/jsii/jsii-faker.ts","../src/projects/add-playwright.ts","../src/projects/add-storybook.ts","../src/projects/astro-project.ts","../src/projects/monorepo-layout.ts","../src/projects/resolve-outdir.ts","../src/projects/typescript-project.ts","../src/projects/changelog-types.ts","../src/projects/monorepo-project.ts","../src/projects/nvmrc.ts","../src/projects/package-private.ts","../src/tasks/reset-task.ts","../src/vscode/vscode.ts","../src/workflows/approve-merge-upgrade.ts","../src/workflows/build-complete-job.ts","../src/workflows/include-hidden-files-in-build-artifact.ts","../src/workflows/pin-pnpm-action-setup.ts","../src/workflows/pin-setup-node-version.ts","../src/workflows/requirement-issue-template.ts","../src/workflows/sync-labels.ts","../src/typescript/tsdoc-config.ts","../src/typescript/typescript-config.ts","../src/projects/aws-cdk-project.ts","../src/workflows/aws-deploy-workflow.ts","../src/workflows/apply-workflow.ts","../src/workflows/plan-apply.ts","../src/workflows/deploy-gate.ts","../src/workflows/diff-report-job.ts","../src/workflows/home-repository.ts","../src/workflows/node-setup.ts","../src/workflows/aws-teardown-workflow.ts","../src/projects/react-vite-site-project.ts","../src/projects/starlight-project.ts"],"sourcesContent":["/**\n * Stage Types\n *\n * What stage of deployment is this? Dev, staging, or prod?\n */\nexport const AWS_STAGE_TYPE = {\n  /**\n   * Development environment, typically used for testing and development.\n   */\n  DEV: \"dev\",\n\n  /**\n   * Staging environment, used for pre-production testing.\n   */\n  STAGE: \"stage\",\n\n  /**\n   * Production environment, used for live deployments.\n   */\n  PROD: \"prod\",\n} as const;\n\n/**\n * Above const as a type.\n */\nexport type AwsStageType = (typeof AWS_STAGE_TYPE)[keyof typeof AWS_STAGE_TYPE];\n\n/**\n * Deployment target role: whether an (account, region) is the primary or\n * secondary deployment target (e.g. primary vs replica region).\n */\nexport const DEPLOYMENT_TARGET_ROLE = {\n  /**\n   * Account and region that represents the primary region for this service.\n   * For example, the base DynamoDB Region for global tables.\n   */\n  PRIMARY: \"primary\",\n  /**\n   * Account and region that represents a secondary region for this service.\n   * For example, a replica region for a global DynamoDB table.\n   */\n  SECONDARY: \"secondary\",\n} as const;\n\n/**\n * Type for deployment target role values.\n */\nexport type DeploymentTargetRoleType =\n  (typeof DEPLOYMENT_TARGET_ROLE)[keyof typeof DEPLOYMENT_TARGET_ROLE];\n\n/**\n * Environment types (primary/secondary).\n *\n * @deprecated Use {@link DEPLOYMENT_TARGET_ROLE} instead. This constant is maintained for backward compatibility.\n */\nexport const AWS_ENVIRONMENT_TYPE = DEPLOYMENT_TARGET_ROLE;\n\n/**\n * Type for environment type values.\n *\n * @deprecated Use {@link DeploymentTargetRoleType} instead. This type is maintained for backward compatibility.\n */\nexport type AwsEnvironmentType = DeploymentTargetRoleType;\n","import { execSync } from \"node:child_process\";\n\n/**\n * Returns the current full git branch name\n *\n * ie: feature/1234 returns feature/1234\n *\n */\nexport const findGitBranch = (): string => {\n  return execSync(\"git rev-parse --abbrev-ref HEAD\")\n    .toString(\"utf8\")\n    .replace(/[\\n\\r\\s]+$/, \"\");\n};\n\nexport const findGitRepoName = (): string => {\n  /**\n   * When running in github actions this will be populated.\n   */\n  if (process.env.GITHUB_REPOSITORY) {\n    return process.env.GITHUB_REPOSITORY;\n  }\n\n  /**\n   * locally, we need to extract the repo name from the git config.\n   */\n  const remote = execSync(\"git config --get remote.origin.url\")\n    .toString(\"utf8\")\n    .replace(/[\\n\\r\\s]+$/, \"\")\n    .trim();\n\n  const match = remote.match(/[:\\/]([^/]+\\/[^/]+?)(?:\\.git)?$/);\n  const repoName = match ? match[1] : \"error-repo-name\";\n\n  return repoName;\n};\n","import * as crypto from \"node:crypto\";\n\n/**\n *\n * @param inString - string to hash\n * @param trimLength - trim to this length (defaults to 999 chars)\n * @returns Hex-encoded sha256 digest, truncated to `trimLength` characters.\n */\nexport const hashString = (inString: string, trimLength: number = 999) => {\n  return crypto\n    .createHash(\"sha256\")\n    .update(inString)\n    .digest(\"hex\")\n    .substring(0, trimLength);\n};\n\n/**\n *\n * @param inputString - string to truncate\n * @param maxLength - max length of this string\n * @returns trimmed string\n */\nexport const trimStringLength = (inputString: string, maxLength: number) => {\n  return inputString.length < maxLength\n    ? inputString\n    : inputString.substring(0, maxLength);\n};\n","/**\n * Public API surface for `@codedrifters/utils`.\n */\nexport * from \"./aws/aws-types\";\nexport * from \"./git/git-utils\";\nexport * from \"./string/string-utils\";\n","import { Component, Project, SampleFile, TextFile } from \"projen\";\nimport {\n  AgentConfigOptions,\n  AgentRuleBundle,\n  ClaudeHookEntry,\n  ClaudeHooksConfig,\n  ClaudePermissionsConfig,\n  ClaudeSettingsConfig,\n  SourceTierExamples,\n} from \"./agent-config-options\";\nimport { buildBuiltInBundles, ResolvedRuleConventions } from \"./bundles\";\nimport {\n  buildAgentRegistryRule,\n  buildConventionsRegistryRule,\n  bundleNameForWorkflowRule,\n  isSuppressedWorkflowRule,\n} from \"./bundles/agent-registry\";\nimport { resolveBuildPolicy } from \"./bundles/build-policy\";\nimport { hasAnyDownstreamIssueKindBundle } from \"./bundles/bundle-ownership\";\nimport {\n  renderCustomDocSections,\n  renderSourceTierExamples,\n} from \"./bundles/features\";\nimport { renderFocusSection } from \"./bundles/focus\";\nimport {\n  resolveIssueDefaults,\n  validateIssueDefaultsConfig,\n} from \"./bundles/issue-defaults\";\nimport {\n  collectIssueTemplateRecipeStubs,\n  issueTemplatesGeneratedPath,\n  renderIssueTemplateLabelsCheckerScript,\n  renderIssueTemplatesBundleHook,\n  renderIssueTemplatesCheckerScript,\n  renderIssueTemplatesGeneratedPage,\n  renderIssueTemplatesStarterPage,\n  resolveIssueTemplates,\n  validateIssueTemplatesConfig,\n} from \"./bundles/issue-templates\";\nimport { renderMeetingTypesSection } from \"./bundles/meeting-types\";\nimport { resolveOrchestratorAssets } from \"./bundles/orchestrator\";\nimport { resolveAgentPaths, ResolvedAgentPaths } from \"./bundles/paths\";\nimport {\n  resolvePrReviewPolicy,\n  validatePrReviewPolicyConfig,\n} from \"./bundles/pr-review-policy\";\nimport { renderPriorityRulesSection } from \"./bundles/priority-rules\";\nimport {\n  renderProgressFilesBundleHook,\n  resolveProgressFiles,\n  validateProgressFilesConfig,\n} from \"./bundles/progress-files\";\nimport { resolveRunRatio } from \"./bundles/run-ratio\";\nimport {\n  renderScheduledTaskSkillFile,\n  validateScheduledTasksConfig,\n} from \"./bundles/scheduled-tasks\";\nimport { scopeFilePatternsToProjects } from \"./bundles/scope\";\nimport { validateScopeGateConfig } from \"./bundles/scope-gate\";\nimport {\n  renderSharedEditingBundleHook,\n  renderSharedEditingHelperScript,\n  resolveSharedEditing,\n  validateSharedEditingConfig,\n} from \"./bundles/shared-editing\";\nimport {\n  renderSkillEvalsBundleHook,\n  renderSkillEvalsRunnerScript,\n  resolveSkillEvals,\n  validateSkillEvalsConfig,\n} from \"./bundles/skill-evals\";\nimport {\n  renderTemporalFramingCheckerScript,\n  resolveTemporalFraming,\n  validateTemporalFramingConfig,\n} from \"./bundles/temporal-framing\";\nimport { validateAgentTierConfig } from \"./bundles/tiers\";\nimport { validateUnblockDependentsConfig } from \"./bundles/unblock-dependents\";\nimport { ClaudeRenderer } from \"./renderers/claude-renderer\";\nimport { CursorRenderer } from \"./renderers/cursor-renderer\";\nimport { resolveTemplateVariables } from \"./template-resolver\";\nimport { ProjectMetadata } from \"../projects/project-metadata\";\nimport { ResolvedProjectMetadata } from \"../projects/project-metadata-options\";\nimport { CodexRenderer } from \"./renderers/codex-renderer\";\nimport { CopilotRenderer } from \"./renderers/copilot-renderer\";\nimport {\n  AGENT_MODEL,\n  AGENT_PLATFORM,\n  AGENT_RULE_SCOPE,\n  AgentCommand,\n  AgentModel,\n  AgentPlatform,\n  AgentProcedure,\n  AgentRule,\n  AgentSkill,\n  AgentSubAgent,\n} from \"./types\";\n\n/**\n * Map a string tier value (`'powerful' | 'balanced' | 'fast'`) to\n * its corresponding `AgentModel`. Returns BALANCED when the input\n * is `undefined` or any unrecognised value so demote-target agents\n * default to Sonnet rather than throwing.\n *\n * Shared by `resolveDefaultAgentTier` (global knob) and\n * `resolveBundleAgentTiers` (per-bundle override map) so both\n * paths normalise identically.\n *\n * @internal\n */\nfunction mapAgentTier(value: string | undefined): AgentModel {\n  switch (value) {\n    case \"powerful\":\n      return AGENT_MODEL.POWERFUL;\n    case \"fast\":\n      return AGENT_MODEL.FAST;\n    case \"balanced\":\n    default:\n      return AGENT_MODEL.BALANCED;\n  }\n}\n\n/**\n * Resolve the project's default sub-agent model tier. Used to thread the\n * caller-configured `defaultAgentTier` knob into every analyst / writer /\n * profile / research / regulatory / standards / business-models / customer /\n * industry / meeting / maintenance bundle factory. Returns BALANCED when the\n * option is omitted so demote-target agents land on Sonnet by default.\n *\n * The four reviewer/orchestrator agents (orchestrator, issue-worker,\n * pr-reviewer, requirements-reviewer) ignore this resolver and stay pinned\n * on POWERFUL inside their bundle source.\n *\n * @internal\n */\nexport function resolveDefaultAgentTier(\n  options?: AgentConfigOptions,\n): AgentModel {\n  return mapAgentTier(options?.defaultAgentTier);\n}\n\n/**\n * Bundle names that read the `bundleAgentTiers` per-bundle override\n * map. Any key in `bundleAgentTiers` that is not in this set is\n * rejected at synth time as a typo / invalid bundle name.\n *\n * Mirrors the demote-set asserted in\n * `bundles.test.ts#defaultAgentTier` — the two lists must stay in\n * lockstep.\n *\n * @internal\n */\nexport const TIER_AWARE_BUNDLE_NAMES: ReadonlyArray<string> = [\n  \"company-profile\",\n  \"customer-profile\",\n  \"maintenance-audit\",\n  \"meeting-analysis\",\n  \"people-profile\",\n  \"software-profile\",\n];\n\n/**\n * Resolve the project's per-bundle agent-tier override map. Returns\n * a `Map<bundleName, AgentModel>` containing only the bundles a\n * consumer pinned via `bundleAgentTiers`; bundles not present in\n * the map fall back to `defaultAgentTier` at lookup time inside\n * `buildBuiltInBundles`.\n *\n * Throws at synth time when the map contains a key that is not\n * one of the six tier-aware bundle names. Silently ignoring an\n * unknown key would let typos hide.\n *\n * @internal\n */\nexport function resolveBundleAgentTiers(\n  options?: AgentConfigOptions,\n): ReadonlyMap<string, AgentModel> {\n  const overrides = options?.bundleAgentTiers;\n  if (!overrides) {\n    return new Map();\n  }\n  const validNames = new Set(TIER_AWARE_BUNDLE_NAMES);\n  const out = new Map<string, AgentModel>();\n  for (const [name, value] of Object.entries(overrides)) {\n    if (!validNames.has(name)) {\n      throw new Error(\n        `bundleAgentTiers contains unknown bundle name \"${name}\". ` +\n          `Valid names are: ${TIER_AWARE_BUNDLE_NAMES.join(\", \")}.`,\n      );\n    }\n    out.set(name, mapAgentTier(value));\n  }\n  return out;\n}\n\n/*******************************************************************************\n *\n * Default Claude Code permissions — hardened baseline that minimises approval\n * prompts while blocking destructive and dangerous operations.\n *\n * Projects can extend these via `claudeSettings.permissions.allow` /\n * `.deny` — user-supplied entries are appended (not replaced).\n *\n ******************************************************************************/\n\n/** @internal */\nconst DEFAULT_CLAUDE_ALLOW: ReadonlyArray<string> = [\n  // ── Git ──────────────────────────────────────────────────────────────\n  \"Bash(git add *)\",\n  \"Bash(git branch *)\",\n  \"Bash(git checkout *)\",\n  \"Bash(git commit *)\",\n  \"Bash(git diff *)\",\n  \"Bash(git fetch *)\",\n  \"Bash(git log *)\",\n  \"Bash(git merge *)\",\n  \"Bash(git mv *)\",\n  \"Bash(git pull *)\",\n  \"Bash(git push *)\",\n  \"Bash(git rebase *)\",\n  \"Bash(git rm *)\",\n  \"Bash(git stash *)\",\n  \"Bash(git status *)\",\n  \"Bash(git show *)\",\n  \"Bash(git rev-parse *)\",\n\n  // ── GitHub CLI ───────────────────────────────────────────────────────\n  \"Bash(gh issue *)\",\n  \"Bash(gh pr *)\",\n  \"Bash(gh repo *)\",\n  \"Bash(gh api *)\",\n  \"Bash(gh label *)\",\n  \"Bash(gh run *)\",\n  \"Bash(gh search *)\",\n  \"Bash(gh browse *)\",\n  \"Bash(gh status *)\",\n\n  // ── Package manager ──────────────────────────────────────────────────\n  \"Bash(pnpm *)\",\n\n  // ── Read-only shell utilities ────────────────────────────────────────\n  \"Bash(ls *)\",\n  \"Bash(find *)\",\n  \"Bash(cat *)\",\n  \"Bash(head *)\",\n  \"Bash(tail *)\",\n  \"Bash(wc *)\",\n  \"Bash(grep *)\",\n  \"Bash(sort *)\",\n  \"Bash(uniq *)\",\n  \"Bash(dirname *)\",\n  \"Bash(basename *)\",\n  \"Bash(which *)\",\n  \"Bash(diff *)\",\n  \"Bash(jq *)\",\n  \"Bash(date *)\",\n\n  // ── Safe output / test utilities ─────────────────────────────────────\n  \"Bash(echo *)\",\n  \"Bash(printf *)\",\n  \"Bash(test *)\",\n  \"Bash([ *)\",\n  \"Bash(true *)\",\n  \"Bash(false *)\",\n\n  // ── Safe directory operations ────────────────────────────────────────\n  \"Bash(mkdir *)\",\n  \"Bash(rmdir *)\",\n\n  // ── Built-in tools ───────────────────────────────────────────────────\n  \"Read(/**)\",\n  \"Edit(/**)\",\n  \"Write(/**)\",\n  \"WebFetch\",\n  \"WebSearch\",\n];\n\n/** @internal */\nconst DEFAULT_CLAUDE_DENY: ReadonlyArray<string> = [\n  // ── Destructive git ──────────────────────────────────────────────────\n  \"Bash(git push --force *)\",\n  \"Bash(git push -f *)\",\n  \"Bash(git push origin --force *)\",\n  \"Bash(git push origin -f *)\",\n  \"Bash(git reset --hard *)\",\n  \"Bash(git clean -f *)\",\n  \"Bash(git remote *)\",\n\n  // ── Destructive file operations ──────────────────────────────────────\n  \"Bash(rm -rf *)\",\n  \"Bash(rm -r *)\",\n  \"Bash(rm *)\",\n\n  // ── Network / remote access ──────────────────────────────────────────\n  \"Bash(curl *)\",\n  \"Bash(wget *)\",\n  \"Bash(ssh *)\",\n  \"Bash(scp *)\",\n\n  // ── System administration ────────────────────────────────────────────\n  \"Bash(sudo *)\",\n  \"Bash(chmod *)\",\n  \"Bash(chown *)\",\n  \"Bash(kill *)\",\n  \"Bash(killall *)\",\n  \"Bash(pkill *)\",\n\n  // ── Code execution / shell spawning ──────────────────────────────────\n  \"Bash(eval *)\",\n  \"Bash(exec *)\",\n  \"Bash(source *)\",\n  \"Bash(. *)\",\n  \"Bash(bash *)\",\n  \"Bash(sh *)\",\n  \"Bash(zsh *)\",\n\n  // ── App launching ────────────────────────────────────────────────────\n  \"Bash(open *)\",\n  \"Bash(xdg-open *)\",\n\n  // ── Environment manipulation ─────────────────────────────────────────\n  \"Bash(export *)\",\n  \"Bash(env *)\",\n];\n\n/**\n * Path-based deny defaults — block read access to large generated trees,\n * lockfiles, and secret-bearing files. These complement the command-based\n * `DEFAULT_CLAUDE_DENY` baseline above by guarding the\n * `Read` tool surface area; an unfiltered `Read(/**)` allow line is fine\n * when paired with these denies because path denies take precedence over\n * tool-level allows.\n *\n * Entries are intentionally relative-to-cwd (`./.astro/**`) so they\n * match a project-rooted Read call without leaking onto sibling clones\n * the operator may explicitly point Claude at.\n *\n * @internal\n */\nconst DEFAULT_CLAUDE_PATH_DENY: ReadonlyArray<string> = [\n  \"Read(./.astro/**)\",\n  \"Read(./.env)\",\n  \"Read(./.env.*)\",\n  \"Read(./*.lock)\",\n  \"Read(./package-lock.json)\",\n];\n\n/**\n * Tier-0 measurement file appended to by the default `Stop` hook.\n * Surfaced as an exported constant so the gitignore wiring inside the\n * `AgentConfig` component can reference the same path the hook writes\n * to without drift.\n *\n * @internal\n */\nconst DEFAULT_USAGE_LOG_PATH = \".claude/usage.log\";\n\n/**\n * Default environment variables shipped to every consumer's\n * `.claude/settings.json`. Consumer-supplied entries on\n * `claudeSettings.env` override the defaults on key collision.\n *\n * - **`ENABLE_TOOL_SEARCH`** — gates Claude Code's deferred-tool-loading\n *   optimization. With `\"1\"`, MCP tool schemas load on demand via a\n *   `ToolSearch` step instead of being pinned into the system prompt.\n *   This recovers per-turn context tokens when several MCP servers are\n *   connected. See knowledge-base technique 02 (`techniques/02-mcp-servers.md`)\n *   for details.\n *\n * The merger in `mergeClaudeDefaults` spreads these entries first and\n * then layers consumer entries on top, so a consumer that sets the\n * same key wins.\n *\n * @internal\n */\nconst DEFAULT_CLAUDE_ENV: Readonly<Record<string, string>> = {\n  ENABLE_TOOL_SEARCH: \"1\",\n};\n\n/**\n * Default Claude Code hooks shipped to every consumer's\n * `.claude/settings.json` unless `claudeSettings.disableAllHooks: true`\n * is set.\n *\n * Claude Code delivers hook data as a JSON object on stdin (fields\n * such as `session_id` and `tool_input.file_path`), not as `CLAUDE_*`\n * environment variables, so both hooks parse their inputs out of that\n * stdin payload with `jq`.\n *\n * - **Stop** — reads `.session_id` from the stdin JSON and appends\n *   `<timestamp>,<session-id>` to `.claude/usage.log` on every Stop\n *   event so consumers can track per-session usage without a separate\n *   measurement harness. Claude Code does not pass token counts to\n *   hooks, so usage.log is a 2-column `<timestamp>,<session-id>` record\n *   — the earlier input/output-token columns are dropped. Disable by\n *   either setting `disableAllHooks: true` (drops every default and\n *   consumer-supplied hook) or by overriding the `Stop` array on\n *   `claudeSettings.hooks` — user-supplied entries are preserved\n *   alongside the defaults.\n * - **PostToolUse** — matches `Edit|Write`, reads `.tool_input.file_path`\n *   from the stdin JSON and, when the touched file lives under\n *   `docs/src/content/docs/`, runs `strip-tool-artifact-tags.sh` to\n *   remove any leaked tool-call wrapper closing tags from the end of\n *   the file (#779). Wrapped in a `case` shell statement that no-ops\n *   cleanly on a missing path or a missing procedure script (the\n *   stripper is `-x`-guarded), so the hook never blocks an edit. The\n *   stripper is idempotent, always exits 0, and produces no output that\n *   reaches the model.\n *\n * The merger in `mergeClaudeDefaults` appends these entries after any\n * consumer-supplied entries and dedupes by `(matcher, command)` so\n * defaults never collide with a consumer's identical override.\n *\n * @internal\n */\nconst DEFAULT_CLAUDE_HOOKS: ClaudeHooksConfig = {\n  Stop: [\n    {\n      matcher: \"*\",\n      hooks: [\n        {\n          type: \"command\",\n          // Claude Code delivers hook data as a JSON object on stdin, not\n          // as CLAUDE_* env vars, so read the session id from `.session_id`\n          // via jq. Token counts are not passed to hooks, so the two token\n          // columns are dropped — usage.log is now `<timestamp>,<session-id>`.\n          command: `sid=\"$(jq -r '.session_id // \"unknown\"' 2>/dev/null)\"; echo \"$(date -u +%FT%TZ),\\${sid:-unknown}\" >> ${DEFAULT_USAGE_LOG_PATH}`,\n        },\n      ],\n    },\n  ],\n  PostToolUse: [\n    {\n      matcher: \"Edit|Write\",\n      hooks: [\n        {\n          type: \"command\",\n          // Claude Code delivers hook data as a JSON object on stdin, not\n          // as CLAUDE_* env vars, so read the edited file path from\n          // `.tool_input.file_path` via jq. On files under\n          // docs/src/content/docs/ this runs only the tool-artifact-tag\n          // stripper (#779); it is `-x`-guarded so it no-ops cleanly when\n          // the path is empty or the procedure script is not shipped.\n          command:\n            'path=\"$(jq -r \\'.tool_input.file_path // empty\\' 2>/dev/null)\"; case \"$path\" in *docs/src/content/docs/*) if [ -x .claude/procedures/strip-tool-artifact-tags.sh ]; then bash .claude/procedures/strip-tool-artifact-tags.sh \"$path\" >/dev/null 2>&1; fi ;; esac',\n        },\n      ],\n    },\n  ],\n};\n\n/**\n * Phased-agent bundle rules that receive a \"Progress File\" hook\n * section in their rendered content when the progress-file convention\n * is enabled. The tuple is `[ruleName, agentLabel]`; the label is\n * substituted into the hook's opening sentence\n * (e.g. `\"Every bcm-writer session writes a progress file …\"`).\n *\n * Bundle rule names that do not exist in the current bundle\n * composition are silently skipped — consumers that opt out of a\n * phased-agent bundle do not need to also opt out of the hook.\n *\n * @internal\n */\nconst PROGRESS_FILE_BUNDLE_HOOKS: ReadonlyArray<readonly [string, string]> = [\n  [\"bcm-writer-workflow\", \"bcm-writer\"],\n  [\"business-models-workflow\", \"business-models\"],\n  [\"company-profile-workflow\", \"company-profile\"],\n  [\"customer-profile-workflow\", \"customer-profile\"],\n  [\"industry-discovery-workflow\", \"industry-discovery\"],\n  [\"meeting-agenda-workflow\", \"agenda\"],\n  [\"meeting-processing-workflow\", \"meeting-analysis\"],\n  [\"regulatory-research-workflow\", \"regulatory-research\"],\n  [\"requirements-analyst-workflow\", \"requirements-analyst\"],\n  [\"research-pipeline-workflow\", \"research-pipeline\"],\n  [\"software-profile-workflow\", \"software-profile\"],\n  [\"standards-research-workflow\", \"standards-research\"],\n];\n\n/**\n * Phased-agent bundle rules that receive a \"Shared Index Editing\"\n * hook section in their rendered content when the shared-editing\n * convention is enabled. The tuple is `[ruleName, agentLabel]`; the\n * label is substituted into the hook's opening sentence (e.g.\n * `\"Every company-profile run that adds a row to a shared registry …\"`).\n *\n * These are the bundles whose output documents are catalogued in a\n * shared `index.md` / `README.md` registry or a feature-matrix file,\n * plus the `requirements-reviewer` deprecation phase that edits an\n * existing registry row — the set that actually produces\n * concurrent-write contention on shared indexes. Bundle rule names\n * that do not exist in the current bundle composition are silently\n * skipped, so consumers that opt out of a phased-agent bundle do not\n * need to also opt out of the hook.\n *\n * @internal\n */\nconst SHARED_EDITING_BUNDLE_HOOKS: ReadonlyArray<readonly [string, string]> = [\n  [\"bcm-writer-workflow\", \"bcm-writer\"],\n  [\"business-models-workflow\", \"business-models\"],\n  [\"company-profile-workflow\", \"company-profile\"],\n  [\"customer-profile-workflow\", \"customer-profile\"],\n  [\"industry-discovery-workflow\", \"industry-discovery\"],\n  [\"meeting-agenda-workflow\", \"agenda\"],\n  [\"meeting-processing-workflow\", \"meeting-analyst\"],\n  [\"people-profile-workflow\", \"people-profile\"],\n  [\"regulatory-research-workflow\", \"regulatory-research\"],\n  [\"requirements-reviewer-workflow\", \"requirements-reviewer\"],\n  [\"requirements-writer-workflow\", \"requirements-writer\"],\n  [\"research-pipeline-workflow\", \"research-pipeline\"],\n  [\"software-profile-workflow\", \"software-profile\"],\n  [\"standards-research-workflow\", \"standards-research\"],\n];\n\n/**\n * Skill-owning bundle rules that receive a \"Skill Evals\" hook section\n * in their rendered content when the skill-evals convention is\n * enabled. The tuple is `[ruleName, skillLabel]`; the label is both\n * the on-disk skill-directory name under `<skillsRoot>/` and the\n * substitution used in the hook's opening sentence (e.g.\n * `\"The write-requirement skill ships a regression suite at .claude/skills/write-requirement/evals/evals.json …\"`).\n *\n * The list is reconciled against the skills that actually ship an\n * `evals/evals.json` file on disk — registering a skill that has no\n * eval suite would render a hook pointing at a missing path, which\n * undermines the convention. When a new skill grows an eval suite,\n * add the matching `[ruleName, skillLabel]` pair here; when a suite\n * is retired, remove the pair.\n *\n * Orchestration-only skills (e.g. review-pr, orchestrator\n * housekeeping loops) are deliberately excluded even if evals land\n * later — their outputs are actions rather than prose, and a\n * regression in those skills surfaces as a workflow failure rather\n * than an output mismatch.\n *\n * Bundle rule names that do not exist in the current bundle\n * composition are silently skipped, so consumers that opt out of a\n * skill-owning bundle do not need to also opt out of the hook.\n *\n * @internal\n */\nconst SKILL_EVALS_BUNDLE_HOOKS: ReadonlyArray<readonly [string, string]> = [\n  [\"company-profile-workflow\", \"profile-company\"],\n  [\"requirements-analyst-workflow\", \"requirements-analyst\"],\n  [\"requirements-writer-workflow\", \"write-requirement\"],\n];\n\n/**\n * Phased-agent bundle rules that receive an \"Issue Templates\" hook\n * section in their rendered content when the issue-templates\n * convention is enabled. The tuple is `[ruleName, bundleLabel]`; the\n * label is substituted into the hook's opening sentence (e.g.\n * `\"Every downstream gh issue create invocation dispatched by the company-profile bundle must …\"`).\n *\n * The list targets every bundle whose phased workflow dispatches\n * downstream issues via `gh issue create` — the agents for whom a\n * canonical template reference meaningfully reduces drift. Pure\n * orchestration bundles (orchestrator, pr-review) do not file\n * downstream issues themselves, so their workflow rules do not\n * receive the hook; they triage and route existing issues rather\n * than minting new ones.\n *\n * Bundle rule names that do not exist in the current bundle\n * composition are silently skipped — consumers that opt out of a\n * phased-agent bundle do not need to also opt out of the hook.\n *\n * @internal\n */\nconst ISSUE_TEMPLATES_BUNDLE_HOOKS: ReadonlyArray<readonly [string, string]> = [\n  [\"bcm-writer-workflow\", \"bcm-writer\"],\n  [\"business-models-workflow\", \"business-models\"],\n  [\"company-profile-workflow\", \"company-profile\"],\n  [\"customer-profile-workflow\", \"customer-profile\"],\n  [\"industry-discovery-workflow\", \"industry-discovery\"],\n  [\"maintenance-audit-workflow\", \"maintenance-audit\"],\n  [\"meeting-agenda-workflow\", \"agenda\"],\n  [\"meeting-processing-workflow\", \"meeting-analysis\"],\n  [\"people-profile-workflow\", \"people-profile\"],\n  [\"regulatory-research-workflow\", \"regulatory-research\"],\n  [\"requirements-analyst-workflow\", \"requirements-analyst\"],\n  [\"requirements-reviewer-workflow\", \"requirements-reviewer\"],\n  [\"requirements-writer-workflow\", \"requirements-writer\"],\n  [\"research-pipeline-workflow\", \"research-pipeline\"],\n  [\"software-profile-workflow\", \"software-profile\"],\n  [\"standards-research-workflow\", \"standards-research\"],\n];\n\n/**\n * Generates AI coding assistant configuration files from a common schema.\n *\n * Supports Cursor and Claude Code (initial release), with Codex and Copilot\n * renderers planned for future issues. Rules, skills, and sub-agents are\n * defined once and rendered into the correct format for each target platform.\n *\n * Follows the configulator component pattern: extends Component, static .of()\n * factory, options interface with JSDoc.\n *\n * @example\n * ```ts\n * new AgentConfig(project, {\n *   rules: [{\n *     name: 'my-rule',\n *     description: 'Project conventions',\n *     scope: AGENT_RULE_SCOPE.ALWAYS,\n *     content: '# My Rule\\n\\nFollow these conventions...',\n *   }],\n * });\n * ```\n */\nexport class AgentConfig extends Component {\n  /**\n   * Find the AgentConfig component on a project.\n   */\n  public static of(project: Project): AgentConfig | undefined {\n    const isAgentConfig = (c: Component): c is AgentConfig =>\n      c instanceof AgentConfig;\n    return project.components.find(isAgentConfig);\n  }\n\n  /**\n   * Returns `true` when at least one tier array on the supplied\n   * `SourceTierExamples` is non-empty, signalling that the consuming\n   * repo has opted into rendering the base bundle's\n   * `source-quality-verification` rule. Returns `false` for\n   * `undefined`, `{}`, or a fully-empty `{ t1: [], t2: [], t3: [], t4: [] }`.\n   */\n  private static hasActiveTierExamples(\n    examples: SourceTierExamples | undefined,\n  ): boolean {\n    if (!examples) {\n      return false;\n    }\n    return (\n      (examples.t1?.length ?? 0) > 0 ||\n      (examples.t2?.length ?? 0) > 0 ||\n      (examples.t3?.length ?? 0) > 0 ||\n      (examples.t4?.length ?? 0) > 0\n    );\n  }\n\n  /**\n   * Merges default Claude permissions and hooks with bundle and\n   * user-supplied settings.\n   *\n   * Permission merge order: defaults → bundle permissions → user-supplied\n   * entries. Both `allow` and `deny` are deduped via\n   * `Array.from(new Set(...))`; V8 `Set` iteration preserves insertion\n   * order, so the final ordering is defaults first, then bundle, then\n   * user, with duplicates removed (first-occurrence wins). After the\n   * merge+dedupe, any entry whose value exactly matches a string in\n   * `permissions.excludeDefaults` is dropped from `allow` / `deny` / `ask`\n   * — the only supported way to remove a baseline default, since the merge\n   * is otherwise append-only. `excludeDefaults` is a build-time directive\n   * and is stripped from the rendered `permissions` object. `defaultMode`\n   * is opt-in (steering decision D7): it is set only from\n   * `userSettings.defaultMode` and left undefined otherwise, so the\n   * renderer omits the key for un-opted-in consumers — see the inline\n   * comment on the literal below.\n   *\n   * Hooks merge: consumer-supplied entries first, then default entries\n   * (Stop, PostToolUse), deduped by `(matcher, JSON-serialized hooks)`.\n   * Defaults are skipped entirely when `disableAllHooks: true` is set —\n   * the `disableAllHooks` flag passes through to the rendered file so\n   * Claude Code suppresses every project-level hook at runtime, and the\n   * defaults are dropped at synth time so the rendered file does not\n   * carry orphan entries that would re-fire if the operator later flipped\n   * the flag back off.\n   *\n   * Env merge: defaults from `DEFAULT_CLAUDE_ENV` (e.g.\n   * `ENABLE_TOOL_SEARCH=1`) layer first, then consumer-supplied\n   * `claudeSettings.env` entries override on key collision. Sibling keys\n   * from both sources land in the rendered file.\n   */\n  private static mergeClaudeDefaults(\n    userSettings?: ClaudeSettingsConfig,\n    bundlePermissions?: { allow: Array<string>; deny: Array<string> },\n  ): ClaudeSettingsConfig {\n    const bundleAllow = bundlePermissions?.allow ?? [];\n    const bundleDeny = bundlePermissions?.deny ?? [];\n    const userAllow = userSettings?.permissions?.allow ?? [];\n    const userDeny = userSettings?.permissions?.deny ?? [];\n\n    const exclude = new Set(userSettings?.permissions?.excludeDefaults ?? []);\n    const dropExcluded = (entries: Array<string>): Array<string> =>\n      entries.filter((entry) => !exclude.has(entry));\n\n    // `excludeDefaults` is a build-time directive, not a rendered field.\n    const { excludeDefaults: _excludeDefaults, ...passthroughPermissions } =\n      userSettings?.permissions ?? {};\n\n    // Defensive/forward-compat: no default `ask` entries exist today, but\n    // filter any consumer-supplied ones for consistency. Only override the\n    // passthrough `ask` when there is something to filter so the rendered\n    // output is byte-identical for consumers that set no `excludeDefaults`.\n    const askOverride = passthroughPermissions.ask?.length\n      ? { ask: dropExcluded([...passthroughPermissions.ask]) }\n      : {};\n\n    const mergedPermissions: ClaudePermissionsConfig = {\n      ...passthroughPermissions,\n      allow: dropExcluded(\n        Array.from(\n          new Set([...DEFAULT_CLAUDE_ALLOW, ...bundleAllow, ...userAllow]),\n        ),\n      ),\n      deny: dropExcluded(\n        Array.from(\n          new Set([\n            ...DEFAULT_CLAUDE_DENY,\n            ...DEFAULT_CLAUDE_PATH_DENY,\n            ...bundleDeny,\n            ...userDeny,\n          ]),\n        ),\n      ),\n      ...askOverride,\n    };\n\n    return {\n      ...userSettings,\n      // `defaultMode` is opt-in (steering decision D7): the base\n      // output does NOT set it unless the consumer supplies\n      // `claudeSettings.defaultMode`. When it is undefined the renderer\n      // omits the key entirely, so an un-opted-in consumer's rendered\n      // settings carry no `defaultMode`. Consumers that run autonomous\n      // scheduled-task workers (issue-worker, orchestrator, pr-reviewer,\n      // and the analyst/writer family) — which would deadlock on\n      // confirmation prompts — opt in by setting\n      // `claudeSettings.defaultMode: \"dontAsk\"`.\n      defaultMode: userSettings?.defaultMode,\n      permissions: mergedPermissions,\n      hooks: AgentConfig.mergeClaudeHooks(userSettings),\n      env: { ...DEFAULT_CLAUDE_ENV, ...(userSettings?.env ?? {}) },\n    };\n  }\n\n  /**\n   * Merge default lifecycle hooks (Stop, PostToolUse) with consumer-\n   * supplied entries on `claudeSettings.hooks`. Consumer entries appear\n   * first so a downstream override that wires a faster lint/format hook\n   * runs ahead of the defaults; defaults are appended after.\n   *\n   * Returns `undefined` when neither defaults nor consumer entries\n   * remain — the renderer skips the `hooks` key entirely in that case\n   * so opt-out repos do not ship an empty `\"hooks\": {}` object.\n   *\n   * Defaults are gated on `disableAllHooks !== true`. When the flag is\n   * set we still pass through any consumer-supplied entries (the\n   * runtime-level `disableAllHooks: true` is what suppresses execution),\n   * but we never inject the bundle defaults. That keeps the disable-all\n   * escape hatch idempotent: flipping the flag drops the bundle's\n   * default surface area instead of leaving the entries on disk for a\n   * future re-enable.\n   */\n  private static mergeClaudeHooks(\n    userSettings?: ClaudeSettingsConfig,\n  ): ClaudeHooksConfig | undefined {\n    const userHooks = userSettings?.hooks;\n    const includeDefaults = userSettings?.disableAllHooks !== true;\n    const defaults = includeDefaults ? DEFAULT_CLAUDE_HOOKS : {};\n\n    const allEvents = new Set<string>([\n      ...Object.keys(userHooks ?? {}),\n      ...Object.keys(defaults),\n    ]);\n\n    const merged: Record<string, ReadonlyArray<ClaudeHookEntry>> = {};\n    for (const event of allEvents) {\n      const userEntries =\n        (\n          (userHooks ?? {}) as Record<\n            string,\n            ReadonlyArray<ClaudeHookEntry> | undefined\n          >\n        )[event] ?? [];\n      const defaultEntries =\n        (\n          defaults as Record<string, ReadonlyArray<ClaudeHookEntry> | undefined>\n        )[event] ?? [];\n\n      const seen = new Set<string>();\n      const combined: Array<ClaudeHookEntry> = [];\n      for (const entry of [...userEntries, ...defaultEntries]) {\n        const key = JSON.stringify({\n          matcher: entry.matcher,\n          hooks: entry.hooks,\n        });\n        if (seen.has(key)) continue;\n        seen.add(key);\n        combined.push(entry);\n      }\n\n      if (combined.length > 0) {\n        merged[event] = combined;\n      }\n    }\n\n    return Object.keys(merged).length > 0\n      ? (merged as ClaudeHooksConfig)\n      : undefined;\n  }\n\n  private readonly options: AgentConfigOptions;\n  private cachedBundles?: ReadonlyArray<AgentRuleBundle>;\n  private cachedPaths?: ResolvedAgentPaths;\n\n  constructor(project: Project, options: AgentConfigOptions = {}) {\n    super(project);\n    this.options = options;\n  }\n\n  /**\n   * Resolved agent-path roots for this project. Consumer overrides on\n   * `AgentConfigOptions.paths` cascade into derived roots via\n   * `resolveAgentPaths()`. Memoized so repeated reads during synthesis\n   * do not re-run the resolver.\n   */\n  private get resolvedPaths(): ResolvedAgentPaths {\n    if (!this.cachedPaths) {\n      this.cachedPaths = resolveAgentPaths(this.options.paths);\n    }\n    return this.cachedPaths;\n  }\n\n  /**\n   * Path-aware built-in bundles assembled with this project's\n   * resolved paths. Path-aware bundle factories (e.g.\n   * `buildResearchPipelineBundle`) receive the resolved struct so\n   * their rendered rule content reflects any consumer override.\n   * Bundles that do not read agent paths are passed through as-is\n   * from their default const exports.\n   *\n   * The build policy is auto-detected from the project's `TurboRepo`\n   * component here rather than configured, so build guidance in the\n   * `github-workflow` and `turborepo` rules only claims an AWS\n   * credential requirement when a remote cache actually exists. The\n   * getter is lazy by design — `TurboRepo` must already be attached\n   * to the project when the bundles are first read.\n   *\n   * Every **config-driven convention rule** is likewise resolved here\n   * and seeded into its owning bundle, so the rule enters the rule map\n   * already carrying the consumer's settings. Rewriting those rules\n   * after the map was assembled — the previous approach — silently\n   * discarded any `ruleExtensions` append or same-name `rules`\n   * override that had already been merged in.\n   */\n  private get pathAwareBundles(): ReadonlyArray<AgentRuleBundle> {\n    if (!this.cachedBundles) {\n      this.cachedBundles = buildBuiltInBundles(\n        this.resolvedPaths,\n        resolveIssueDefaults(this.options.issueDefaults),\n        resolveDefaultAgentTier(this.options),\n        resolveBundleAgentTiers(this.options),\n        resolvePrReviewPolicy(this.options.prReviewPolicy),\n        resolveBuildPolicy(this.project),\n        this.resolvedRuleConventions,\n      );\n    }\n    return this.cachedBundles;\n  }\n\n  /**\n   * Resolved settings for every config-driven convention rule, derived\n   * from this project's options. Consumed by `buildBuiltInBundles` so\n   * the `base` and `orchestrator` bundles seed final rule content.\n   *\n   * `excludeBundles` feeds two of these: the orchestrator's rendered\n   * tier table / scope-gate overrides / scheduled-tasks registry drop\n   * rows owned by excluded bundles, and the issue-templates rule falls\n   * back to its disabled stub once every downstream-issue-kind bundle\n   * has been excluded.\n   */\n  private get resolvedRuleConventions(): ResolvedRuleConventions {\n    const excludeBundles = this.options.excludeBundles ?? [];\n    const orchestratorAssets = resolveOrchestratorAssets(\n      this.options.tiers,\n      this.options.scopeGate,\n      this.options.runRatio,\n      this.options.scheduledTasks,\n      this.options.unblockDependents,\n      excludeBundles,\n    );\n\n    return {\n      base: {\n        progressFiles: resolveProgressFiles(this.options.progressFiles),\n        sharedEditing: resolveSharedEditing(this.options.sharedEditing),\n        temporalFraming: resolveTemporalFraming(this.options.temporalFraming),\n        skillEvals: resolveSkillEvals(this.options.skillEvals),\n        issueTemplates: resolveIssueTemplates(this.options.issueTemplates),\n        hasDownstreamIssueKindBundles:\n          hasAnyDownstreamIssueKindBundle(excludeBundles),\n      },\n      orchestrator: {\n        tiers: orchestratorAssets.tiers,\n        scopeGate: orchestratorAssets.scopeGate,\n        runRatio: orchestratorAssets.runRatio,\n        scheduledTasks: orchestratorAssets.scheduledTasks,\n        unblockDependents: orchestratorAssets.unblockDependents,\n        excludeBundles,\n      },\n    };\n  }\n\n  /**\n   * Returns the bundles that are active for this project: auto-detected\n   * bundles (when `autoDetectBundles !== false`) plus force-included\n   * bundles, minus explicitly excluded bundles. Deduplicated by name.\n   *\n   * Exposed so sibling components (e.g. the sync-labels workflow) can\n   * consume bundle-contributed configuration.\n   */\n  public get activeBundles(): ReadonlyArray<AgentRuleBundle> {\n    const bundleMap = new Map<string, AgentRuleBundle>();\n\n    if (this.options.autoDetectBundles !== false) {\n      for (const bundle of this.pathAwareBundles) {\n        if (this.options.excludeBundles?.includes(bundle.name)) {\n          continue;\n        }\n        if (bundle.name === \"base\" && this.options.includeBaseRules === false) {\n          continue;\n        }\n        if (bundle.appliesWhen(this.project)) {\n          bundleMap.set(bundle.name, bundle);\n        }\n      }\n    }\n\n    if (this.options.includeBundles) {\n      for (const bundleName of this.options.includeBundles) {\n        const bundle = this.pathAwareBundles.find((b) => b.name === bundleName);\n        if (bundle) {\n          bundleMap.set(bundle.name, bundle);\n        }\n      }\n    }\n\n    return [...bundleMap.values()];\n  }\n\n  public override preSynthesize(): void {\n    super.preSynthesize();\n\n    // Validate the tier config **before** any rendering so a malformed\n    // `AgentTierConfig` fails the build with a clear error instead of\n    // silently shipping broken sort keys. Throwing here stops\n    // synthesis before any file is written.\n    validateAgentTierConfig(this.options.tiers);\n\n    // Validate the scope-gate config at the same time. Malformed\n    // thresholds (negative, non-integer, or inverted) fail the build\n    // before rendering so the orchestrator never ships a gate that\n    // would mis-classify issues.\n    validateScopeGateConfig(this.options.scopeGate);\n\n    // Validate the PR review policy config. Empty / whitespace-only\n    // entries in `prReviewPolicy.autoMerge.pathsExemptFromSize` fail\n    // the build before rendering so the rendered policy YAML never\n    // ships with a broken carve-out glob.\n    validatePrReviewPolicyConfig(this.options.prReviewPolicy);\n\n    // Validate the run-ratio config. Malformed ratios (non-integer\n    // or non-positive) or an empty / absolute state-file path fail\n    // the build before rendering so the orchestrator never ships a\n    // broken housekeeping cadence. Resolving here also gives us the\n    // canonical state-file path so we can gitignore it — the rendered\n    // CLAUDE.md claims the file is gitignored in consumer repos, so\n    // the bundle is responsible for making that claim true.\n    const resolvedRunRatio = resolveRunRatio(this.options.runRatio);\n    if (resolvedRunRatio.enabled) {\n      this.project.gitignore.addPatterns(`/${resolvedRunRatio.stateFilePath}`);\n    }\n\n    // Gitignore the per-session usage-log file written by the default\n    // `Stop` hook. The default hook is opt-out via\n    // `claudeSettings.disableAllHooks`, so the gitignore entry is only\n    // added when the hook will actually fire — flipping the flag drops\n    // both the hook and the gitignore line so the file pattern never\n    // outlives the writer.\n    if (this.options.claudeSettings?.disableAllHooks !== true) {\n      this.project.gitignore.addPatterns(`/${DEFAULT_USAGE_LOG_PATH}`);\n    }\n\n    // Validate the agent-driven unblock-dependents config. Empty /\n    // whitespace-only comment templates fail the build before\n    // rendering so the emitted unblock-dependents.sh never ships\n    // with a broken comment body.\n    validateUnblockDependentsConfig(this.options.unblockDependents);\n\n    // Validate the per-phase-label issue-defaults overrides. Unknown\n    // status:* / priority:* values, empty entries, and empty\n    // phase-label keys fail the build before rendering so bundle\n    // prompts never ship with a malformed `gh issue create` recipe.\n    validateIssueDefaultsConfig(this.options.issueDefaults);\n\n    // Validate the progress-file convention. Empty / absolute\n    // stateDir, filename patterns missing the <ISSUE_NUMBER>\n    // placeholder, unknown format values, and non-positive\n    // staleAfterHours fail the build before rendering so agents\n    // never ship with a broken resume contract. Resolving here also\n    // gives us the canonical state directory so we can gitignore it\n    // — the rendered convention claims progress files never land on\n    // the default branch, so the bundle is responsible for making\n    // that claim true.\n    const resolvedProgressFiles = validateProgressFilesConfig(\n      this.options.progressFiles,\n    );\n    if (resolvedProgressFiles.enabled) {\n      this.project.gitignore.addPatterns(`/${resolvedProgressFiles.stateDir}/`);\n    }\n\n    // Validate the scheduled-tasks config. Unknown model values,\n    // empty taskId / agent / typeLabel fields, overrides keyed on an\n    // unknown taskId, and duplicate taskIds inside `tasks` fail the\n    // build before rendering so the bundle never ships a broken\n    // per-agent worker SKILL.md.\n    const resolvedScheduledTasks = validateScheduledTasksConfig(\n      this.options.scheduledTasks,\n      this.options.excludeBundles ?? [],\n    );\n\n    // Emit one .claude/scheduled-tasks/<taskId>/SKILL.md per enabled\n    // task. The subsystem is opt-in at the task level: every default\n    // entry ships with `enabled: false`, so repos that never touch\n    // `options.scheduledTasks` see no files on disk. Consumers flip\n    // specific tasks on via `overrides.<taskId>.enabled = true`.\n    if (resolvedScheduledTasks.enabled) {\n      for (const task of resolvedScheduledTasks.tasks) {\n        if (!task.enabled) continue;\n        const filePath = `${resolvedScheduledTasks.root}/${task.taskId}/SKILL.md`;\n        new TextFile(this, filePath, {\n          lines: renderScheduledTaskSkillFile(task).split(\"\\n\"),\n        });\n      }\n    }\n\n    // Validate the shared-editing convention. Empty / whitespace-only\n    // path entries and unknown conflictStrategy values fail the build\n    // before rendering so agents never ship with a malformed\n    // shared-index contract. The optional helper script is emitted\n    // here when the consumer opts in — keeping the emission next to\n    // validation keeps every shared-editing side-effect in one place.\n    const resolvedSharedEditing = validateSharedEditingConfig(\n      this.options.sharedEditing,\n    );\n    if (resolvedSharedEditing.enabled && resolvedSharedEditing.emitHelper) {\n      new TextFile(this, \".claude/procedures/verify-index-row.sh\", {\n        lines: renderSharedEditingHelperScript(resolvedSharedEditing).split(\n          \"\\n\",\n        ),\n        executable: true,\n      });\n    }\n\n    // Validate the skill-evals convention. Empty / whitespace-only or\n    // absolute `skillsRoot` / `productContextPath` fail the build\n    // before rendering so agents never ship with a malformed eval\n    // harness contract. The optional runner script is emitted here\n    // when the consumer opts in — keeping the emission next to\n    // validation keeps every skill-evals side-effect in one place.\n    const resolvedSkillEvals = validateSkillEvalsConfig(\n      this.options.skillEvals,\n    );\n    if (resolvedSkillEvals.enabled && resolvedSkillEvals.emitRunner) {\n      new TextFile(this, \".claude/procedures/run-skill-evals.sh\", {\n        lines: renderSkillEvalsRunnerScript(resolvedSkillEvals).split(\"\\n\"),\n        executable: true,\n      });\n    }\n\n    // Validate the issue-templates convention. Empty / whitespace-only\n    // or absolute `templatesPath` and empty / whitespace-only pattern\n    // entries fail the build before rendering so agents never ship\n    // with a malformed templates contract. The optional lint script\n    // and starter doc are emitted here when the consumer opts in —\n    // keeping the emission next to validation keeps every\n    // issue-templates side-effect in one place.\n    const resolvedIssueTemplates = validateIssueTemplatesConfig(\n      this.options.issueTemplates,\n    );\n    if (resolvedIssueTemplates.enabled) {\n      if (resolvedIssueTemplates.emitChecker) {\n        new TextFile(this, \".claude/procedures/check-issue-templates.sh\", {\n          lines: renderIssueTemplatesCheckerScript(\n            resolvedIssueTemplates,\n          ).split(\"\\n\"),\n          executable: true,\n        });\n        // Companion lint: `check-issue-templates.sh` polices *where*\n        // recipes live, this one polices *what they say* — that every\n        // `## Template:` recipe pairs its phase label with the\n        // `type:<bundle>` label the bundle-ownership map requires and\n        // assigns a GitHub issue type.\n        new TextFile(\n          this,\n          \".claude/procedures/check-issue-template-labels.sh\",\n          {\n            lines: renderIssueTemplateLabelsCheckerScript(\n              resolvedIssueTemplates,\n            ).split(\"\\n\"),\n            executable: true,\n          },\n        );\n      }\n      if (resolvedIssueTemplates.emitStarterDoc) {\n        // SampleFile: write-once — the starter page scaffolds the\n        // hand-authored templates file without clobbering it on later\n        // projen runs. Subsequent `pnpm exec projen` runs leave the\n        // file alone so authors can flesh out the scaffold.\n        new SampleFile(this.project, resolvedIssueTemplates.templatesPath, {\n          contents: renderIssueTemplatesStarterPage(resolvedIssueTemplates),\n        });\n        // TextFile: always regenerated. A `SampleFile` never reaches a\n        // consumer whose templates page already exists, so the label\n        // half of every recipe lives here instead — one\n        // correct-by-construction stub per phase label the active\n        // bundles emit, refreshed on every synth.\n        new TextFile(\n          this,\n          issueTemplatesGeneratedPath(resolvedIssueTemplates.templatesPath),\n          {\n            lines: renderIssueTemplatesGeneratedPage(\n              resolvedIssueTemplates,\n              collectIssueTemplateRecipeStubs(\n                this.activeBundles,\n                resolveIssueDefaults(this.options.issueDefaults),\n              ),\n            ).split(\"\\n\"),\n          },\n        );\n      }\n    }\n\n    // Validate the temporal-framing convention. Empty path entries\n    // and non-positive cadences fail the build before rendering so\n    // agents never ship with a malformed temporal-framing contract.\n    // The optional lint script is emitted here when the consumer\n    // opts in via `emitChecker: true` — keeping the emission next to\n    // validation keeps every temporal-framing side-effect in one\n    // place.\n    const resolvedTemporalFraming = validateTemporalFramingConfig(\n      this.options.temporalFraming,\n    );\n    if (\n      resolvedTemporalFraming.enabled &&\n      resolvedTemporalFraming.emitChecker\n    ) {\n      new TextFile(this, \".claude/procedures/check-temporal-framing.sh\", {\n        lines: renderTemporalFramingCheckerScript(\n          resolvedTemporalFraming,\n        ).split(\"\\n\"),\n        executable: true,\n      });\n    }\n\n    const platforms = this.resolvePlatforms();\n    const rules = this.resolveRules();\n    const skills = this.resolveSkills();\n    const subAgents = this.resolveSubAgents();\n    const procedures = this.resolveProcedures();\n    const commands = this.resolveCommands();\n    const mcpServers = this.options.mcpServers ?? {};\n\n    // Resolve template variables in rule content, skill instructions, and\n    // sub-agent prompts using ProjectMetadata (if available).\n    const projectMetadata = ProjectMetadata.of(this.project);\n    const metadata = projectMetadata?.metadata;\n    const resolvedRules = this.resolveTemplates(rules, metadata);\n    const resolvedSkills = this.resolveSkillTemplates(skills, metadata);\n    const resolvedSubAgents = this.resolveSubAgentTemplates(\n      subAgents,\n      metadata,\n    );\n    const resolvedProcedures = this.resolveProcedureTemplates(\n      procedures,\n      metadata,\n    );\n\n    if (platforms.includes(AGENT_PLATFORM.CURSOR)) {\n      CursorRenderer.render(\n        this,\n        resolvedRules,\n        resolvedSkills,\n        resolvedSubAgents,\n        mcpServers,\n        this.options.cursorSettings,\n      );\n    }\n\n    if (platforms.includes(AGENT_PLATFORM.CLAUDE)) {\n      const bundlePermissions = this.resolveBundlePermissions();\n      ClaudeRenderer.render(\n        this,\n        resolvedRules,\n        resolvedSkills,\n        resolvedSubAgents,\n        mcpServers,\n        AgentConfig.mergeClaudeDefaults(\n          this.options.claudeSettings,\n          bundlePermissions,\n        ),\n        resolvedProcedures,\n        commands,\n      );\n    }\n\n    if (platforms.includes(AGENT_PLATFORM.CODEX)) {\n      CodexRenderer.render(\n        this,\n        resolvedRules,\n        resolvedSkills,\n        resolvedSubAgents,\n      );\n    }\n\n    if (platforms.includes(AGENT_PLATFORM.COPILOT)) {\n      CopilotRenderer.render(\n        this,\n        resolvedRules,\n        resolvedSkills,\n        resolvedSubAgents,\n      );\n    }\n  }\n\n  private resolvePlatforms(): ReadonlyArray<AgentPlatform> {\n    return (\n      this.options.platforms ?? [AGENT_PLATFORM.CURSOR, AGENT_PLATFORM.CLAUDE]\n    );\n  }\n\n  private resolveRules(): AgentRule[] {\n    const ruleMap = new Map<string, AgentRule>();\n\n    // 1. Auto-detected bundle rules\n    if (this.options.autoDetectBundles !== false) {\n      for (const bundle of this.pathAwareBundles) {\n        if (this.options.excludeBundles?.includes(bundle.name)) continue;\n        if (bundle.name === \"base\" && this.options.includeBaseRules === false) {\n          continue;\n        }\n        if (bundle.appliesWhen(this.project)) {\n          for (const rule of this.bundleRulesFor(bundle)) {\n            ruleMap.set(rule.name, rule);\n          }\n        }\n      }\n    }\n\n    // 2. Force-included bundles\n    if (this.options.includeBundles) {\n      for (const bundleName of this.options.includeBundles) {\n        const bundle = this.pathAwareBundles.find((b) => b.name === bundleName);\n        if (bundle) {\n          for (const rule of this.bundleRulesFor(bundle)) {\n            ruleMap.set(rule.name, rule);\n          }\n        }\n      }\n    }\n\n    // 3. Custom rules (override bundle rules with same name)\n    if (this.options.rules) {\n      for (const rule of this.options.rules) {\n        ruleMap.set(rule.name, rule);\n      }\n    }\n\n    // 4. Remove excluded rules\n    if (this.options.excludeRules) {\n      for (const name of this.options.excludeRules) {\n        ruleMap.delete(name);\n      }\n    }\n\n    // 5. Apply rule extensions (append content to existing rules)\n    if (this.options.ruleExtensions) {\n      for (const [name, extra] of Object.entries(this.options.ruleExtensions)) {\n        const existing = ruleMap.get(name);\n        if (existing) {\n          ruleMap.set(name, {\n            ...existing,\n            content: `${existing.content}\\n\\n---\\n\\n${extra}`,\n          });\n        }\n      }\n    }\n\n    // 5a. Apply additional rule paths (append filePatterns globs to\n    // existing FILE_PATTERN-scoped rules). Silently no-op for\n    // ALWAYS-scoped rules — see AgentConfigOptions.additionalRulePaths.\n    if (this.options.additionalRulePaths) {\n      for (const [name, extraPaths] of Object.entries(\n        this.options.additionalRulePaths,\n      )) {\n        if (extraPaths.length === 0) continue;\n        const existing = ruleMap.get(name);\n        if (!existing) continue;\n        if (existing.scope !== AGENT_RULE_SCOPE.FILE_PATTERN) continue;\n        ruleMap.set(name, {\n          ...existing,\n          filePatterns: [...(existing.filePatterns ?? []), ...extraPaths],\n        });\n      }\n    }\n\n    // 5b. Append project-specific priority rules to issue-label-conventions\n    if (this.options.priorityRules && this.options.priorityRules.length > 0) {\n      const issueLabelRule = ruleMap.get(\"issue-label-conventions\");\n      if (issueLabelRule) {\n        const section = renderPriorityRulesSection(this.options.priorityRules);\n        ruleMap.set(\"issue-label-conventions\", {\n          ...issueLabelRule,\n          content: `${issueLabelRule.content}\\n\\n---\\n\\n${section}`,\n        });\n      }\n    }\n\n    // 5c. Append focus-scoring section to issue-label-conventions\n    if (this.options.focus) {\n      const issueLabelRule = ruleMap.get(\"issue-label-conventions\");\n      if (issueLabelRule) {\n        const section = renderFocusSection(this.options.focus);\n        if (section.length > 0) {\n          ruleMap.set(\"issue-label-conventions\", {\n            ...issueLabelRule,\n            content: `${issueLabelRule.content}\\n\\n---\\n\\n${section}`,\n          });\n        }\n      }\n    }\n\n    // 5d. Append meeting-type / area sections to\n    // meeting-processing-workflow. The workflow rule itself is\n    // excluded from the Claude platform output post-Batch-5 (the\n    // routing summary lives in the shared agent-registry rule),\n    // but the rule object is still mutated here so Cursor mode\n    // continues to ship the meetings taxonomy. The standalone\n    // `meetings-taxonomy` rule wired below picks up the same\n    // section so CLAUDE.md keeps the consumer-supplied taxonomy\n    // visible.\n    if (this.options.meetings) {\n      const meetingRule = ruleMap.get(\"meeting-processing-workflow\");\n      if (meetingRule) {\n        const section = renderMeetingTypesSection(this.options.meetings);\n        if (section.length > 0) {\n          ruleMap.set(\"meeting-processing-workflow\", {\n            ...meetingRule,\n            content: `${meetingRule.content}\\n\\n---\\n\\n${section}`,\n          });\n        }\n      }\n    }\n\n    // NOTE: the `orchestrator-conventions`, `progress-file-convention`,\n    // `shared-editing-safety`, `skill-evals`,\n    // `issue-templates-convention`, and `temporal-framing-convention`\n    // rules are **config-driven**: their bodies are rendered from the\n    // consumer's resolved config. That rendering happens in the owning\n    // bundle factory (see `resolvedRuleConventions` above), *before*\n    // the rule map is seeded — never here.\n    //\n    // Do not add a late \"rewrite rule X from resolved config\" pass to\n    // this method. Every pass below step 3 runs after custom rules\n    // (step 3) and rule extensions (step 5) have already been merged,\n    // so a wholesale content replacement discards them: that is\n    // exactly how `ruleExtensions[\"orchestrator-conventions\"]` came to\n    // be silently dropped for any consumer who also set `scopeGate`.\n    // Composition passes that *append* to a rule are fine — the\n    // per-bundle convention hooks below are the canonical example.\n    const excludedBundleNames = this.options.excludeBundles ?? [];\n\n    // 5d2.5. Resolve the CLAUDE.md `injectBundleHooks` knob once for\n    // the four hook-injection passes below. When the consumer opts\n    // out (`claudeMd: { injectBundleHooks: false }`), each loop is\n    // skipped and the per-bundle \"see also\" subsections are dropped\n    // from every `<bundle>-workflow` rule. The convention rules\n    // themselves still render unconditionally as standalone CLAUDE.md\n    // sections — only the duplicated per-bundle stubs go away.\n    const injectBundleHooks = this.options.claudeMd?.injectBundleHooks ?? true;\n\n    // 5d3. Inject a short \"Progress File\" hook section into every\n    // phased-agent bundle rule that references the convention. The\n    // `progress-file-convention` rule itself is already rendered from\n    // the consumer's resolved config by the base bundle. The hook is\n    // injected whenever the convention is enabled so every phased\n    // agent renders the reminder in its own workflow rule.\n    const resolvedProgressFiles = resolveProgressFiles(\n      this.options.progressFiles,\n    );\n    if (injectBundleHooks && resolvedProgressFiles.enabled) {\n      for (const [ruleName, label] of PROGRESS_FILE_BUNDLE_HOOKS) {\n        const existing = ruleMap.get(ruleName);\n        if (!existing) {\n          continue;\n        }\n        const hook = renderProgressFilesBundleHook(\n          resolvedProgressFiles,\n          label,\n        );\n        if (hook.length === 0) {\n          continue;\n        }\n        ruleMap.set(ruleName, {\n          ...existing,\n          content: `${existing.content}\\n\\n---\\n\\n${hook}`,\n        });\n      }\n    }\n\n    // 5d4. Inject a short \"Shared Index Editing\" hook section into\n    // every phased-agent bundle rule that writes rows to a shared\n    // registry or feature-matrix file. The `shared-editing-safety`\n    // rule itself is already rendered from the consumer's resolved\n    // config by the base bundle.\n    const resolvedSharedEditingForRules = resolveSharedEditing(\n      this.options.sharedEditing,\n    );\n    if (injectBundleHooks && resolvedSharedEditingForRules.enabled) {\n      for (const [ruleName, label] of SHARED_EDITING_BUNDLE_HOOKS) {\n        const existing = ruleMap.get(ruleName);\n        if (!existing) {\n          continue;\n        }\n        const hook = renderSharedEditingBundleHook(\n          resolvedSharedEditingForRules,\n          label,\n        );\n        if (hook.length === 0) {\n          continue;\n        }\n        ruleMap.set(ruleName, {\n          ...existing,\n          content: `${existing.content}\\n\\n---\\n\\n${hook}`,\n        });\n      }\n    }\n\n    // 5d5. Inject a short \"Skill Evals\" hook section into every\n    // skill-owning bundle rule that ships a prompt-driven skill. The\n    // `skill-evals` rule itself is already rendered from the\n    // consumer's resolved config by the base bundle.\n    const resolvedSkillEvalsForRules = resolveSkillEvals(\n      this.options.skillEvals,\n    );\n    if (injectBundleHooks && resolvedSkillEvalsForRules.enabled) {\n      for (const [ruleName, label] of SKILL_EVALS_BUNDLE_HOOKS) {\n        const existing = ruleMap.get(ruleName);\n        if (!existing) {\n          continue;\n        }\n        const hook = renderSkillEvalsBundleHook(\n          resolvedSkillEvalsForRules,\n          label,\n        );\n        if (hook.length === 0) {\n          continue;\n        }\n        ruleMap.set(ruleName, {\n          ...existing,\n          content: `${existing.content}\\n\\n---\\n\\n${hook}`,\n        });\n      }\n    }\n\n    // 5d7. Inject a short \"Issue Templates\" hook section into every\n    // phased-agent bundle rule whose workflow dispatches downstream\n    // issues. The `issue-templates-convention` rule itself is already\n    // rendered from the consumer's resolved config by the base bundle\n    // — including the disabled-stub variant it falls back to once\n    // every downstream-issue-kind bundle has been excluded.\n    const resolvedIssueTemplatesForRules = resolveIssueTemplates(\n      this.options.issueTemplates,\n    );\n    const hasDownstreamBundles =\n      hasAnyDownstreamIssueKindBundle(excludedBundleNames);\n    if (\n      injectBundleHooks &&\n      resolvedIssueTemplatesForRules.enabled &&\n      hasDownstreamBundles\n    ) {\n      for (const [ruleName, label] of ISSUE_TEMPLATES_BUNDLE_HOOKS) {\n        const existing = ruleMap.get(ruleName);\n        if (!existing) {\n          continue;\n        }\n        const hook = renderIssueTemplatesBundleHook(\n          resolvedIssueTemplatesForRules,\n          label,\n        );\n        if (hook.length === 0) {\n          continue;\n        }\n        ruleMap.set(ruleName, {\n          ...existing,\n          content: `${existing.content}\\n\\n---\\n\\n${hook}`,\n        });\n      }\n    }\n\n    // 5d8. (The `temporal-framing-convention` rule is rendered from\n    // the consumer's resolved config by the base bundle; it has no\n    // per-bundle hook, so nothing is done here.)\n\n    // 5e. Gate the base bundle's `source-quality-verification` rule\n    // behind `features.sourceTierExamples`. When the feature is absent\n    // or every tier array is empty, drop the rule entirely so\n    // pure-infra / CDK-only repos that never produce research don't\n    // ship an empty tier stub. When the feature is active, inject the\n    // consumer-supplied examples under the T1–T4 headings.\n    const tierExamples = this.options.features?.sourceTierExamples;\n    if (AgentConfig.hasActiveTierExamples(tierExamples)) {\n      const sourceRule = ruleMap.get(\"source-quality-verification\");\n      if (sourceRule) {\n        const updated = renderSourceTierExamples(\n          sourceRule.content,\n          tierExamples,\n        );\n        if (updated !== sourceRule.content) {\n          ruleMap.set(\"source-quality-verification\", {\n            ...sourceRule,\n            content: updated,\n          });\n        }\n      }\n    } else {\n      ruleMap.delete(\"source-quality-verification\");\n    }\n\n    // 5f. Gate the upstream-configulator-docs bundle behind\n    // `upstreamConfigulator.enabled`. The bundle ships **enabled** by\n    // default so every consumer of `@codedrifters/configulator`\n    // carries the upstream pointers; non-CodeDrifters consumers opt\n    // out by setting `upstreamConfigulator.enabled = false`, at which\n    // point every rule whose name starts with\n    // `upstream-configulator-docs` is filtered out of the resolved set.\n    if (this.options.upstreamConfigulator?.enabled === false) {\n      for (const ruleName of [...ruleMap.keys()]) {\n        if (ruleName.startsWith(\"upstream-configulator-docs\")) {\n          ruleMap.delete(ruleName);\n        }\n      }\n    }\n\n    // 5g. Consolidate per-bundle workflow rules into a single\n    // shared `agent-registry` rule. The registry renders one\n    // alphabetical row per phased-agent bundle (skill, agent,\n    // bundle, output path, purpose) so the routing signal stays\n    // ALWAYS-scoped without 18 prose summaries each duplicating\n    // the same handful of facts. Each `<bundle>-workflow` rule\n    // is left in the rule map (so Cursor mode still sees it) but\n    // marked `platforms.claude.exclude = true` so the Claude\n    // platform output skips it. The convention rules at the top\n    // of CLAUDE.md (Progress File, Shared-Editing Safety, Issue\n    // Templates, Skill Evals) are unaffected.\n    const registryRule = buildAgentRegistryRule(\n      this.activeBundles,\n      this.resolvedPaths,\n    );\n    if (registryRule) {\n      // When the consumer supplies a `meetings` config AND the\n      // meeting-analysis bundle is active, append the resolved\n      // meeting-type / area subsections to the registry rule so\n      // the consumer-supplied taxonomy stays visible in CLAUDE.md.\n      // The same subsections are also injected into\n      // `meeting-processing-workflow` above so Cursor mode (which\n      // still renders that rule) sees the taxonomy. Excluding\n      // meeting-analysis drops the registry's meetings appendix\n      // because the taxonomy has nothing to reference.\n      let registryContent = registryRule.content;\n      const meetingAnalysisActive = this.activeBundles.some(\n        (b) => b.name === \"meeting-analysis\",\n      );\n      if (this.options.meetings && meetingAnalysisActive) {\n        const meetingsSection = renderMeetingTypesSection(\n          this.options.meetings,\n        );\n        if (meetingsSection.length > 0) {\n          registryContent = `${registryContent}\\n\\n---\\n\\n${meetingsSection}`;\n        }\n      }\n      ruleMap.set(registryRule.name, {\n        ...registryRule,\n        content: registryContent,\n      });\n\n      // Bundle names that the consumer has targeted with one or\n      // more `features.customDocSections` entries. Their workflow\n      // rules carry consumer-supplied prose that the registry\n      // table cannot capture, so they keep rendering to CLAUDE.md.\n      // The registry row still appears for them — consumers see\n      // the routing summary AND the per-bundle custom section.\n      const customSectionBundles = new Set(\n        (this.options.features?.customDocSections ?? []).map(\n          (s) => s.bundleName,\n        ),\n      );\n\n      for (const [ruleName, rule] of ruleMap) {\n        if (!isSuppressedWorkflowRule(ruleName)) {\n          continue;\n        }\n        // Workflow rules whose owning bundle carries a\n        // customDocSection injection stay visible in CLAUDE.md\n        // — the consumer-supplied prose has nowhere else to go.\n        const owningBundleName = bundleNameForWorkflowRule(ruleName);\n        if (\n          owningBundleName !== undefined &&\n          customSectionBundles.has(owningBundleName)\n        ) {\n          continue;\n        }\n        const existingClaude = rule.platforms?.claude ?? {};\n        if (existingClaude.exclude === true) {\n          continue;\n        }\n        ruleMap.set(ruleName, {\n          ...rule,\n          platforms: {\n            ...rule.platforms,\n            claude: { ...existingClaude, exclude: true },\n          },\n        });\n      }\n    }\n\n    // 5h. Build the ALWAYS-scoped `conventions-registry` rule from\n    // the final, post-transform rule map. The registry renders one\n    // row per FILE_PATTERN-scoped rule (slug, file patterns,\n    // description) so the Claude session sees a routing table back\n    // into the full convention set even when its current file does\n    // not match any rule's `paths:`. Built last so suppressed\n    // workflow rules and customised content from earlier transforms\n    // are reflected in the rendered table.\n    const conventionsRegistryRule = buildConventionsRegistryRule(\n      ruleMap.values(),\n    );\n    if (conventionsRegistryRule) {\n      ruleMap.set(conventionsRegistryRule.name, conventionsRegistryRule);\n    }\n\n    // 6. Sort: project-overview first, then by first tag (alphabetical), then by name\n    return [...ruleMap.values()].sort((a, b) => {\n      if (a.name === \"project-overview\") return -1;\n      if (b.name === \"project-overview\") return 1;\n\n      const tagA = a.tags?.[0] ?? \"\\uffff\";\n      const tagB = b.tags?.[0] ?? \"\\uffff\";\n      if (tagA !== tagB) return tagA.localeCompare(tagB);\n\n      return a.name.localeCompare(b.name);\n    });\n  }\n\n  /**\n   * Return a bundle's rules with `filePatterns` narrowed to the projects\n   * that actually matched the bundle's detection predicate (when the bundle\n   * provides `findApplicableProjects`) and any project-specified\n   * `features.customDocSections` entries injected into the matching rule\n   * content. Rules with `ALWAYS` scope and rules on bundles that don't\n   * implement the hook are returned with only the custom-section\n   * transformation (if any) applied.\n   */\n  private bundleRulesFor(bundle: AgentRuleBundle): ReadonlyArray<AgentRule> {\n    const customSections = this.options.features?.customDocSections ?? [];\n    const withCustomSections =\n      customSections.length > 0\n        ? renderCustomDocSections(bundle, customSections)\n        : bundle;\n\n    if (!withCustomSections.findApplicableProjects) {\n      return withCustomSections.rules;\n    }\n    const detected = withCustomSections.findApplicableProjects(this.project);\n    if (detected.length === 0) {\n      return withCustomSections.rules;\n    }\n    const scoped = scopeFilePatternsToProjects(this.project, detected);\n    return withCustomSections.rules.map((rule) =>\n      rule.scope === AGENT_RULE_SCOPE.FILE_PATTERN\n        ? { ...rule, filePatterns: scoped }\n        : rule,\n    );\n  }\n\n  private resolveSkills(): AgentSkill[] {\n    const skillMap = new Map<string, AgentSkill>();\n\n    // 1. Auto-detected bundle skills\n    if (this.options.autoDetectBundles !== false) {\n      for (const bundle of this.pathAwareBundles) {\n        if (this.options.excludeBundles?.includes(bundle.name)) continue;\n        if (bundle.appliesWhen(this.project) && bundle.skills) {\n          for (const skill of bundle.skills) {\n            skillMap.set(skill.name, skill);\n          }\n        }\n      }\n    }\n\n    // 2. Force-included bundle skills\n    if (this.options.includeBundles) {\n      for (const bundleName of this.options.includeBundles) {\n        const bundle = this.pathAwareBundles.find((b) => b.name === bundleName);\n        if (bundle?.skills) {\n          for (const skill of bundle.skills) {\n            skillMap.set(skill.name, skill);\n          }\n        }\n      }\n    }\n\n    // 3. Custom skills (override)\n    if (this.options.skills) {\n      for (const skill of this.options.skills) {\n        skillMap.set(skill.name, skill);\n      }\n    }\n\n    return [...skillMap.values()];\n  }\n\n  private resolveSubAgents(): AgentSubAgent[] {\n    const agentMap = new Map<string, AgentSubAgent>();\n\n    // 1. Auto-detected bundle sub-agents\n    if (this.options.autoDetectBundles !== false) {\n      for (const bundle of this.pathAwareBundles) {\n        if (this.options.excludeBundles?.includes(bundle.name)) continue;\n        if (bundle.appliesWhen(this.project) && bundle.subAgents) {\n          for (const agent of bundle.subAgents) {\n            agentMap.set(agent.name, agent);\n          }\n        }\n      }\n    }\n\n    // 2. Force-included bundle sub-agents\n    if (this.options.includeBundles) {\n      for (const bundleName of this.options.includeBundles) {\n        const bundle = this.pathAwareBundles.find((b) => b.name === bundleName);\n        if (bundle?.subAgents) {\n          for (const agent of bundle.subAgents) {\n            agentMap.set(agent.name, agent);\n          }\n        }\n      }\n    }\n\n    // 3. Custom sub-agents (override)\n    if (this.options.subAgents) {\n      for (const agent of this.options.subAgents) {\n        agentMap.set(agent.name, agent);\n      }\n    }\n\n    return [...agentMap.values()];\n  }\n\n  private resolveProcedures(): AgentProcedure[] {\n    const procMap = new Map<string, AgentProcedure>();\n\n    // 1. Auto-detected bundle procedures\n    if (this.options.autoDetectBundles !== false) {\n      for (const bundle of this.pathAwareBundles) {\n        if (this.options.excludeBundles?.includes(bundle.name)) continue;\n        if (bundle.appliesWhen(this.project) && bundle.procedures) {\n          for (const proc of bundle.procedures) {\n            procMap.set(proc.name, proc);\n          }\n        }\n      }\n    }\n\n    // 2. Force-included bundle procedures\n    if (this.options.includeBundles) {\n      for (const bundleName of this.options.includeBundles) {\n        const bundle = this.pathAwareBundles.find((b) => b.name === bundleName);\n        if (bundle?.procedures) {\n          for (const proc of bundle.procedures) {\n            procMap.set(proc.name, proc);\n          }\n        }\n      }\n    }\n\n    // 3. Custom procedures (override)\n    if (this.options.procedures) {\n      for (const proc of this.options.procedures) {\n        procMap.set(proc.name, proc);\n      }\n    }\n\n    // 4. Rewrite the orchestrator bundle's check-blocked.sh with the\n    // consumer's resolved tier table, scope-gate settings, and\n    // run-ratio settings. The procedure ships with defaults baked in,\n    // so repos that never touch `options.tiers`, `options.scopeGate`,\n    // or `options.runRatio` get the same generated script\n    // byte-for-byte; this step only changes the emitted content when\n    // the consumer overrides one of those configs.\n    if (this.options.tiers || this.options.scopeGate || this.options.runRatio) {\n      const existing = procMap.get(\"check-blocked.sh\");\n      if (existing) {\n        const { procedure } = resolveOrchestratorAssets(\n          this.options.tiers,\n          this.options.scopeGate,\n          this.options.runRatio,\n        );\n        if (procedure.content !== existing.content) {\n          procMap.set(\"check-blocked.sh\", procedure);\n        }\n      }\n    }\n\n    // 4b. Rewrite unblock-dependents.sh with the consumer's resolved\n    // unblock-dependents settings. The procedure ships with defaults\n    // baked in, so repos that never touch `options.unblockDependents`\n    // see the same generated script byte-for-byte; this step only\n    // changes the emitted content when the consumer overrides the\n    // config.\n    if (this.options.unblockDependents) {\n      const existing = procMap.get(\"unblock-dependents.sh\");\n      if (existing) {\n        const { unblockDependentsProcedure } = resolveOrchestratorAssets(\n          undefined,\n          undefined,\n          undefined,\n          undefined,\n          this.options.unblockDependents,\n        );\n        if (unblockDependentsProcedure.content !== existing.content) {\n          procMap.set(\"unblock-dependents.sh\", unblockDependentsProcedure);\n        }\n      }\n    }\n\n    return [...procMap.values()];\n  }\n\n  /**\n   * Resolves the final list of slash commands by merging bundle-shipped\n   * defaults with consumer-supplied entries. Mirrors {@link resolveSkills}\n   * and {@link resolveSubAgents}: auto-detected bundles contribute first,\n   * force-included bundles overlay, and consumer commands override on\n   * name collision. Names listed in `excludeCommands` are dropped after\n   * the merge so consumers can opt out of a single default without\n   * disabling the whole bundle.\n   */\n  private resolveCommands(): AgentCommand[] {\n    const commandMap = new Map<string, AgentCommand>();\n\n    // 1. Auto-detected bundle commands\n    if (this.options.autoDetectBundles !== false) {\n      for (const bundle of this.pathAwareBundles) {\n        if (this.options.excludeBundles?.includes(bundle.name)) continue;\n        if (bundle.appliesWhen(this.project) && bundle.commands) {\n          for (const command of bundle.commands) {\n            commandMap.set(command.name, command);\n          }\n        }\n      }\n    }\n\n    // 2. Force-included bundle commands\n    if (this.options.includeBundles) {\n      for (const bundleName of this.options.includeBundles) {\n        const bundle = this.pathAwareBundles.find((b) => b.name === bundleName);\n        if (bundle?.commands) {\n          for (const command of bundle.commands) {\n            commandMap.set(command.name, command);\n          }\n        }\n      }\n    }\n\n    // 3. Custom commands (override bundle commands with same name)\n    if (this.options.commands) {\n      for (const command of this.options.commands) {\n        commandMap.set(command.name, command);\n      }\n    }\n\n    // 4. Drop entries the consumer has explicitly excluded by name. This\n    // runs last so a consumer override followed by an exclusion still\n    // results in the command being dropped — predictable shadowing.\n    if (this.options.excludeCommands) {\n      for (const name of this.options.excludeCommands) {\n        commandMap.delete(name);\n      }\n    }\n\n    return [...commandMap.values()];\n  }\n\n  /**\n   * Resolves template variables in rule content using project metadata.\n   * Emits synthesis warnings for rules with unresolved variables.\n   */\n  private resolveTemplates(\n    rules: ReadonlyArray<AgentRule>,\n    metadata: ResolvedProjectMetadata | undefined,\n  ): ReadonlyArray<AgentRule> {\n    return rules.map((rule) => {\n      const { resolved, unresolvedKeys } = resolveTemplateVariables(\n        rule.content,\n        metadata,\n      );\n      if (unresolvedKeys.length > 0) {\n        this.project.logger.warn(\n          `AgentConfig: ProjectMetadata not found; rule '${rule.name}' using default values`,\n        );\n      }\n      return resolved !== rule.content ? { ...rule, content: resolved } : rule;\n    });\n  }\n\n  /**\n   * Resolves template variables in skill instructions using project metadata,\n   * then appends any matching `skillExtensions` content after a horizontal\n   * rule. Unknown keys in `skillExtensions` are silently ignored, mirroring\n   * the `ruleExtensions` contract.\n   */\n  private resolveSkillTemplates(\n    skills: ReadonlyArray<AgentSkill>,\n    metadata: ResolvedProjectMetadata | undefined,\n  ): ReadonlyArray<AgentSkill> {\n    const extensions = this.options.skillExtensions;\n    return skills.map((skill) => {\n      const { resolved, unresolvedKeys } = resolveTemplateVariables(\n        skill.instructions,\n        metadata,\n      );\n      if (unresolvedKeys.length > 0) {\n        this.project.logger.warn(\n          `AgentConfig: ProjectMetadata not found; skill '${skill.name}' using default values`,\n        );\n      }\n      const extra = extensions?.[skill.name];\n      const baseInstructions = resolved;\n      const finalInstructions =\n        extra !== undefined && extra !== \"\"\n          ? `${baseInstructions}\\n\\n---\\n\\n${extra}`\n          : baseInstructions;\n      return finalInstructions !== skill.instructions\n        ? { ...skill, instructions: finalInstructions }\n        : skill;\n    });\n  }\n\n  /**\n   * Resolves template variables in sub-agent prompts using project metadata,\n   * then appends any matching `subAgentExtensions` content after a horizontal\n   * rule. Unknown keys in `subAgentExtensions` are silently ignored,\n   * mirroring the `ruleExtensions` contract.\n   */\n  private resolveSubAgentTemplates(\n    subAgents: ReadonlyArray<AgentSubAgent>,\n    metadata: ResolvedProjectMetadata | undefined,\n  ): ReadonlyArray<AgentSubAgent> {\n    const extensions = this.options.subAgentExtensions;\n    return subAgents.map((agent) => {\n      const { resolved, unresolvedKeys } = resolveTemplateVariables(\n        agent.prompt,\n        metadata,\n      );\n      if (unresolvedKeys.length > 0) {\n        this.project.logger.warn(\n          `AgentConfig: ProjectMetadata not found; sub-agent '${agent.name}' using default values`,\n        );\n      }\n      const extra = extensions?.[agent.name];\n      const basePrompt = resolved;\n      const finalPrompt =\n        extra !== undefined && extra !== \"\"\n          ? `${basePrompt}\\n\\n---\\n\\n${extra}`\n          : basePrompt;\n      return finalPrompt !== agent.prompt\n        ? { ...agent, prompt: finalPrompt }\n        : agent;\n    });\n  }\n\n  /**\n   * Resolves template variables in procedure content using project metadata.\n   */\n  private resolveProcedureTemplates(\n    procedures: ReadonlyArray<AgentProcedure>,\n    metadata: ResolvedProjectMetadata | undefined,\n  ): ReadonlyArray<AgentProcedure> {\n    return procedures.map((proc) => {\n      const { resolved, unresolvedKeys } = resolveTemplateVariables(\n        proc.content,\n        metadata,\n      );\n      if (unresolvedKeys.length > 0) {\n        this.project.logger.warn(\n          `AgentConfig: ProjectMetadata not found; procedure '${proc.name}' using default values`,\n        );\n      }\n      return resolved !== proc.content ? { ...proc, content: resolved } : proc;\n    });\n  }\n\n  /**\n   * Collects Claude permission entries from all active bundles.\n   */\n  private resolveBundlePermissions(): {\n    allow: Array<string>;\n    deny: Array<string>;\n  } {\n    const allow: Array<string> = [];\n    const deny: Array<string> = [];\n\n    if (this.options.autoDetectBundles !== false) {\n      for (const bundle of this.pathAwareBundles) {\n        if (this.options.excludeBundles?.includes(bundle.name)) continue;\n        if (bundle.appliesWhen(this.project) && bundle.claudePermissions) {\n          if (bundle.claudePermissions.allow) {\n            allow.push(...bundle.claudePermissions.allow);\n          }\n          if (bundle.claudePermissions.deny) {\n            deny.push(...bundle.claudePermissions.deny);\n          }\n        }\n      }\n    }\n\n    // Force-included bundles\n    if (this.options.includeBundles) {\n      for (const bundleName of this.options.includeBundles) {\n        const bundle = this.pathAwareBundles.find((b) => b.name === bundleName);\n        if (bundle?.claudePermissions) {\n          if (bundle.claudePermissions.allow) {\n            allow.push(...bundle.claudePermissions.allow);\n          }\n          if (bundle.claudePermissions.deny) {\n            deny.push(...bundle.claudePermissions.deny);\n          }\n        }\n      }\n    }\n\n    return { allow, deny };\n  }\n}\n","/**\n * Defines the scope/activation model for an agent rule.\n * - ALWAYS: Rule is always active regardless of context\n * - FILE_PATTERN: Rule activates when the AI is working on files matching the patterns\n */\nexport const AGENT_RULE_SCOPE = {\n  ALWAYS: \"always\",\n  FILE_PATTERN: \"file-pattern\",\n} as const;\n\nexport type AgentRuleScope =\n  (typeof AGENT_RULE_SCOPE)[keyof typeof AGENT_RULE_SCOPE];\n\n/**\n * Supported AI coding assistant platforms.\n */\nexport const AGENT_PLATFORM = {\n  CURSOR: \"cursor\",\n  CLAUDE: \"claude\",\n  CODEX: \"codex\",\n  COPILOT: \"copilot\",\n} as const;\n\nexport type AgentPlatform =\n  (typeof AGENT_PLATFORM)[keyof typeof AGENT_PLATFORM];\n\n/**\n * Render target for Claude Code rules.\n * - SCOPED_FILE: `.claude/rules/{name}.md` (default — supports paths frontmatter for conditional activation)\n * - AGENTS_MD: AGENTS.md (always-active, shared with Codex)\n * - CLAUDE_MD: CLAUDE.md (always-active, Claude-only content not consumed by other agents)\n */\nexport const CLAUDE_RULE_TARGET = {\n  SCOPED_FILE: \"scoped-file\",\n  AGENTS_MD: \"agents-md\",\n  CLAUDE_MD: \"claude-md\",\n} as const;\n\nexport type ClaudeRuleTarget =\n  (typeof CLAUDE_RULE_TARGET)[keyof typeof CLAUDE_RULE_TARGET];\n\n/**\n * Model selection for sub-agents. Platforms map these to their own model identifiers.\n */\nexport const AGENT_MODEL = {\n  INHERIT: \"inherit\",\n  FAST: \"fast\",\n  BALANCED: \"balanced\",\n  POWERFUL: \"powerful\",\n} as const;\n\nexport type AgentModel = (typeof AGENT_MODEL)[keyof typeof AGENT_MODEL];\n\n/**\n * Maps abstract AGENT_MODEL values to Claude Code model aliases.\n * Returns undefined for \"inherit\" (omit the field entirely).\n * Cursor omits the model field to use its default model selection.\n */\nexport function resolveModelAlias(\n  model: string | undefined,\n): string | undefined {\n  if (!model || model === AGENT_MODEL.INHERIT) {\n    return undefined;\n  }\n  const mapping: Record<string, string> = {\n    [AGENT_MODEL.POWERFUL]: \"opus\",\n    [AGENT_MODEL.BALANCED]: \"sonnet\",\n    [AGENT_MODEL.FAST]: \"haiku\",\n  };\n  return mapping[model] ?? model;\n}\n\n/**\n * MCP server transport type.\n */\nexport const MCP_TRANSPORT = {\n  STDIO: \"stdio\",\n  HTTP: \"http\",\n  SSE: \"sse\",\n} as const;\n\nexport type McpTransport = (typeof MCP_TRANSPORT)[keyof typeof MCP_TRANSPORT];\n\n/**\n * Platform-specific overrides for a rule.\n */\nexport interface AgentPlatformOverrides {\n  /** Cursor-specific overrides */\n  readonly cursor?: {\n    /** Override the description used in Cursor's YAML frontmatter */\n    readonly description?: string;\n    /** Exclude this rule from Cursor output entirely */\n    readonly exclude?: boolean;\n  };\n  /** Claude Code-specific overrides */\n  readonly claude?: {\n    /**\n     * Where to render this rule for Claude Code.\n     * - SCOPED_FILE: `.claude/rules/{name}.md` (default — supports paths frontmatter)\n     * - AGENTS_MD: AGENTS.md (always-active, shared with Codex)\n     * - CLAUDE_MD: CLAUDE.md (always-active, Claude-only)\n     */\n    readonly target?: ClaudeRuleTarget;\n    /** Exclude this rule from Claude Code output entirely */\n    readonly exclude?: boolean;\n  };\n  /** Codex-specific overrides (future) */\n  readonly codex?: {\n    /** Place this rule in a sub-directory AGENTS.md instead of root */\n    readonly directory?: string;\n    /** Exclude this rule from Codex output entirely */\n    readonly exclude?: boolean;\n  };\n  /** Copilot-specific overrides (future) */\n  readonly copilot?: {\n    /** Exclude this rule from Copilot output entirely */\n    readonly exclude?: boolean;\n  };\n}\n\n/**\n * A single agent rule definition, platform-agnostic.\n */\nexport interface AgentRule {\n  /**\n   * Unique identifier for the rule. Used as the filename stem in platforms\n   * that use per-rule files (Cursor, Claude Code, Copilot).\n   * @example 'typescript-conventions'\n   */\n  readonly name: string;\n\n  /**\n   * Human-readable description of the rule's purpose.\n   * Used by Cursor for AI-assisted rule selection.\n   * @example 'TypeScript project patterns and conventions'\n   */\n  readonly description: string;\n\n  /**\n   * Activation scope for this rule.\n   * - AGENT_RULE_SCOPE.ALWAYS: Active in all contexts\n   * - AGENT_RULE_SCOPE.FILE_PATTERN: Active only when working on matching files\n   */\n  readonly scope: AgentRuleScope;\n\n  /**\n   * Glob patterns for conditional activation.\n   * Required when scope is AGENT_RULE_SCOPE.FILE_PATTERN.\n   * @example ['src/**\\/*.ts', 'tests/**\\/*.ts']\n   */\n  readonly filePatterns?: ReadonlyArray<string>;\n\n  /**\n   * The rule content as markdown. This is the platform-agnostic body\n   * that applies equally to all AI assistants.\n   */\n  readonly content: string;\n\n  /**\n   * Optional per-platform overrides. Use sparingly — prefer platform-agnostic content.\n   */\n  readonly platforms?: AgentPlatformOverrides;\n\n  /**\n   * Optional tags for categorizing and ordering rules.\n   * Rules are ordered by tag (alphabetical), then by name within each tag.\n   * @example ['typescript', 'testing', 'workflow']\n   */\n  readonly tags?: ReadonlyArray<string>;\n}\n\n/**\n * A skill definition following the cross-platform Agent Skills specification.\n * Rendered to .claude/skills/ (Claude Code) and .cursor/skills/ (Cursor).\n */\nexport interface AgentSkill {\n  /**\n   * Unique identifier for the skill. Becomes the /slash-command name.\n   * @example 'commit'\n   */\n  readonly name: string;\n\n  /**\n   * Human-readable description. Claude uses this to decide when to auto-invoke.\n   */\n  readonly description: string;\n\n  /**\n   * Multi-line instruction content (markdown). Becomes the SKILL.md body.\n   */\n  readonly instructions: string;\n\n  /**\n   * Optional tool allowlist for this skill.\n   * @example ['Read', 'Bash(npm run *)']\n   */\n  readonly allowedTools?: ReadonlyArray<string>;\n\n  /**\n   * Whether to prevent auto-invocation of this skill.\n   * When true, only triggered by the user typing /skill-name.\n   * @default false\n   */\n  readonly disableModelInvocation?: boolean;\n\n  /**\n   * Whether the user can invoke this skill directly via /skill-name.\n   * Set to false for background skills that should not appear in the / menu.\n   * @default true\n   */\n  readonly userInvocable?: boolean;\n\n  /**\n   * Model override when this skill is active.\n   * @example 'claude-opus-4-6'\n   */\n  readonly model?: string;\n\n  /**\n   * Reasoning effort level when this skill is active.\n   * @example 'high'\n   */\n  readonly effort?: string;\n\n  /**\n   * Glob patterns that limit when the skill is auto-loaded.\n   * @example ['src/api/**\\/*.ts']\n   */\n  readonly paths?: ReadonlyArray<string>;\n\n  /**\n   * Resource directories bundled with the skill (e.g., references/, scripts/, assets/).\n   * Documentation hint only — directory names listed here are not emitted to disk.\n   * Prefer {@link referenceFiles} to ship actual companion file contents.\n   *\n   * @deprecated Use {@link referenceFiles} to emit physical companion files.\n   * @example ['references/', 'scripts/']\n   */\n  readonly references?: ReadonlyArray<string>;\n\n  /**\n   * Companion files shipped alongside the SKILL.md (e.g., templates, references, scripts).\n   * Each entry is rendered as a TextFile under the skill's directory on every\n   * platform that emits skills (Claude: `.claude/skills/{name}/{path}`,\n   * Cursor: `.cursor/skills/{name}/{path}`).\n   *\n   * Use this for skill assets that benefit from being separate files rather than\n   * inlined into the skill instructions — large templates, reference tables,\n   * runnable scripts.\n   *\n   * Per-platform `platforms.{claude,cursor}.exclude` flags suppress reference\n   * files for that platform alongside the SKILL.md.\n   *\n   * @example\n   * ```ts\n   * referenceFiles: [\n   *   { path: '_references/templates/_template-FR.md', content: '# Functional Requirement\\n...' },\n   *   { path: '_references/standards-and-frameworks.md', content: '# Standards\\n...' },\n   * ]\n   * ```\n   */\n  readonly referenceFiles?: ReadonlyArray<{\n    /** Path relative to the skill directory (e.g., `_references/templates/_template-FR.md`). */\n    readonly path: string;\n    /** File contents written verbatim. */\n    readonly content: string;\n  }>;\n\n  /**\n   * Context isolation mode. Set to 'fork' to run in an isolated subagent context.\n   */\n  readonly context?: string;\n\n  /**\n   * Subagent name to delegate to when context is 'fork'.\n   * @example 'code-reviewer'\n   */\n  readonly agent?: string;\n\n  /**\n   * Shell for dynamic context injection via !`command` syntax.\n   * @default 'bash'\n   */\n  readonly shell?: string;\n\n  /** Per-platform overrides. Use `exclude: true` to skip a platform. */\n  readonly platforms?: {\n    readonly claude?: { readonly exclude?: boolean };\n    readonly cursor?: { readonly exclude?: boolean };\n  };\n}\n\n/**\n * Platform-specific overrides for a sub-agent definition.\n */\n/**\n * Copilot handoff definition for sub-agent delegation.\n */\nexport interface CopilotHandoff {\n  /** Display label for the handoff action. */\n  readonly label: string;\n  /** Target agent name. */\n  readonly agent: string;\n  /** Optional prompt to pass to the target agent. */\n  readonly prompt?: string;\n  /** Whether to auto-send the handoff without user confirmation. */\n  readonly send?: boolean;\n}\n\nexport interface AgentSubAgentPlatformOverrides {\n  /** Claude Code-specific overrides */\n  readonly claude?: {\n    /** Permission mode: default, acceptEdits, dontAsk, bypassPermissions, plan */\n    readonly permissionMode?: string;\n    /** Run in isolated git worktree */\n    readonly isolation?: string;\n    /** Run as a background task */\n    readonly background?: boolean;\n    /** Reasoning effort level (Opus): low, medium, high, max */\n    readonly effort?: string;\n    /** Persistent memory scope: user, project, local */\n    readonly memory?: string;\n    /** Exclude this sub-agent from Claude Code output entirely */\n    readonly exclude?: boolean;\n  };\n  /** Cursor-specific overrides */\n  readonly cursor?: {\n    /** Restrict the sub-agent to read-only operations */\n    readonly readonly?: boolean;\n    /** Run the sub-agent asynchronously as a background task */\n    readonly isBackground?: boolean;\n    /** Exclude this sub-agent from Cursor output entirely */\n    readonly exclude?: boolean;\n  };\n  /** Codex-specific overrides (future) */\n  readonly codex?: {\n    /** Sandbox mode: read-only or full */\n    readonly sandboxMode?: string;\n    /** Model reasoning effort */\n    readonly modelReasoningEffort?: string;\n    /** Exclude this sub-agent from Codex output entirely */\n    readonly exclude?: boolean;\n  };\n  /** Copilot-specific overrides (future) */\n  readonly copilot?: {\n    /** Target environment: vscode or github-copilot */\n    readonly target?: string;\n    /** Whether the user can invoke this sub-agent directly */\n    readonly userInvocable?: boolean;\n    /** Prevent auto-invocation of this sub-agent */\n    readonly disableModelInvocation?: boolean;\n    /** Handoff definitions for agent-to-agent delegation */\n    readonly handoffs?: ReadonlyArray<CopilotHandoff>;\n    /** Exclude this sub-agent from Copilot output entirely */\n    readonly exclude?: boolean;\n  };\n}\n\n/**\n * A custom sub-agent definition, platform-agnostic.\n * Rendered to .cursor/agents/ (Cursor), .claude/agents/ (Claude Code).\n */\nexport interface AgentSubAgent {\n  /**\n   * Unique identifier for the sub-agent. Used as the filename stem.\n   * Must be lowercase letters and hyphens only.\n   * @example 'code-reviewer'\n   */\n  readonly name: string;\n\n  /** Human-readable description. Used by the parent agent to decide when to delegate. */\n  readonly description: string;\n\n  /**\n   * System prompt / instructions for the sub-agent (markdown).\n   * This becomes the body of the generated agent file.\n   */\n  readonly prompt: string;\n\n  /**\n   * Model selection for this sub-agent.\n   * @default AGENT_MODEL.INHERIT\n   */\n  readonly model?: AgentModel;\n\n  /**\n   * Tool allowlist. When omitted, inherits all tools from parent.\n   * @example ['Read', 'Glob', 'Grep']\n   */\n  readonly tools?: ReadonlyArray<string>;\n\n  /**\n   * Tool denylist. Applied before the allowlist.\n   * @example ['Bash', 'Write']\n   */\n  readonly disallowedTools?: ReadonlyArray<string>;\n\n  /** Maximum agentic turns before the sub-agent stops. */\n  readonly maxTurns?: number;\n\n  /**\n   * Skills to preload for this sub-agent.\n   * @example ['commit', 'review-pr']\n   */\n  readonly skills?: ReadonlyArray<string>;\n\n  /**\n   * MCP servers available to this sub-agent.\n   * Rendered to the platform-specific sub-agent config.\n   */\n  readonly mcpServers?: Readonly<Record<string, McpServerConfig>>;\n\n  /** Optional per-platform overrides for this sub-agent. */\n  readonly platforms?: AgentSubAgentPlatformOverrides;\n}\n\n/**\n * A user-invokable slash command. Rendered to `.claude/commands/<name>.md`.\n *\n * Slash commands appear in the Claude Code command picker (typed as\n * `/<name>`) and execute the body as the user prompt. The body may\n * reference any rule, skill, sub-agent, or procedure registered via\n * `AgentConfigOptions` — bundle-shipped commands typically delegate to\n * an existing sub-agent or procedure rather than restating its content.\n *\n * @see https://docs.claude.com/en/docs/claude-code/slash-commands\n */\nexport interface AgentCommand {\n  /**\n   * Slash-command name (no leading slash). Lowercase, kebab-case.\n   * Becomes the filename stem under `.claude/commands/`.\n   * @example 'orchestrate'\n   */\n  readonly name: string;\n\n  /**\n   * One-sentence summary shown in the slash-command picker.\n   */\n  readonly description: string;\n\n  /**\n   * Body content (markdown). Rendered as the command file body verbatim,\n   * after the generated YAML frontmatter.\n   */\n  readonly content: string;\n\n  /**\n   * Optional model override for the command's invocation. Maps to a\n   * Claude Code model alias (e.g. `opus`, `sonnet`, `haiku`) via\n   * {@link resolveModelAlias}.\n   */\n  readonly model?: AgentModel;\n}\n\n/**\n * An executable procedure (shell script) that ships with a bundle.\n * Rendered to `.claude/procedures/{name}` as an executable file.\n */\nexport interface AgentProcedure {\n  /**\n   * Filename for the procedure (e.g., 'check-blocked.sh').\n   * Used as the filename in .claude/procedures/.\n   */\n  readonly name: string;\n\n  /** Human-readable description of what this procedure does. */\n  readonly description: string;\n\n  /** Script content as a single string. Lines are split on newlines for rendering. */\n  readonly content: string;\n}\n\n/**\n * MCP server configuration. Cross-platform — rendered to .claude/settings.json\n * (Claude Code) and .cursor/mcp.json (Cursor).\n */\nexport interface McpServerConfig {\n  /**\n   * Transport type for the server connection.\n   * @default MCP_TRANSPORT.STDIO\n   */\n  readonly transport?: McpTransport;\n\n  /** Command to launch a stdio server. */\n  readonly command?: string;\n\n  /** Command arguments for stdio server. */\n  readonly args?: ReadonlyArray<string>;\n\n  /** URL for HTTP/SSE remote servers. */\n  readonly url?: string;\n\n  /** HTTP headers for HTTP/SSE connections. */\n  readonly headers?: Readonly<Record<string, string>>;\n\n  /** Environment variables for the server process. */\n  readonly env?: Readonly<Record<string, string>>;\n\n  /**\n   * Tool allowlist — only these tools from the server will be available.\n   * @example ['read_file', 'search']\n   */\n  readonly enabledTools?: ReadonlyArray<string>;\n\n  /**\n   * Tool denylist — these tools from the server will be blocked.\n   * Applied before enabledTools.\n   * @example ['delete_file', 'execute']\n   */\n  readonly disabledTools?: ReadonlyArray<string>;\n}\n","/**\n * Shared \"Claim verification\" section for every phased worker/analyst\n * bundle (fleet anti-collision — codedrifters/packages#868).\n *\n * Fleet deployments run several orchestrator runners against one shared\n * GitHub queue (staggered scheduled tasks over isolated clones). A bare\n * `status:ready` → `status:in-progress` label flip does not, on its own,\n * guarantee that only one session works an issue: two runners can scan\n * the queue in the same window and both flip the label. The orchestrator\n * closes the common multi-minute window with **claim-at-pick** (it claims\n * the label itself before dispatching); this section is the dispatched\n * agent's **verify-or-claim backstop** for the sub-second residual race.\n *\n * The section is rendered identically into the issue-worker and every\n * phased analyst/writer prompt via {@link renderClaimVerificationSection}\n * so the protocol never drifts between bundles — the same pattern the\n * project-context and progress-file sections use.\n */\n\n/**\n * Greppable HTML-comment tag that anchors the claim-marker comment.\n * Exported so callers (orchestrator claim-at-pick, tests) reference the\n * exact same string the verify query matches on.\n */\nexport const ISSUE_CLAIM_MARKER_TAG = \"<!-- issue-claim -->\";\n\n/**\n * jq filter (for `gh issue view <n> --json comments`) that lists every\n * issue-claim marker in claim order (earliest first, tie-broken on the\n * lowest comment id). The earliest marker is the owner.\n */\nexport const CLAIM_MARKER_LIST_JQ = `[.comments[] | select(.body | contains(\"${ISSUE_CLAIM_MARKER_TAG}\")) | {id, createdAt}] | sort_by(.createdAt, .id)`;\n\n/**\n * Render the shared `## Claim verification` section as prompt lines.\n * Spread into a sub-agent `prompt` array with\n * `...renderClaimVerificationSection()`.\n */\nexport function renderClaimVerificationSection(): ReadonlyArray<string> {\n  return [\n    \"## Claim verification\",\n    \"\",\n    \"Before you create a branch or write any artifacts, verify you own the\",\n    \"claim on the issue. This governs the `status:ready` →\",\n    \"`status:in-progress` transition. In fleet deployments several\",\n    \"orchestrator runners share one GitHub queue, so a bare label flip does\",\n    \"not by itself guarantee you are the only session working the issue —\",\n    \"two runners can scan the queue in the same window and both claim it\",\n    \"(fleet anti-collision).\",\n    \"\",\n    \"### The issue-claim marker\",\n    \"\",\n    \"Ownership is recorded by a single claim-marker comment on the issue.\",\n    \"Whoever claims the issue — the orchestrator at pick time\",\n    \"(claim-at-pick), or you, when you claim an unclaimed issue yourself —\",\n    \"posts exactly one:\",\n    \"\",\n    \"```\",\n    `${ISSUE_CLAIM_MARKER_TAG} Claimed <ISO-8601 UTC> by <claimant> — fleet anti-collision.`,\n    \"```\",\n    \"\",\n    \"The **owner is the earliest** claim marker — the\",\n    `\\`${ISSUE_CLAIM_MARKER_TAG}\\` comment with the lowest \\`createdAt\\``,\n    \"(tie-broken on the lowest comment id). List the markers in claim order\",\n    \"with:\",\n    \"\",\n    \"```bash\",\n    \"gh issue view <n> --json comments \\\\\",\n    `  --jq '${CLAIM_MARKER_LIST_JQ}'`,\n    \"```\",\n    \"\",\n    \"### Verify or claim\",\n    \"\",\n    \"1. **Pre-claimed at pick.** If your dispatch brief says the orchestrator\",\n    \"   already flipped the label (claim-at-pick) and cites the marker it\",\n    \"   posted, confirm that marker is the **earliest** claim marker on the\",\n    \"   issue, then proceed. Do **not** re-add `status:ready` and do **not**\",\n    \"   re-flip the label — the claim is already yours.\",\n    \"2. **Unclaimed (`status:ready`).** Claim it yourself: **first** post the\",\n    `   \\`${ISSUE_CLAIM_MARKER_TAG}\\` marker comment, **then** flip`,\n    \"   `status:ready` → `status:in-progress`. Re-read the markers; proceed\",\n    \"   only if the marker you just posted is the earliest.\",\n    \"3. **Foreign prior claim → back off.** If a claim marker from another\",\n    \"   dispatch is **earlier** than yours — or the issue is already\",\n    \"   `status:in-progress` with a foreign marker and your dispatch brief\",\n    \"   did not claim it for you — a sibling runner owns the issue. **Back\",\n    \"   off cleanly and write no artifacts**: no branch, no files, no PR, and\",\n    \"   no completion or duplicate-output comment. Log\",\n    \"   `CLAIM_CONFLICT #<n> owner=<earliest-marker-id>` and stop the session.\",\n    \"\",\n    \"Backing off on a foreign claim is the analyst-side backstop to the\",\n    \"orchestrator's claim-at-pick guard: claim-at-pick closes the common\",\n    \"multi-minute window between the queue scan and the claim, and this\",\n    \"check absorbs the sub-second residual race where two runners both\",\n    \"scanned before either flipped the label. If you discover a foreign\",\n    \"prior claim **mid-execution** — after you have already begun a phase —\",\n    \"stop immediately and discard the uncommitted work rather than opening a\",\n    \"second PR or writing a duplicate artifact for the issue.\",\n  ];\n}\n","/**\n * Hand-maintained registry mapping every bundle name to the cross-bundle\n * surface it owns: GitHub `type:*` labels, phase-label prefixes,\n * scheduled-task IDs, whether it emits Starlight docs, and whether it\n * declares any downstream issue kinds (i.e. files `gh issue create`\n * recipes via the issue-templates convention).\n *\n * The registry is consulted by renderers in other bundles whenever\n * `AgentConfigOptions.excludeBundles` is non-empty so cross-bundle\n * references to an excluded bundle's agents, type labels, phase labels,\n * or scheduled tasks disappear from the generated output.\n *\n * The map is **hand-maintained** rather than derived from each bundle's\n * runtime shape. The defining surfaces (the funnel-tier table in\n * `tiers.ts`, the per-phase scope-gate overrides in `scope-gate.ts`, and\n * the scheduled-tasks registry in `scheduled-tasks.ts`) live as flat\n * data tables that already get walked by their renderers — declaring the\n * ownership map alongside them keeps the relationship explicit and\n * readable without forcing every bundle to grow an \"ownership\"\n * descriptor.\n *\n * Bundles that ship no cross-bundle surface (e.g. `slack`, `typescript`,\n * `pnpm`, `vitest`, `jest`, `aws-cdk`, `projen`, `turborepo`,\n * `upstream-configulator-docs`) deliberately do not appear here —\n * excluding them is already a no-op since they own nothing other\n * bundles reference.\n */\nexport interface BundleOwnership {\n  /**\n   * GitHub `type:*` label values (without the `type:` prefix) the\n   * bundle owns. The funnel-tier table in `tiers.ts` and any rendered\n   * tables that group agents by `type:*` label consult this list.\n   */\n  readonly typeLabels: ReadonlyArray<string>;\n  /**\n   * Phase-label prefixes (with trailing colon, e.g. `\"company:\"`) the\n   * bundle owns. Used by the scope-gate per-phase override table and\n   * any other renderer that groups by phase label. An entry without a\n   * trailing colon (e.g. `\"req:write\"`) is treated as an exact\n   * phase-label match instead of a prefix.\n   */\n  readonly phaseLabelPrefixes: ReadonlyArray<string>;\n  /**\n   * `taskId` values from `DEFAULT_SCHEDULED_TASK_ENTRIES` that target\n   * this bundle's sub-agent. The scheduled-tasks registry filter in\n   * `agent-config.ts` consults this list when pruning default entries\n   * for an excluded bundle.\n   */\n  readonly scheduledTaskIds: ReadonlyArray<string>;\n  /**\n   * Whether this bundle emits Starlight content roots — i.e. whether\n   * any of its workflows write files under `docs/src/content/docs/`\n   * (or the configured docs root). Drives the auto-suppression of the\n   * `section-index-pages` rule when no docs-emitting bundle is active.\n   */\n  readonly emitsDocs: boolean;\n  /**\n   * Whether this bundle dispatches downstream issues (i.e. its\n   * workflows file `gh issue create` recipes). Drives the\n   * auto-suppression of the `issue-templates-convention` rule when no\n   * such bundle is active.\n   *\n   * Not an exhaustive enumerator of issue-filing bundles. Only bundles\n   * that own a cross-bundle surface appear in {@link BUNDLE_OWNERSHIP}\n   * at all, so a bundle can file issues and still be absent — the\n   * `upstream-configulator-docs` bundle files into a *foreign* repo\n   * (`codedrifters/packages`) and is deliberately not registered.\n   * Treat a `true` here as \"this bundle's phase labels need the\n   * templates convention\", not as \"these are all the filing sites\".\n   */\n  readonly downstreamIssueKinds: boolean;\n}\n\n/**\n * Canonical ownership map. Only bundles that own at least one\n * cross-bundle surface appear here.\n */\nexport const BUNDLE_OWNERSHIP: Readonly<Record<string, BundleOwnership>> = {\n  agenda: {\n    typeLabels: [\"agenda\"],\n    phaseLabelPrefixes: [\"agenda:\"],\n    scheduledTaskIds: [\"worker-agenda\"],\n    emitsDocs: true,\n    downstreamIssueKinds: true,\n  },\n  \"bcm-writer\": {\n    typeLabels: [\"bcm-document\"],\n    phaseLabelPrefixes: [\"bcm:\"],\n    scheduledTaskIds: [\"worker-bcm-writer\"],\n    emitsDocs: true,\n    downstreamIssueKinds: true,\n  },\n  \"business-models\": {\n    typeLabels: [\"business-model\"],\n    phaseLabelPrefixes: [\"business-models:\"],\n    scheduledTaskIds: [\"worker-business-models\"],\n    emitsDocs: true,\n    downstreamIssueKinds: true,\n  },\n  \"company-profile\": {\n    typeLabels: [\"company-profile\"],\n    phaseLabelPrefixes: [\"company:\"],\n    scheduledTaskIds: [\"worker-company-profile\"],\n    emitsDocs: true,\n    downstreamIssueKinds: true,\n  },\n  \"customer-profile\": {\n    typeLabels: [\"customer-profile\"],\n    phaseLabelPrefixes: [\"customer:\"],\n    scheduledTaskIds: [\"worker-customer-profile\"],\n    emitsDocs: true,\n    downstreamIssueKinds: true,\n  },\n  \"docs-sync\": {\n    typeLabels: [\"docs-sync\"],\n    phaseLabelPrefixes: [\"docs-sync:\"],\n    scheduledTaskIds: [\"worker-docs-sync\"],\n    emitsDocs: true,\n    downstreamIssueKinds: true,\n  },\n  \"industry-discovery\": {\n    typeLabels: [\"industry-discovery\"],\n    phaseLabelPrefixes: [\"industry:\"],\n    scheduledTaskIds: [\"worker-industry-discovery\"],\n    emitsDocs: true,\n    downstreamIssueKinds: true,\n  },\n  \"maintenance-audit\": {\n    typeLabels: [\"maintenance\"],\n    phaseLabelPrefixes: [\"maint:\"],\n    scheduledTaskIds: [\"worker-maintenance\"],\n    emitsDocs: false,\n    downstreamIssueKinds: true,\n  },\n  \"meeting-analysis\": {\n    typeLabels: [\"meeting-processing\"],\n    phaseLabelPrefixes: [\"meeting:\"],\n    scheduledTaskIds: [\"worker-meeting-analysis\"],\n    emitsDocs: true,\n    downstreamIssueKinds: true,\n  },\n  orchestrator: {\n    // The orchestrator pipeline manager itself ships with the\n    // `worker-orchestrator` scheduled task. It owns no `type:*` label\n    // (it dispatches every type) and no phase-label prefix.\n    typeLabels: [],\n    phaseLabelPrefixes: [],\n    scheduledTaskIds: [\"worker-orchestrator\"],\n    emitsDocs: false,\n    downstreamIssueKinds: false,\n  },\n  \"people-profile\": {\n    typeLabels: [\"people-profile\"],\n    phaseLabelPrefixes: [\"people:\"],\n    scheduledTaskIds: [\"worker-people-profile\"],\n    emitsDocs: true,\n    downstreamIssueKinds: true,\n  },\n  \"pr-review\": {\n    typeLabels: [\"pr-review\"],\n    phaseLabelPrefixes: [],\n    scheduledTaskIds: [\"worker-pr-review\"],\n    emitsDocs: false,\n    downstreamIssueKinds: false,\n  },\n  \"regulatory-research\": {\n    typeLabels: [\"regulatory-research\"],\n    phaseLabelPrefixes: [\"regulatory:\"],\n    scheduledTaskIds: [\"worker-regulatory-research\"],\n    emitsDocs: true,\n    downstreamIssueKinds: true,\n  },\n  \"requirements-analyst\": {\n    typeLabels: [\"requirement\"],\n    phaseLabelPrefixes: [\"req:\"],\n    scheduledTaskIds: [\"worker-requirements-analyst\"],\n    emitsDocs: true,\n    downstreamIssueKinds: true,\n  },\n  \"requirements-reviewer\": {\n    // Co-owns `type:requirement` with the analyst and writer; owns\n    // the `req:review` and `req:deprecate` phase labels exactly.\n    typeLabels: [\"requirement\"],\n    phaseLabelPrefixes: [\"req:review\", \"req:deprecate\"],\n    scheduledTaskIds: [\"worker-requirements-reviewer\"],\n    emitsDocs: true,\n    downstreamIssueKinds: true,\n  },\n  \"requirements-writer\": {\n    // Co-owns `type:requirement` with the analyst and reviewer; owns\n    // the `req:write` phase label exactly.\n    typeLabels: [\"requirement\"],\n    phaseLabelPrefixes: [\"req:write\"],\n    scheduledTaskIds: [\"worker-requirements-writer\"],\n    emitsDocs: true,\n    downstreamIssueKinds: true,\n  },\n  \"research-pipeline\": {\n    typeLabels: [\"research\"],\n    phaseLabelPrefixes: [\"research:\"],\n    scheduledTaskIds: [\"worker-research\"],\n    emitsDocs: true,\n    downstreamIssueKinds: true,\n  },\n  \"software-profile\": {\n    typeLabels: [\"software-profile\"],\n    phaseLabelPrefixes: [\"software:\"],\n    scheduledTaskIds: [\"worker-software-profile\"],\n    emitsDocs: true,\n    downstreamIssueKinds: true,\n  },\n  \"standards-research\": {\n    typeLabels: [\"standards-research\"],\n    phaseLabelPrefixes: [\"standards:\"],\n    scheduledTaskIds: [\"worker-standards-research\"],\n    emitsDocs: true,\n    downstreamIssueKinds: true,\n  },\n};\n\n/**\n * GitHub `type:*` labels (WITH the `type:` prefix) that come from the\n * **conventional-commit** vocabulary rather than the bundle/routing\n * vocabulary. These are derived from an issue's title prefix by the\n * generic create-issue workflow (`feat:` → `type:feat`, `docs:` →\n * `type:docs`, …) and are the only `type:*` labels the phase-label\n * invariant is allowed to remove when it corrects a mislabeled issue.\n *\n * A bundle `type:*` label (e.g. `type:research`, `type:bcm-document`)\n * is deliberately **not** in this set: an issue carrying a phase label\n * from one bundle plus a `type:*` label owned by a *different* bundle\n * is genuinely ambiguous and gets flagged for a human rather than\n * silently rewritten.\n */\nexport const CONVENTIONAL_COMMIT_TYPE_LABELS: ReadonlyArray<string> = [\n  \"type:chore\",\n  \"type:docs\",\n  \"type:feat\",\n  \"type:fix\",\n  \"type:hotfix\",\n  \"type:refactor\",\n  \"type:release\",\n];\n\n/**\n * Canonical phase-label matcher → `type:<bundle>` label map, derived\n * from {@link BUNDLE_OWNERSHIP}. This is the **single source of truth**\n * for the phase-label → type-label invariant: label registry\n * generation, the orchestrator's triage sweep, and the consumer-facing\n * label audit all read this map rather than re-deriving the pairing.\n *\n * Keys are matchers in the same notation `BundleOwnership.phaseLabelPrefixes`\n * uses — an entry ending in a colon (`\"company:\"`) is a prefix match,\n * an entry without one (`\"req:write\"`) is an exact match. Values carry\n * the `type:` prefix.\n *\n * Co-ownership is fine as long as the co-owners agree on the type\n * label: all three requirements bundles declare `type:requirement`, so\n * `req:`, `req:write`, `req:review`, and `req:deprecate` all resolve to\n * the same value. A matcher that resolved to two *different* type\n * labels would be a registry bug and throws at module load.\n */\nexport const PHASE_LABEL_TYPE_MAP: Readonly<Record<string, string>> =\n  buildPhaseLabelTypeMap();\n\n/**\n * Outcome of resolving a set of issue labels against\n * {@link PHASE_LABEL_TYPE_MAP}.\n *\n * - `\"none\"` — the labels carry no **recognised** phase label, so the\n *   invariant does not apply. Unrecognised `foo:bar` labels are\n *   consumer-specific and deliberately not policed.\n * - `\"match\"` — the recognised phase labels all imply one and the same\n *   `type:<bundle>` label, carried in `typeLabel`.\n * - `\"ambiguous\"` — the recognised phase labels imply two or more\n *   different `type:<bundle>` labels. Never auto-corrected; the caller\n *   flags the issue for human triage instead.\n */\nexport type PhaseLabelTypeOutcome = \"none\" | \"match\" | \"ambiguous\";\n\n/** Result of {@link resolveTypeLabelForLabels}. */\nexport interface PhaseLabelTypeResolution {\n  /** Which of the three outcomes applies. */\n  readonly outcome: PhaseLabelTypeOutcome;\n  /**\n   * The single implied `type:<bundle>` label (with the `type:` prefix)\n   * when `outcome` is `\"match\"`; `undefined` otherwise.\n   */\n  readonly typeLabel?: string;\n  /**\n   * Every distinct implied `type:<bundle>` label, sorted. Empty on\n   * `\"none\"`, one entry on `\"match\"`, two or more on `\"ambiguous\"`.\n   */\n  readonly candidateTypeLabels: ReadonlyArray<string>;\n  /**\n   * The subset of the input labels that matched a phase-label matcher,\n   * in input order. Empty on `\"none\"`.\n   */\n  readonly phaseLabels: ReadonlyArray<string>;\n}\n\n/**\n * Resolve a single phase label to the `type:<bundle>` label its owning\n * bundle declares, or `undefined` when no bundle owns it.\n *\n * Exact-match entries beat prefix entries: `req:write` is owned by\n * `requirements-writer` while the `req:` prefix is owned by\n * `requirements-analyst`. (Both currently declare `type:requirement`,\n * but the precedence is load-bearing for any future divergence.)\n */\nexport function typeLabelForPhaseLabel(phaseLabel: string): string | undefined {\n  const exact = PHASE_LABEL_TYPE_MAP[phaseLabel];\n  if (exact !== undefined && !phaseLabel.endsWith(\":\")) {\n    return exact;\n  }\n  let bestMatcher: string | undefined;\n  for (const matcher of Object.keys(PHASE_LABEL_TYPE_MAP)) {\n    if (!matcher.endsWith(\":\")) {\n      continue;\n    }\n    if (!phaseLabel.startsWith(matcher)) {\n      continue;\n    }\n    // Longest prefix wins so a future `req:sub:` never loses to `req:`.\n    if (bestMatcher === undefined || matcher.length > bestMatcher.length) {\n      bestMatcher = matcher;\n    }\n  }\n  return bestMatcher === undefined\n    ? undefined\n    : PHASE_LABEL_TYPE_MAP[bestMatcher];\n}\n\n/**\n * Resolve every label on an issue to the `type:<bundle>` label the\n * phase-label invariant requires it to carry.\n *\n * The input is the issue's **full** label list — the resolver picks out\n * the recognised phase labels itself and ignores everything else\n * (`status:*`, `priority:*`, existing `type:*`, and any consumer label\n * that matches no bundle).\n */\nexport function resolveTypeLabelForLabels(\n  labels: ReadonlyArray<string>,\n): PhaseLabelTypeResolution {\n  const phaseLabels: Array<string> = [];\n  const candidates = new Set<string>();\n  for (const label of labels) {\n    const typeLabel = typeLabelForPhaseLabel(label);\n    if (typeLabel === undefined) {\n      continue;\n    }\n    phaseLabels.push(label);\n    candidates.add(typeLabel);\n  }\n  const candidateTypeLabels = Array.from(candidates).sort();\n  if (candidateTypeLabels.length === 0) {\n    return { outcome: \"none\", candidateTypeLabels: [], phaseLabels: [] };\n  }\n  if (candidateTypeLabels.length === 1) {\n    return {\n      outcome: \"match\",\n      typeLabel: candidateTypeLabels[0],\n      candidateTypeLabels,\n      phaseLabels,\n    };\n  }\n  return { outcome: \"ambiguous\", candidateTypeLabels, phaseLabels };\n}\n\n/**\n * Render the **Phase-label → `type:<bundle>` invariant** section of the\n * `orchestrator-conventions` rule. The matcher table is generated from\n * {@link PHASE_LABEL_TYPE_MAP}, so the documented pairing can never\n * drift from the pairing the sweep enforces.\n *\n * Rows whose owning bundle appears in `excludeBundles` are dropped,\n * matching every other cross-bundle renderer.\n */\nexport function renderPhaseTypeInvariantSection(\n  excludeBundles: ReadonlyArray<string> = [],\n): string {\n  const rows = Object.keys(PHASE_LABEL_TYPE_MAP)\n    .filter(\n      (matcher) => !isPhaseLabelMatcherOwnedByExcluded(matcher, excludeBundles),\n    )\n    .sort()\n    .map((matcher) => {\n      const display = matcher.endsWith(\":\") ? `${matcher}*` : matcher;\n      const kind = matcher.endsWith(\":\") ? \"prefix\" : \"exact\";\n      return `| \\`${display}\\` | ${kind} | \\`${PHASE_LABEL_TYPE_MAP[matcher]}\\` |`;\n    });\n\n  return [\n    \"## Phase-label → `type:<bundle>` invariant\",\n    \"\",\n    \"Every phased-pipeline bundle pairs its `<bundle>:<phase>` labels\",\n    \"with exactly one `type:<bundle>` label. That type label is the\",\n    \"**dedup + dispatch signal**: agents de-duplicate downstream work\",\n    'with `gh issue list --label \"type:<bundle>\"`, and Phase E derives',\n    \"its funnel-tier sort key from the issue's `type:*` label. An issue\",\n    \"that carries the phase label but a conventional-commit `type:*`\",\n    \"(`type:feat`, `type:docs`, …, stamped from its title prefix by the\",\n    \"generic create-issue workflow) is invisible to that dedup query and\",\n    \"mis-tiers in dispatch.\",\n    \"\",\n    \"The pairing below is derived from the canonical bundle-ownership\",\n    \"map — the same source of truth that generates the label registry.\",\n    \"Matchers ending in `*` match by prefix; the rest match exactly, and\",\n    \"an exact match always beats a prefix match.\",\n    \"\",\n    \"| Phase label | Match | Required type label |\",\n    \"|-------------|-------|---------------------|\",\n    ...rows,\n    \"\",\n    \"### Enforcement\",\n    \"\",\n    \"The Phase D maintenance sweep runs the invariant in auto-correct\",\n    \"mode and emits one summary line:\",\n    \"\",\n    \"```\",\n    \"LABEL_INVARIANT_DONE mode=fix checked=<N> ok=<O> violations=<V> corrected=<C> flagged=<F>\",\n    \"```\",\n    \"\",\n    \"A **report-only** audit is available for repos that prefer\",\n    \"report-then-fix over auto-correct — same sweep, no mutations:\",\n    \"\",\n    \"```bash\",\n    \".claude/procedures/check-blocked.sh label-invariant        # report only\",\n    \".claude/procedures/check-blocked.sh label-invariant --fix  # apply\",\n    \"```\",\n    \"\",\n    \"### Correction policy\",\n    \"\",\n    \"An issue must carry **exactly one** `type:*` label. Merely *adding*\",\n    \"the required type label to an issue that already carries a\",\n    \"conventional-commit one would leave two, making the funnel-tier sort\",\n    \"key (which reads the **first** `type:*` label) non-deterministic and\",\n    \"violating the label conventions. The correction therefore\",\n    \"**replaces**, in a single atomic `gh issue edit`, so the issue is\",\n    \"never observable carrying two `type:*` labels:\",\n    \"\",\n    \"| Issue state | Action |\",\n    \"|-------------|--------|\",\n    \"| Required type label present, nothing else | none — compliant, left untouched |\",\n    \"| No `type:*` label at all | **add** the required label |\",\n    \"| Only conventional-commit `type:*` label(s) | **replace** — remove them, add the required label |\",\n    \"| Required label present **plus** a stray conventional-commit one | **remove** the stray, leaving exactly one |\",\n    \"| A `type:*` label owned by a **different** bundle | **flag** `status:needs-attention` — never guessed at |\",\n    \"| Phase labels imply **two or more** type labels | **flag** `status:needs-attention` — never auto-corrected |\",\n    \"\",\n    \"Only a conventional-commit `type:*` label is ever removed. A\",\n    \"`type:*` label owned by another bundle carries real routing\",\n    \"information, so the sweep refuses to guess and hands the issue to a\",\n    \"human instead. Ambiguity is narrower than it looks: all three\",\n    \"requirements bundles declare `type:requirement`, so every `req:*`\",\n    \"phase label resolves to the same type label — genuine ambiguity\",\n    \"needs phase labels from two bundles with *different* type labels.\",\n    \"\",\n    \"`status:needs-attention` is applied **additively** — the base\",\n    \"`status:*` label always stays, per the additive-flag rule. Flagging\",\n    \"is idempotent: an issue already carrying the flag is reported but\",\n    \"not re-flagged.\",\n  ].join(\"\\n\");\n}\n\n/**\n * Return `true` when the bundle(s) declaring `matcher` are all in\n * `excludeBundles`.\n */\nfunction isPhaseLabelMatcherOwnedByExcluded(\n  matcher: string,\n  excludeBundles: ReadonlyArray<string>,\n): boolean {\n  if (excludeBundles.length === 0) {\n    return false;\n  }\n  let owned = false;\n  for (const [bundleName, ownership] of Object.entries(BUNDLE_OWNERSHIP)) {\n    if (!ownership.phaseLabelPrefixes.includes(matcher)) {\n      continue;\n    }\n    owned = true;\n    if (!excludeBundles.includes(bundleName)) {\n      return false;\n    }\n  }\n  return owned;\n}\n\n/**\n * Render the POSIX-shell half of the phase-label → `type:<bundle>`\n * invariant, derived from the same {@link PHASE_LABEL_TYPE_MAP} the\n * TypeScript accessors read. Emitted into `check-blocked.sh` so the\n * orchestrator's triage sweep and the consumer-runnable label audit\n * never carry a hand-copied second map.\n *\n * Three functions are rendered:\n *\n * - `phase_label_type_of <label>` — echoes the `type:<bundle>` label a\n *   single phase label implies, or nothing. Exact-match branches are\n *   emitted before prefix branches so `case` ordering reproduces the\n *   exact-beats-prefix precedence.\n * - `phase_type_of` — reads an issue's labels (one per line) on stdin\n *   and emits `KEY=VALUE` assignments: `OUTCOME=none|match|ambiguous`,\n *   `TYPE_LABEL=` (match only), `CANDIDATE_TYPE_LABELS=` (ambiguous\n *   only), and `PHASE_LABELS=`.\n * - `is_conventional_type_label <label>` — returns 0 for a\n *   conventional-commit `type:*` label, i.e. the only labels the\n *   auto-correction is allowed to remove.\n */\nexport function renderPhaseTypeInvariantShellHelpers(): string {\n  const matchers = Object.keys(PHASE_LABEL_TYPE_MAP);\n  const exactMatchers = matchers.filter((m) => !m.endsWith(\":\")).sort();\n  // Longest prefix first so a future `req:sub:` is tested before `req:`.\n  const prefixMatchers = matchers\n    .filter((m) => m.endsWith(\":\"))\n    .sort((a, b) => b.length - a.length || a.localeCompare(b));\n\n  const lines: Array<string> = [\n    \"# Resolve ONE phase label to the `type:<bundle>` label its owning\",\n    \"# bundle declares. Echoes the label (with the `type:` prefix) or\",\n    \"# nothing when no bundle owns it. Exact-match branches come first,\",\n    \"# so `req:write` (requirements-writer) beats the `req:` prefix\",\n    \"# (requirements-analyst). Generated from BUNDLE_OWNERSHIP — do not\",\n    \"# hand-edit.\",\n    \"phase_label_type_of() {\",\n    '  case \"${1:-}\" in',\n  ];\n  for (const matcher of exactMatchers) {\n    lines.push(`    ${matcher}) echo \"${PHASE_LABEL_TYPE_MAP[matcher]}\" ;;`);\n  }\n  for (const matcher of prefixMatchers) {\n    lines.push(`    ${matcher}*) echo \"${PHASE_LABEL_TYPE_MAP[matcher]}\" ;;`);\n  }\n  lines.push(\n    \"    *) : ;;\",\n    \"  esac\",\n    \"}\",\n    \"\",\n    \"# Return 0 when the argument is a conventional-commit `type:*`\",\n    \"# label — the ONLY type labels the invariant correction may remove.\",\n    \"# A `type:*` label owned by another bundle is never removed; the\",\n    \"# issue is flagged for human triage instead.\",\n    \"is_conventional_type_label() {\",\n    `  case \"\\${1:-}\" in`,\n    `    ${CONVENTIONAL_COMMIT_TYPE_LABELS.join(\"|\")}) return 0 ;;`,\n    \"    *) return 1 ;;\",\n    \"  esac\",\n    \"}\",\n    \"\",\n    \"# Resolve an issue's FULL label list (one label per line on stdin)\",\n    \"# to the type label the phase-label invariant requires. Emits\",\n    \"# KEY=VALUE assignments the caller parses:\",\n    \"#   OUTCOME=none      — no recognised phase label; invariant N/A\",\n    \"#   OUTCOME=match     — plus TYPE_LABEL=<type:bundle>\",\n    \"#   OUTCOME=ambiguous — plus CANDIDATE_TYPE_LABELS=<space-separated>\",\n    \"#   PHASE_LABELS=<space-separated recognised phase labels>\",\n    \"phase_type_of() {\",\n    \"  local label resolved\",\n    '  local matched_types=\"\"',\n    '  local matched_phase=\"\"',\n    \"  while IFS= read -r label; do\",\n    '    [ -z \"$label\" ] && continue',\n    '    resolved=$(phase_label_type_of \"$label\")',\n    '    [ -z \"$resolved\" ] && continue',\n    '    matched_phase=\"${matched_phase}${label} \"',\n    '    case \" ${matched_types} \" in',\n    '      *\" ${resolved} \"*) ;;',\n    '      *) matched_types=\"${matched_types}${resolved} \" ;;',\n    \"    esac\",\n    \"  done\",\n    \"  local count=0\",\n    \"  for resolved in $matched_types; do\",\n    \"    count=$((count + 1))\",\n    \"  done\",\n    '  if [ \"$count\" -eq 0 ]; then',\n    '    echo \"OUTCOME=none\"',\n    '  elif [ \"$count\" -eq 1 ]; then',\n    '    echo \"OUTCOME=match\"',\n    '    echo \"TYPE_LABEL=${matched_types% }\"',\n    \"  else\",\n    '    echo \"OUTCOME=ambiguous\"',\n    '    echo \"CANDIDATE_TYPE_LABELS=${matched_types% }\"',\n    \"  fi\",\n    '  echo \"PHASE_LABELS=${matched_phase% }\"',\n    \"}\",\n  );\n  return lines.join(\"\\n\");\n}\n\n/**\n * Build {@link PHASE_LABEL_TYPE_MAP} from {@link BUNDLE_OWNERSHIP}.\n *\n * @throws `Error` when two bundles claim the same phase-label matcher\n *         with different `type:*` labels, or when a bundle declares a\n *         phase-label matcher without declaring exactly one type label\n *         to pair it with — both are unresolvable registry bugs.\n */\nfunction buildPhaseLabelTypeMap(): Readonly<Record<string, string>> {\n  const map: Record<string, string> = {};\n  for (const [bundleName, ownership] of Object.entries(BUNDLE_OWNERSHIP)) {\n    if (ownership.phaseLabelPrefixes.length === 0) {\n      continue;\n    }\n    if (ownership.typeLabels.length !== 1) {\n      throw new Error(\n        `BUNDLE_OWNERSHIP[\"${bundleName}\"] declares ${ownership.phaseLabelPrefixes.length} phase-label matcher(s) but ${ownership.typeLabels.length} type label(s); a phase label must pair with exactly one type label`,\n      );\n    }\n    const typeLabel = `type:${ownership.typeLabels[0]}`;\n    for (const matcher of ownership.phaseLabelPrefixes) {\n      const existing = map[matcher];\n      if (existing !== undefined && existing !== typeLabel) {\n        throw new Error(\n          `Phase-label matcher \"${matcher}\" resolves to both \"${existing}\" and \"${typeLabel}\"; a matcher must imply exactly one type label`,\n        );\n      }\n      map[matcher] = typeLabel;\n    }\n  }\n  return map;\n}\n\n/**\n * Return `true` when `typeLabel` (without the leading `type:` prefix)\n * is owned by any bundle in `excludedBundles`. Used by tier-table and\n * scheduled-task renderers to drop rows whose owning bundle has been\n * excluded.\n */\nexport function isTypeLabelOwnedByExcluded(\n  typeLabel: string,\n  excludedBundles: ReadonlyArray<string>,\n): boolean {\n  if (excludedBundles.length === 0) {\n    return false;\n  }\n  for (const bundleName of excludedBundles) {\n    const ownership = BUNDLE_OWNERSHIP[bundleName];\n    if (!ownership) {\n      continue;\n    }\n    if (ownership.typeLabels.includes(typeLabel)) {\n      // Co-owned `type:requirement` is the only multi-bundle case.\n      // Drop the row only when **every** bundle that owns the label\n      // is excluded, otherwise the still-active co-owner needs the\n      // row to reach its own scheduled task.\n      const owners = findOwnersOfTypeLabel(typeLabel);\n      const allExcluded = owners.every((owner) =>\n        excludedBundles.includes(owner),\n      );\n      if (allExcluded) {\n        return true;\n      }\n    }\n  }\n  return false;\n}\n\n/**\n * Return `true` when `phaseLabel` is owned by any bundle in\n * `excludedBundles`. Matches against both prefix entries (with\n * trailing colon, e.g. `\"company:\"`) and exact-match entries (without\n * trailing colon, e.g. `\"req:write\"`). Used by the scope-gate\n * per-phase-override table renderer.\n */\nexport function isPhaseLabelOwnedByExcluded(\n  phaseLabel: string,\n  excludedBundles: ReadonlyArray<string>,\n): boolean {\n  if (excludedBundles.length === 0) {\n    return false;\n  }\n  for (const bundleName of excludedBundles) {\n    const ownership = BUNDLE_OWNERSHIP[bundleName];\n    if (!ownership) {\n      continue;\n    }\n    for (const entry of ownership.phaseLabelPrefixes) {\n      if (entry.endsWith(\":\")) {\n        if (phaseLabel.startsWith(entry)) {\n          return true;\n        }\n      } else if (phaseLabel === entry) {\n        return true;\n      }\n    }\n  }\n  return false;\n}\n\n/**\n * Return `true` when the scheduled-task `taskId` is owned by any\n * bundle in `excludedBundles`. Used by the scheduled-tasks registry\n * filter to drop default entries pointing at an excluded bundle.\n */\nexport function isScheduledTaskOwnedByExcluded(\n  taskId: string,\n  excludedBundles: ReadonlyArray<string>,\n): boolean {\n  if (excludedBundles.length === 0) {\n    return false;\n  }\n  for (const bundleName of excludedBundles) {\n    const ownership = BUNDLE_OWNERSHIP[bundleName];\n    if (!ownership) {\n      continue;\n    }\n    if (ownership.scheduledTaskIds.includes(taskId)) {\n      return true;\n    }\n  }\n  return false;\n}\n\n/**\n * Return `true` when at least one docs-emitting bundle is **not**\n * excluded. Used by the `section-index-pages` rule auto-suppression\n * gate — when this returns `false`, the rule is dropped from the\n * rendered rule map entirely.\n */\nexport function hasAnyDocsEmittingBundle(\n  excludedBundles: ReadonlyArray<string>,\n): boolean {\n  for (const [bundleName, ownership] of Object.entries(BUNDLE_OWNERSHIP)) {\n    if (!ownership.emitsDocs) {\n      continue;\n    }\n    if (!excludedBundles.includes(bundleName)) {\n      return true;\n    }\n  }\n  return false;\n}\n\n/**\n * Return `true` when at least one downstream-issue-kind bundle is\n * **not** excluded. Used by the `issue-templates-convention`\n * auto-suppression gate — when this returns `false`, the rule body\n * renders the disabled-stub variant.\n */\nexport function hasAnyDownstreamIssueKindBundle(\n  excludedBundles: ReadonlyArray<string>,\n): boolean {\n  for (const [bundleName, ownership] of Object.entries(BUNDLE_OWNERSHIP)) {\n    if (!ownership.downstreamIssueKinds) {\n      continue;\n    }\n    if (!excludedBundles.includes(bundleName)) {\n      return true;\n    }\n  }\n  return false;\n}\n\n/**\n * Find every bundle that declares ownership of `typeLabel`. Returns an\n * empty array when no bundle in the registry owns the label. Used by\n * `isTypeLabelOwnedByExcluded` to handle co-owned labels (e.g.\n * `type:requirement` is owned by three bundles — the row stays in the\n * table unless every co-owner is excluded).\n */\nfunction findOwnersOfTypeLabel(typeLabel: string): ReadonlyArray<string> {\n  const owners: Array<string> = [];\n  for (const [bundleName, ownership] of Object.entries(BUNDLE_OWNERSHIP)) {\n    if (ownership.typeLabels.includes(typeLabel)) {\n      owners.push(bundleName);\n    }\n  }\n  return owners;\n}\n","import { CONVENTIONAL_COMMIT_TYPE_LABELS } from \"./bundle-ownership\";\n\n/**\n * The GitHub **issue type** vocabulary this convention assigns.\n *\n * An issue type is a first-class GitHub field (Epic / Feature / Bug /\n * Task) and is a completely different axis from the `type:*` **label**\n * taxonomy:\n *\n * - `type:<bundle>` / `type:<conventional-commit>` — a *label*. Routing\n *   and dedup signal. Owned by {@link BUNDLE_OWNERSHIP} and set with\n *   `gh issue create --label`.\n * - GitHub issue type — a *field*. Human triage, Epic-relationship\n *   tracking, and reporting signal. `gh issue create` cannot set it, so\n *   it is applied immediately after creation via the\n *   `updateIssueIssueType` GraphQL mutation.\n *\n * Conflating the two is the single most common mistake in this area, so\n * both this module and the prose it renders keep them explicitly apart.\n */\nexport const GITHUB_ISSUE_TYPES = [\"Epic\", \"Feature\", \"Bug\", \"Task\"] as const;\n\nexport type GithubIssueType = (typeof GITHUB_ISSUE_TYPES)[number];\n\n/**\n * The issue type every title prefix maps to unless it is one of the\n * three explicit exceptions in {@link NON_DEFAULT_TITLE_PREFIX_TYPES}.\n *\n * Every bundle-phase prefix (`company:`, `req:`, `bcm:`, `software:`,\n * …) lands here, which is why agent-enqueued downstream issues are\n * almost always `Task` — the phased pipelines file work items, not\n * features or bug reports.\n */\nexport const DEFAULT_GITHUB_ISSUE_TYPE: GithubIssueType = \"Task\";\n\n/**\n * The only title prefixes that map to something other than\n * {@link DEFAULT_GITHUB_ISSUE_TYPE}.\n *\n * `epic:` deliberately has no conventional-commit `type:epic` **label**\n * (epics carry `type:feat`), so it does not appear in\n * {@link CONVENTIONAL_COMMIT_TYPE_LABELS} and is declared here instead.\n */\nconst NON_DEFAULT_TITLE_PREFIX_TYPES: Readonly<\n  Record<string, GithubIssueType>\n> = {\n  \"epic:\": \"Epic\",\n  \"feat:\": \"Feature\",\n  \"fix:\": \"Bug\",\n};\n\n/**\n * Canonical issue-title-prefix → GitHub issue type map.\n *\n * Derived from {@link CONVENTIONAL_COMMIT_TYPE_LABELS} — the shared\n * conventional-commit vocabulary exported alongside the bundle\n * ownership registry — so the prefix list can never drift from the\n * label list the create-issue workflow stamps. Every conventional-commit\n * prefix defaults to `Task`; the three exceptions are overlaid on top.\n *\n * Prefixes carry their trailing colon (`\"feat:\"`) to match the way the\n * title conventions write them.\n */\nexport const GITHUB_ISSUE_TYPE_BY_TITLE_PREFIX: Readonly<\n  Record<string, GithubIssueType>\n> = buildTitlePrefixTypeMap();\n\n/**\n * Resolve an issue **title** to the GitHub issue type it must carry.\n *\n * Anything that is not one of the four recognised non-default prefixes\n * — including every bundle-phase prefix (`company:research: …`) and a\n * title with no prefix at all — resolves to\n * {@link DEFAULT_GITHUB_ISSUE_TYPE}.\n */\nexport function githubIssueTypeForTitle(title: string): GithubIssueType {\n  const colon = title.indexOf(\":\");\n  if (colon === -1) {\n    return DEFAULT_GITHUB_ISSUE_TYPE;\n  }\n  const prefix = title\n    .slice(0, colon + 1)\n    .trim()\n    .toLowerCase();\n  return GITHUB_ISSUE_TYPE_BY_TITLE_PREFIX[prefix] ?? DEFAULT_GITHUB_ISSUE_TYPE;\n}\n\n/**\n * Path to the `set-issue-type.sh` helper the `github-workflow` bundle\n * ships. Referenced (never assumed present) by the rendered prose — see\n * {@link renderGithubIssueTypeSectionLines} for the fallback that keeps\n * the recipe working for consumers who exclude that bundle.\n */\nexport const SET_ISSUE_TYPE_HELPER_PATH =\n  \".claude/procedures/set-issue-type.sh\";\n\n/**\n * The two-step `updateIssueIssueType` GraphQL flow, rendered as shell.\n *\n * `set-issue-type.sh` wraps exactly this flow, but that helper ships\n * **only** via the `github-workflow` bundle. Any recipe outside that\n * bundle that cited the helper unconditionally would be broken for a\n * consumer running `excludeBundles: [\"github-workflow\"]`, so the\n * fallback is documented inline in an always-on base rule and every\n * per-filing-site step points at it.\n */\nexport function renderSetIssueTypeFallbackLines(): Array<string> {\n  return [\n    \"```bash\",\n    \"gh api graphql -f query='query($owner:String!,$repo:String!){repository(owner:$owner,name:$repo){issueTypes(first:50){nodes{id name}}}}' -f owner=<owner> -f repo=<repo>\",\n    \"gh issue view <issue-number> --json id --jq '.id'\",\n    \"gh api graphql -f query='mutation($issueId:ID!,$typeId:ID!){updateIssueIssueType(input:{issueId:$issueId,issueTypeId:$typeId}){issue{number issueType{name}}}}' -f issueId=<issue-node-id> -f typeId=<issue-type-node-id>\",\n    \"```\",\n  ];\n}\n\n/**\n * Render the **GitHub Issue Type** section of the always-on\n * `issue-conventions` rule.\n *\n * The section is the single canonical answer to \"how does an agent set\n * an issue's type?\", and it is rendered into an `ALWAYS`-scoped base\n * rule precisely so every downstream filing site can cite it in one\n * line regardless of which optional bundles the consumer enabled.\n *\n * It documents both paths deliberately:\n *\n * 1. The `set-issue-type.sh` one-liner, when `github-workflow` is\n *    active.\n * 2. The inline GraphQL fallback, when it is not.\n */\nexport function renderGithubIssueTypeSectionLines(): Array<string> {\n  const defaultPrefixes = Object.keys(GITHUB_ISSUE_TYPE_BY_TITLE_PREFIX)\n    .filter(\n      (prefix) =>\n        GITHUB_ISSUE_TYPE_BY_TITLE_PREFIX[prefix] === DEFAULT_GITHUB_ISSUE_TYPE,\n    )\n    .sort()\n    .map((prefix) => `\\`${prefix}\\``)\n    .join(\", \");\n\n  return [\n    \"## GitHub Issue Type\",\n    \"\",\n    \"A GitHub **issue type** is a distinct field from the `type:*` **label**:\",\n    \"the label routes and dedups, the issue type drives triage and Epic\",\n    \"tracking. Setting one does not set the other. Derive it from the\",\n    \"**title prefix**:\",\n    \"\",\n    \"| Prefix | GitHub Issue Type |\",\n    \"|--------|------------------|\",\n    \"| `epic:` | Epic |\",\n    \"| `feat:` | Feature |\",\n    \"| `fix:` | Bug |\",\n    `| ${defaultPrefixes} | ${DEFAULT_GITHUB_ISSUE_TYPE} |`,\n    \"| any bundle-phase prefix (`company:`, `req:`, …), or no prefix | Task |\",\n    \"\",\n    \"### Assigning the GitHub issue type\",\n    \"\",\n    \"`gh issue create` **cannot** set the issue type — there is no `--type`\",\n    \"flag — so assign it in a follow-up call immediately after creation, for\",\n    \"every issue an agent files (auto-enqueued downstream issues included).\",\n    \"An issue that skips that call stays untyped forever. The\",\n    \"`github-workflow` bundle ships a one-step helper:\",\n    \"\",\n    \"```bash\",\n    `${SET_ISSUE_TYPE_HELPER_PATH} <issue-number> <${GITHUB_ISSUE_TYPES.join(\"|\")}>`,\n    \"```\",\n    \"\",\n    \"When that helper is absent (the bundle is excluded), run the\",\n    \"`updateIssueIssueType` GraphQL flow it wraps:\",\n    \"\",\n    ...renderSetIssueTypeFallbackLines(),\n  ];\n}\n\n/**\n * Render the title-prefix → issue-type mapping as a markdown bullet\n * list, for recipes that present it inline rather than as a table (the\n * interactive create-issue workflow's step 3).\n *\n * Grouping matches the table in {@link renderGithubIssueTypeSectionLines}:\n * one bullet per non-default prefix, then a single bullet collapsing\n * every prefix that maps to {@link DEFAULT_GITHUB_ISSUE_TYPE}.\n */\nexport function renderTitlePrefixTypeBullets(indent = \"   \"): Array<string> {\n  const nonDefault = Object.entries(NON_DEFAULT_TITLE_PREFIX_TYPES).map(\n    ([prefix, issueType]) => `${indent}- \\`${prefix}\\` → ${issueType}`,\n  );\n  const defaults = Object.keys(GITHUB_ISSUE_TYPE_BY_TITLE_PREFIX)\n    .filter(\n      (prefix) =>\n        GITHUB_ISSUE_TYPE_BY_TITLE_PREFIX[prefix] === DEFAULT_GITHUB_ISSUE_TYPE,\n    )\n    .sort()\n    .map((prefix) => `\\`${prefix}\\``)\n    .join(\", \");\n  return [\n    ...nonDefault,\n    `${indent}- ${defaults} → ${DEFAULT_GITHUB_ISSUE_TYPE}`,\n    `${indent}- any bundle-phase prefix (\\`company:\\`, \\`req:\\`, \\`bcm:\\`, …) → ${DEFAULT_GITHUB_ISSUE_TYPE}`,\n  ];\n}\n\n/** String form of {@link renderGithubIssueTypeSectionLines}. */\nexport function renderGithubIssueTypeSection(): string {\n  return renderGithubIssueTypeSectionLines().join(\"\\n\");\n}\n\n/** Options for {@link renderIssueTypeAssignmentStep}. */\nexport interface IssueTypeAssignmentStepOptions {\n  /**\n   * Leading whitespace prepended to every rendered line so the step\n   * nests correctly under the numbered/bulleted filing recipe it\n   * follows. Defaults to the three spaces a top-level numbered list\n   * item continues with.\n   */\n  readonly indent?: string;\n  /**\n   * The GitHub issue type the filed issue must carry. Defaults to\n   * {@link DEFAULT_GITHUB_ISSUE_TYPE}, which is correct for every\n   * bundle-phase-prefixed downstream issue.\n   */\n  readonly issueType?: GithubIssueType;\n  /**\n   * Render the step as a markdown list item (`- …` with hanging\n   * continuation lines) instead of a paragraph. Used at the handful of\n   * filing recipes that specify the issue with a bullet list rather\n   * than numbered prose.\n   */\n  readonly bullet?: boolean;\n}\n\n/**\n * Render the compact \"now set the issue type\" step appended to every\n * bundle-shipped downstream filing recipe.\n *\n * Kept deliberately short: it appears at ~45 filing sites across the\n * phased-pipeline bundles, so it names the concrete type, calls out that\n * the `type:*` label is a different field, gives the command, and\n * delegates the fallback to the always-on `issue-conventions` rule\n * rather than re-inlining the GraphQL flow at every site.\n */\nexport function renderIssueTypeAssignmentStep(\n  options: IssueTypeAssignmentStepOptions = {},\n): Array<string> {\n  const indent = options.indent ?? \"   \";\n  const issueType = options.issueType ?? DEFAULT_GITHUB_ISSUE_TYPE;\n  const lead = options.bullet ? `${indent}- ` : indent;\n  const cont = options.bullet ? `${indent}  ` : indent;\n  return [\n    `${lead}Then assign the new issue's **GitHub issue type** (\\`${issueType}\\`) —`,\n    `${cont}the \\`type:*\\` label does not set it:`,\n    `${cont}\\`${SET_ISSUE_TYPE_HELPER_PATH} <issue-number> ${issueType}\\`. See`,\n    `${cont}**Assigning the GitHub issue type** for the no-helper fallback.`,\n  ];\n}\n\n/**\n * Render the phase-wide variant of {@link renderIssueTypeAssignmentStep}\n * for a workflow phase that files several kinds of issue across several\n * steps, where repeating the per-recipe step at each one would bloat the\n * prompt without adding information.\n */\nexport function renderIssueTypeAssignmentBlanket(\n  indent = \"\",\n  issueType: GithubIssueType = DEFAULT_GITHUB_ISSUE_TYPE,\n): Array<string> {\n  return [\n    `${indent}**Every** issue this phase files needs a **GitHub issue type**`,\n    `${indent}assigned right after creation — the \\`type:*\\` label does not set`,\n    `${indent}it, and \\`gh issue create\\` cannot:`,\n    `${indent}\\`${SET_ISSUE_TYPE_HELPER_PATH} <issue-number> ${issueType}\\`. See`,\n    `${indent}**Assigning the GitHub issue type** for the prefix table (nearly`,\n    `${indent}every downstream issue is a \\`${issueType}\\`) and the no-helper fallback.`,\n  ];\n}\n\n/**\n * Build {@link GITHUB_ISSUE_TYPE_BY_TITLE_PREFIX} from the shared\n * conventional-commit label vocabulary plus the explicit exceptions.\n */\nfunction buildTitlePrefixTypeMap(): Readonly<Record<string, GithubIssueType>> {\n  const map: Record<string, GithubIssueType> = {};\n  for (const label of CONVENTIONAL_COMMIT_TYPE_LABELS) {\n    map[`${label.slice(\"type:\".length)}:`] = DEFAULT_GITHUB_ISSUE_TYPE;\n  }\n  for (const [prefix, issueType] of Object.entries(\n    NON_DEFAULT_TITLE_PREFIX_TYPES,\n  )) {\n    map[prefix] = issueType;\n  }\n  return map;\n}\n","/**\n * Shared `origin:*` label vocabulary for agent-opened PRs\n * (fix-delegation parity — codedrifters/packages#859).\n *\n * The `pr-reviewer` decides whether it may autonomously delegate\n * in-scope fixes to the `issue-worker` by looking at the PR's origin\n * label. Historically only {@link ORIGIN_ISSUE_WORKER_LABEL} existed, so\n * every PR opened by the phased analyst/writer family looked\n * human-authored to the reviewer and had its delegation hand-off\n * skipped — those PRs waited for a human instead of self-healing.\n *\n * Stamping the literal `origin:issue-worker` label on an analyst PR\n * would be semantically false (the glossary defines it as \"PR was opened\n * by the `issue-worker` agent\"), so the analyst family stamps the\n * {@link ORIGIN_AGENT_LABEL} umbrella label instead and both labels\n * resolve to delegation-eligible.\n *\n * Scope note: this is **fix-delegation parity only**. Sweep and\n * auto-merge eligibility have never been origin-gated (`cmd_review` has\n * no origin/author check), so nothing here changes which PRs merge.\n *\n * The stamp section is rendered identically into every phased\n * analyst/writer prompt via {@link renderOriginStampSection} so the\n * protocol never drifts between bundles — the same pattern the\n * claim-verification and project-context sections use.\n */\n\n/**\n * Origin label stamped by the `issue-worker` agent on the PRs it opens.\n * Unchanged by #859 — the issue-worker keeps its own specific label.\n */\nexport const ORIGIN_ISSUE_WORKER_LABEL = \"origin:issue-worker\";\n\n/**\n * Umbrella origin label stamped by every phased analyst/writer agent on\n * the PRs it opens. Semantically \"opened by an agent in this project's\n * pipeline\", as distinct from the narrower `origin:issue-worker`.\n */\nexport const ORIGIN_AGENT_LABEL = \"origin:agent\";\n\n/**\n * Every origin label that resolves to **fix-delegation-eligible** in the\n * `pr-reviewer`'s invocation guard. A PR carrying any of these is\n * bot-authored and may have in-scope fixes delegated autonomously,\n * without the `--allow-human-author` opt-in flag.\n */\nexport const DELEGATION_ELIGIBLE_ORIGIN_LABELS: ReadonlyArray<string> = [\n  ORIGIN_ISSUE_WORKER_LABEL,\n  ORIGIN_AGENT_LABEL,\n];\n\n/**\n * Inline prose fragment naming both delegation-eligible origin labels.\n * Used wherever a prompt previously said \"the `origin:issue-worker`\n * label\" while meaning \"an origin label that marks the PR bot-authored\".\n */\nexport const DELEGATION_ELIGIBLE_ORIGIN_PHRASE = `an origin label (\\`${ORIGIN_ISSUE_WORKER_LABEL}\\` or \\`${ORIGIN_AGENT_LABEL}\\`)`;\n\n/**\n * Bare \"either label\" fragment, for prose that already sits inside\n * parentheses (where {@link DELEGATION_ELIGIBLE_ORIGIN_PHRASE} would\n * nest a second pair).\n */\nexport const DELEGATION_ELIGIBLE_ORIGIN_LIST = `\\`${ORIGIN_ISSUE_WORKER_LABEL}\\` or \\`${ORIGIN_AGENT_LABEL}\\``;\n\n/**\n * Render the shared `## Origin label` section as prompt lines. Spread\n * into a phased analyst/writer sub-agent `prompt` array with\n * `...renderOriginStampSection()`.\n */\nexport function renderOriginStampSection(): ReadonlyArray<string> {\n  return [\n    \"## Origin label\",\n    \"\",\n    `Every PR you open must carry the \\`${ORIGIN_AGENT_LABEL}\\` label. It is`,\n    \"the umbrella origin label for **agent-opened** PRs: the `pr-reviewer`\",\n    \"reads it to decide whether it may autonomously delegate in-scope\",\n    \"review fixes back to the `issue-worker`. A PR that reaches the\",\n    \"reviewer with no origin label looks human-authored, so the reviewer\",\n    \"skips the delegation hand-off and the PR sits waiting for a human\",\n    \"instead of being self-healed by the pipeline.\",\n    \"\",\n    \"Pass the label on the `gh pr create` invocation:\",\n    \"\",\n    \"```bash\",\n    'gh pr create --title \"<type>(<scope>): <description>\" \\\\',\n    `  --label '${ORIGIN_AGENT_LABEL}' \\\\`,\n    '  --body \"<summary>',\n    \"\",\n    'Closes #<issue-number>\"',\n    \"```\",\n    \"\",\n    \"If your project's PR workflow opens the PR for you and the label is\",\n    \"missing afterwards, add it immediately — before handing the PR to\",\n    \"review:\",\n    \"\",\n    \"```bash\",\n    `gh pr edit <pr-number> --add-label '${ORIGIN_AGENT_LABEL}'`,\n    \"```\",\n    \"\",\n    `Stamp \\`${ORIGIN_AGENT_LABEL}\\`, never \\`${ORIGIN_ISSUE_WORKER_LABEL}\\` —`,\n    `\\`${ORIGIN_ISSUE_WORKER_LABEL}\\` means the PR was opened by the`,\n    \"`issue-worker` agent specifically, and claiming it on an analyst PR\",\n    \"would be false. Both labels are delegation-eligible, so the umbrella\",\n    \"label buys the same autonomous fix hand-off without the false claim.\",\n    \"\",\n    `The \\`${ORIGIN_AGENT_LABEL}\\` label ships with the \\`pr-review\\` bundle's`,\n    \"label set, so it is already present in the repository's label\",\n    \"registry — you never need to create it.\",\n  ];\n}\n","/**\n * Shared prompt snippets that teach agents about the\n * `docs/project-context.md` convention file.\n *\n * The file is the canonical answer to \"what is this project about?\" —\n * mission, domain vocabulary, in/out-of-scope capabilities, and key\n * stakeholders. Two variants are exported:\n *\n * - {@link PROJECT_CONTEXT_READER_SECTION} — for execution agents that\n *   read the file for framing but never edit it.\n * - {@link PROJECT_CONTEXT_MAINTAINER_SECTION} — for learning agents\n *   (meeting-analyst, requirements-analyst) that seed the file on first\n *   use and update it when new project-scope facts emerge.\n *\n * Each export is a `ReadonlyArray<string>` so it can be spread directly\n * into a sub-agent `prompt` array.\n */\n\n/** Path to the convention file, relative to the repo root. */\nexport const PROJECT_CONTEXT_PATH = \"docs/src/content/docs/project-context.md\";\n\n/**\n * Shared guidance on deriving a sub-project's role from the top-level\n * segment of its `outdir`. Included in both the reader and maintainer\n * sections so every agent understands the convention without needing\n * an external link. Kept self-contained — agents never need to follow\n * a cross-reference to interpret the rule.\n */\nconst SUBPROJECT_ROLE_GUIDANCE: ReadonlyArray<string> = [\n  \"### Sub-project roles\",\n  \"\",\n  \"When the repository follows the configulator monorepo layout,\",\n  \"every sub-project's role is derivable from the first segment of\",\n  \"its `outdir` path. No other lookup is required.\",\n  \"\",\n  \"- `apps/<scope>/<name>` — deployable application (CDK stack,\",\n  \"  mobile app, backend service).\",\n  \"- `packages/<scope>/<name>` — shared library (published npm\",\n  \"  package or workspace-internal library).\",\n  \"- `sites/<scope>/<name>` — user-facing web front end that is\",\n  \"  not the monorepo-wide docs site.\",\n  \"- `docs/` — the single Starlight documentation site for the\",\n  \"  whole monorepo (exactly one per repo; lives at `/docs`, not\",\n  \"  under `sites/`).\",\n  \"\",\n  \"Repositories that have not adopted the layout contract may use a\",\n  \"different folder structure — in that case fall back to whatever\",\n  `\\`${PROJECT_CONTEXT_PATH}\\` documents explicitly.`,\n  \"\",\n];\n\n/**\n * Read-only framing section. Spread into prompts for agents that should\n * consult `docs/project-context.md` but never edit it.\n */\nexport const PROJECT_CONTEXT_READER_SECTION: ReadonlyArray<string> = [\n  \"## Project Context\",\n  \"\",\n  `Before doing any work, read \\`${PROJECT_CONTEXT_PATH}\\` at the`,\n  'repository root. It is the canonical answer to \"what is this project',\n  'about?\" — mission, domain vocabulary, in/out-of-scope capabilities, and',\n  \"key stakeholders. Use it to frame judgment calls in this session.\",\n  \"\",\n  `If \\`${PROJECT_CONTEXT_PATH}\\` does not exist, proceed with the current`,\n  \"task and note the absence in your session log — the meeting-analyst and\",\n  \"requirements-analyst agents seed the file on their next run.\",\n  \"\",\n  \"You are a **read-only consumer** of this file. Do not edit it.\",\n  \"\",\n  ...SUBPROJECT_ROLE_GUIDANCE,\n  \"---\",\n  \"\",\n];\n\n/**\n * Maintainer section. Spread into prompts for agents that own updates\n * to `docs/project-context.md`. Includes the seed template and the\n * trigger conditions for updates.\n *\n * The seed template embeds a `{{monorepoLayoutSeedBlock}}` template\n * variable. When the consuming monorepo has layout enforcement on\n * (`layoutEnforcement !== \"off\"`), `ProjectMetadata` resolves it to a\n * grouped sub-project list skeleton (Applications / Packages / Sites /\n * Docs) so the seeded file surfaces each sub-project's role up front.\n * Repos with layout enforcement off resolve it to an empty string, so\n * the seed template is unchanged.\n */\nexport const PROJECT_CONTEXT_MAINTAINER_SECTION: ReadonlyArray<string> = [\n  \"## Project Context\",\n  \"\",\n  `Before starting any phase, read \\`${PROJECT_CONTEXT_PATH}\\` at the`,\n  'repository root. It is the canonical answer to \"what is this project',\n  'about?\" — mission, domain vocabulary, in/out-of-scope capabilities, and',\n  \"key stakeholders. Use it to judge relevance when scanning source\",\n  \"material in this session.\",\n  \"\",\n  ...SUBPROJECT_ROLE_GUIDANCE,\n  \"### Seed on first use\",\n  \"\",\n  `If \\`${PROJECT_CONTEXT_PATH}\\` does not exist, create it from this`,\n  \"template and commit it alongside this phase's other outputs:\",\n  \"\",\n  \"```markdown\",\n  \"# Project Context\",\n  \"\",\n  \"> Canonical description of this project. Read by all agents before\",\n  \"> work. Updated by meeting-analyst and requirements-analyst when new\",\n  \"> scope, vocabulary, or stakeholders emerge.\",\n  \"\",\n  \"## Mission\",\n  \"TODO: one or two sentences on what this project exists to do.\",\n  \"\",\n  \"## Target Users\",\n  \"TODO: who uses this, in what role.\",\n  \"\",\n  \"## In-Scope Capabilities\",\n  \"TODO: bullet list of the capabilities this project owns.\",\n  \"\",\n  \"## Out-of-Scope\",\n  \"TODO: capabilities or concerns that are explicitly not this project's.\",\n  \"\",\n  \"## Domain Vocabulary\",\n  \"TODO: short glossary of domain terms, acronyms, and their definitions.\",\n  \"\",\n  \"## Key Stakeholders\",\n  \"TODO: named people or teams and what they care about.\",\n  \"{{monorepoLayoutSeedBlock}}\",\n  \"## References\",\n  \"TODO: links to BCM docs, competitive analysis, product roadmap, and\",\n  \"other authoritative sources.\",\n  \"```\",\n  \"\",\n  \"Fill whatever you can infer from the source material you are already\",\n  \"reading in this phase; leave `TODO:` placeholders for the rest.\",\n  \"\",\n  \"### Update on new facts\",\n  \"\",\n  \"When the source material you process reveals new project-scope\",\n  \"information — a new capability, a vocabulary term, an entity, a\",\n  \"stakeholder, an in/out-of-scope decision, or a shift in mission —\",\n  `append or revise the relevant section in \\`${PROJECT_CONTEXT_PATH}\\``,\n  \"before closing the phase. Commit those edits with the phase's other\",\n  \"outputs.\",\n  \"\",\n  \"Keep edits surgical: short bullet additions, brief clarifications, or\",\n  \"single-line vocabulary entries. Treat the file as an accreting\",\n  \"reference, not a document you reshape every session.\",\n  \"\",\n  \"---\",\n  \"\",\n];\n\n/**\n * Markdown block appended to the maintainer seed template when the\n * consuming monorepo has layout enforcement on. Groups sub-projects\n * by role (Applications / Packages / Sites / Docs) so the seeded\n * `docs/project-context.md` surfaces each sub-project's role from\n * day one. The heading sits between \"Key Stakeholders\" and\n * \"References\" so the seeded document still reads top-to-bottom when\n * the block is absent.\n *\n * Returned as a plain string (with embedded newlines) so it can drop\n * straight into `resolveTemplateVariables` as the resolved value for\n * `{{monorepoLayoutSeedBlock}}`. The leading newline ensures the\n * block's `##` heading starts on a fresh line when it replaces a\n * whole template-variable line.\n */\nexport const MONOREPO_LAYOUT_SEED_BLOCK: string = [\n  \"\",\n  \"## Sub-Projects\",\n  \"\",\n  \"TODO: one bullet per sub-project, grouped by role. The role is\",\n  \"derivable from the first segment of each sub-project's `outdir`.\",\n  \"\",\n  \"### Applications (`apps/`)\",\n  \"TODO: deployable applications (CDK stacks, mobile apps, services).\",\n  \"\",\n  \"### Packages (`packages/`)\",\n  \"TODO: shared libraries (published npm packages, workspace-internal libraries).\",\n  \"\",\n  \"### Sites (`sites/`)\",\n  \"TODO: user-facing web front ends (marketing sites, SPAs, client apps).\",\n  \"\",\n  \"### Docs (`docs/`)\",\n  \"TODO: the single monorepo-wide Starlight documentation site.\",\n  \"\",\n].join(\"\\n\");\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { renderClaimVerificationSection } from \"./claim-verification\";\nimport { renderIssueTypeAssignmentStep } from \"./issue-type\";\nimport { renderOriginStampSection } from \"./origin-label\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n  AGENT_MODEL,\n  AGENT_RULE_SCOPE,\n  AgentSkill,\n  AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that authors pre-meeting agendas. Complements the\n * `meeting-analyst`: the meeting-analyst handles the post-meeting\n * pipeline (extract → notes → draft → link); the agenda-analyst\n * handles the pre-meeting counterpart (draft → finalize).\n *\n * Together they close the loop:\n * **agenda → meeting → transcript → notes → follow-up work**.\n *\n * The prompt is deliberately domain-neutral. Concrete meeting-type\n * identifiers, agenda templates, and area routing come from the\n * consuming project via `AgentConfigOptions.meetings.meetingTypes`\n * and `AgentConfigOptions.meetings.meetingAreas`.\n */\nconst agendaAnalystSubAgent: AgentSubAgent = {\n  name: \"agenda-analyst\",\n  description:\n    \"Authors pre-meeting agendas through a 2-phase pipeline (draft → finalize). Selects a type-specific template, pulls carryover from prior instances of the same recurring series, and writes a time-boxed, intent-tagged agenda to the meeting's dated folder. One phase per session, tracked by agenda:* GitHub issue labels.\",\n  model: AGENT_MODEL.BALANCED,\n  maxTurns: 40,\n  platforms: { cursor: { exclude: true } },\n  prompt: [\n    \"# Meeting Agenda Agent\",\n    \"\",\n    \"Dedicated agent loop for producing meeting **agendas** before a\",\n    \"meeting takes place. Complements the `meeting-analyst`, which\",\n    \"processes transcripts and notes *after* the meeting. Together they\",\n    \"close the loop: **agenda → meeting → transcript → notes → follow-up\",\n    \"work**.\",\n    \"\",\n    \"Each phase runs as a **separate agent session**, triggered by its\",\n    \"own GitHub issue with an `agenda:*` phase label. You handle exactly\",\n    \"**one phase per session** — read the issue to determine which phase\",\n    \"to execute.\",\n    \"\",\n    \"This agent is **domain-neutral**. It makes no assumptions about\",\n    \"concrete meeting types, templates, or area routing — those come\",\n    \"from the consuming project via `AgentConfigOptions.meetings`\",\n    \"(which renders a **Recognized meeting types** table the agent\",\n    \"consults at runtime).\",\n    \"\",\n    \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n    \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n    \"\",\n    \"---\",\n    \"\",\n    ...PROJECT_CONTEXT_READER_SECTION,\n    \"## Design Principles\",\n    \"\",\n    \"1. **Agendas exist to make meetings shorter.** Every section must\",\n    \"   justify its minutes. If a section has no decision, no discussion,\",\n    \"   and no new information, cut it or move it to async.\",\n    \"2. **One meeting, one dated folder.** All artifacts for a given\",\n    \"   meeting live in `<meetingsRoot>/<YYYY-MM-DD>-<slug>/`: `agenda.md`,\",\n    \"   `notes.md`, and any attachments. The agenda agent creates the\",\n    \"   folder if it does not yet exist; the meeting-analyst lands\",\n    \"   transcripts and notes into the same folder post-meeting.\",\n    \"3. **Objective before outline.** No agenda ships without a stated\",\n    \"   objective and 1–3 desired outcomes. If the issue does not supply\",\n    \"   them and they cannot be inferred from prior meeting notes or\",\n    \"   related docs, **block the issue** rather than guessing.\",\n    \"4. **Time-box everything.** Section times must sum to the meeting\",\n    \"   duration ±5 minutes. Overruns are planned for (a parking lot\",\n    \"   section) rather than assumed.\",\n    \"5. **Tag every section with intent.** Each timed block carries one\",\n    \"   of: `[decide]`, `[discuss]`, `[inform]`, `[brainstorm]`.\",\n    \"   Attendees should know what is expected of them before the section\",\n    \"   starts.\",\n    \"6. **Link by reference, never copy.** Pre-reads link to existing\",\n    \"   docs by relative markdown path. The agent does not inline content\",\n    \"   from other files into the agenda.\",\n    \"7. **Recurring meetings share a skeleton.** Every instance of a\",\n    \"   recurring meeting uses the same template structure so attendees\",\n    \"   know where to find what; only the content varies.\",\n    \"8. **Never cross agent boundaries.** Do not write `notes.md`,\",\n    \"   transcripts, extracts, requirements, ADRs, or profiles. If the\",\n    \"   agenda work surfaces a need for any of those, create the\",\n    \"   appropriate issue for the specialist agent instead.\",\n    \"\",\n    \"---\",\n    \"\",\n    \"## State Machine Overview\",\n    \"\",\n    \"Producing one agenda flows through **2 phases**:\",\n    \"\",\n    \"```\",\n    \"┌─────────────────┐     ┌──────────────────┐\",\n    \"│ 1. DRAFT        │────▶│  2. FINALIZE     │\",\n    \"│ Create folder,  │     │  Cross-link,     │\",\n    \"│ select template,│     │  register in     │\",\n    \"│ write agenda.md │     │  index.md,       │\",\n    \"│                 │     │  verify          │\",\n    \"└─────────────────┘     └──────────────────┘\",\n    \"```\",\n    \"\",\n    \"**Issue labels encode the phase:**\",\n    \"\",\n    \"| Label | Phase | Session work |\",\n    \"|-------|-------|-------------|\",\n    \"| `agenda:draft` | 1. Draft | Create dated folder if missing, select template by meeting type, write `agenda.md` with objective, outcomes, timed sections, pre-reads, parking lot. Inline-finalize when possible. |\",\n    \"| `agenda:finalize` | 2. Finalize | Register agenda in the meetings index, add cross-links to related docs, verify the folder contains the canonical artifact set. Only exists as a separate session when finalize work was deferred. |\",\n    \"\",\n    \"All issues also carry `type:agenda` and a `status:*` label.\",\n    \"\",\n    \"**Issue count per agenda:** usually **1** (`agenda:draft` only).\",\n    \"Small, well-specified agendas do not need a separate finalize\",\n    \"session — the draft phase does both draft and finalize in one\",\n    \"session. Create a separate `agenda:finalize` issue only when:\",\n    \"\",\n    \"- The agenda requires review by a non-agent reviewer before\",\n    \"  cross-linking.\",\n    \"- Finalize work is blocked on other deliverables (e.g., sprint plan\",\n    \"  not yet written).\",\n    \"- The draft was produced by a human and only needs agent-side\",\n    \"  linking.\",\n    \"\",\n    \"**Default path:** single `agenda:draft` session, finalize inline.\",\n    \"\",\n    \"---\",\n    \"\",\n    \"## Meeting Type Handling\",\n    \"\",\n    \"The issue body specifies `meeting_type` in its Context or Inputs\",\n    \"section. The agent matches `meeting_type` to the project's\",\n    \"**Recognized meeting types** table (rendered below when the\",\n    \"consuming project declares `AgentConfigOptions.meetings.meetingTypes`)\",\n    \"and applies the matching row's `agendaTemplatePath` and\",\n    \"`defaultDurationMinutes`.\",\n    \"\",\n    \"**How to resolve the template:**\",\n    \"\",\n    \"1. Read `meeting_type` from the issue body.\",\n    \"2. Look up the matching `id` in the project's **Recognized meeting\",\n    \"   types** table. Use the `Agenda template` column value, resolved\",\n    \"   relative to the `agendaTemplateRoot` documented above the table\",\n    \"   (defaults to `<meetingsRoot>/_agenda-templates`).\",\n    \"3. If the table is absent, the `id` is unknown, or the template\",\n    \"   column is `—`, fall back to `<meetingsRoot>/_agenda-templates/_base.md`\",\n    \"   and note the gap in the agenda's Open Items section so the\",\n    \"   template can be added later.\",\n    \"\",\n    \"When the project has **not** declared any `meetingTypes` at all,\",\n    \"the agent uses `_base.md` unconditionally and relies on the issue\",\n    \"body for all per-meeting structure.\",\n    \"\",\n    \"---\",\n    \"\",\n    \"## Agent Loop\",\n    \"\",\n    \"Run this loop exactly once per session. Never start a second issue.\",\n    \"\",\n    \"1. Claim one open `type:agenda` issue. Phase priority:\",\n    \"   `agenda:finalize` > `agenda:draft` so a deferred finalize for an\",\n    \"   older agenda closes before a new draft starts.\",\n    \"2. Transition `status:ready` → `status:in-progress` and create the\",\n    \"   branch per your project's branch-naming convention.\",\n    \"3. Execute the phase handler that matches the issue's `agenda:*`\",\n    \"   label.\",\n    \"4. Commit, push, open a PR, and transition the issue to\",\n    \"   `status:ready-for-review` per your project's PR workflow.\",\n    \"   Stamp every PR you open with the `origin:agent` label — see the\",\n    \"   **Origin label** section below.\",\n    \"\",\n    \"---\",\n    \"\",\n    ...renderClaimVerificationSection(),\n    \"\",\n    \"---\",\n    \"\",\n    ...renderOriginStampSection(),\n    \"\",\n    \"---\",\n    \"\",\n    \"## Phase 1: Draft (`agenda:draft`)\",\n    \"\",\n    \"**Goal:** Produce a well-structured `agenda.md` in the meeting's\",\n    \"dated folder, with objective, desired outcomes, timed sections,\",\n    \"pre-reads, and a parking lot.\",\n    \"\",\n    \"**Budget:** Reading + one file write (`agenda.md`), plus an optional\",\n    \"folder creation and a small registry edit when inline-finalizing.\",\n    \"No web searches unless the issue explicitly asks for external\",\n    \"research.\",\n    \"\",\n    \"### Steps\",\n    \"\",\n    \"1. **Read the issue body.** Extract:\",\n    \"   - `meeting_type` — one of the `id`s in the project's\",\n    \"     **Recognized meeting types** table\",\n    \"   - `meeting_date` — `YYYY-MM-DD`\",\n    \"   - `meeting_slug` — kebab-case (becomes the folder name suffix)\",\n    \"   - `duration_min` — integer minutes (default from the type table\",\n    \"     if absent)\",\n    \"   - `attendees` — list of names/roles (internal) or\",\n    \"     names/companies (external)\",\n    \"   - `objective` — one-sentence decision-oriented goal\",\n    '   - `desired_outcomes` — 1–3 bullets describing \"done\"',\n    \"   - `pre_reads` — relative paths to existing docs (optional)\",\n    \"   - `related_docs` — relative paths for context (optional)\",\n    \"\",\n    \"2. **Block if under-specified.** If `objective` AND\",\n    \"   `desired_outcomes` are both missing and cannot be inferred from\",\n    \"   prior meeting notes or the template type, follow Blocked Issues\",\n    \"   below. Do not invent an objective.\",\n    \"\",\n    \"3. **Create or locate the dated folder.**\",\n    \"   ```\",\n    \"   <meetingsRoot>/<YYYY-MM-DD>-<slug>/\",\n    \"   ```\",\n    \"   If the folder does not exist, create it. If it exists (because\",\n    \"   the meeting-analyst already landed a transcript), reuse it. If an\",\n    \"   `agenda.md` already exists, read it and update rather than\",\n    \"   overwriting.\",\n    \"\",\n    \"4. **Load the matching template** by resolving `meeting_type`\",\n    \"   against the project's **Recognized meeting types** table. Follow\",\n    \"   the resolution rules in **Meeting Type Handling** above. If the\",\n    \"   type is unrecognized, load `_base.md` and note the gap in Open\",\n    \"   Items.\",\n    \"\",\n    \"5. **Read prior meeting notes for recurring series.** If\",\n    \"   `meeting_type` maps to kind `planning` or `review` in the\",\n    \"   project's meeting-types table (or, in the absence of a table,\",\n    \"   the issue body flags the meeting as recurring):\",\n    \"   - Glob `<meetingsRoot>/` for prior instances with the same\",\n    \"     `meeting_type` (by frontmatter `meeting_type:` field).\",\n    \"   - Read the most recent prior `notes.md`.\",\n    \"   - Carry forward open action items, unresolved questions, and\",\n    \"     `## Follow-up` entries into the new agenda under a\",\n    \"     `## Carryover from last meeting` section.\",\n    \"\",\n    \"6. **Write the agenda.** Populate the template with:\",\n    \"   - Frontmatter (see skeleton below)\",\n    \"   - Objective (single sentence)\",\n    \"   - Desired outcomes (1–3 bullets)\",\n    \"   - Attendees + roles\",\n    \"   - Pre-reads (relative markdown links only)\",\n    \"   - Timed sections with\",\n    \"     `[decide | discuss | inform | brainstorm]` tags\",\n    \"   - Parking lot\",\n    \"   - Action items placeholder (the meeting-analyst fills this in\",\n    \"     post-meeting)\",\n    \"   - Cross-link stub back to `notes.md` (created post-meeting)\",\n    \"\",\n    \"   **Frontmatter skeleton:**\",\n    \"   ```markdown\",\n    \"   ---\",\n    '   title: \"Agenda: <Meeting Name>\"',\n    \"   date: YYYY-MM-DD\",\n    \"   meeting_type: <type>\",\n    \"   duration_min: <N>\",\n    \"   attendees:\",\n    \"     - <Name> (<role>)\",\n    \"   status: proposed\",\n    \"   areas:\",\n    \"     - <area-id-from-the-project's-area-map>\",\n    \"   sidebar:\",\n    \"     hidden: true\",\n    \"   ---\",\n    \"   ```\",\n    \"\",\n    \"   `sidebar.hidden: true` keeps the agenda out of any autogenerated\",\n    \"   sidebar — only the folder's `index.md` should appear there.\",\n    \"\",\n    \"   **Duration check.** Sum of section times must equal\",\n    \"   `duration_min` ± 5 minutes. If it doesn't, adjust section times\",\n    \"   or cut content — do not ship a math-broken agenda.\",\n    \"\",\n    \"7. **Create the folder `index.md` if missing.** Populate it\",\n    \"   following the section-index-page contract in the\",\n    \"   `shared-editing-safety` rule:\",\n    \"   - Frontmatter `title` (short sidebar label) and `description`\",\n    \"     (one line).\",\n    \"   - A 2–4 sentence summary of the meeting's objective and desired\",\n    \"     outcomes pulled from the agenda.\",\n    \"   - A `## Documents` section linking to `./agenda.md` (and\",\n    \"     `./notes.md` once the meeting-analyst produces it).\",\n    \"   - No body `# Heading` — the frontmatter `title:` already\",\n    \"     renders as the page H1.\",\n    \"\",\n    \"   Do NOT set `sidebar.hidden: true` on `index.md` — it is the page\",\n    \"   that should appear in the sidebar.\",\n    \"\",\n    \"8. **Inline finalize (default).** Unless a separate\",\n    \"   `agenda:finalize` issue was created, complete these steps in the\",\n    \"   same session:\",\n    \"   - Register the agenda in `<meetingsRoot>/index.md` (append to\",\n    \"     the meeting registry table).\",\n    \"   - Add a forward link from any related doc in `related_docs` to\",\n    \"     the agenda, using a relative markdown link.\",\n    \"   - Verify the dated folder contains at minimum `agenda.md`.\",\n    \"     Transcript and notes will land later via the meeting-analyst.\",\n    \"\",\n    \"9. **Commit and push.**\",\n    \"\",\n    \"---\",\n    \"\",\n    \"## Phase 2: Finalize (`agenda:finalize`)\",\n    \"\",\n    \"**Goal:** Complete the registry updates and cross-linking that were\",\n    \"deferred from the draft phase. Only runs when an explicit\",\n    \"`agenda:finalize` issue exists.\",\n    \"\",\n    \"**Budget:** Reading + small edits to `index.md` and related docs.\",\n    \"No new agenda file writes.\",\n    \"\",\n    \"### Steps\",\n    \"\",\n    \"1. **Read the draft agenda** at\",\n    \"   `<meetingsRoot>/<YYYY-MM-DD>-<slug>/agenda.md`.\",\n    \"\",\n    \"2. **Incorporate late-added items.** The finalize phase is the\",\n    \"   last chance to add attendee-requested sections before the\",\n    \"   meeting starts. Read any comments on the `agenda:finalize`\",\n    \"   issue for late additions; fold them into timed sections and\",\n    \"   re-balance durations so the sum still equals `duration_min` ±5.\",\n    \"   If late additions exceed the remaining budget, move the lowest-\",\n    \"   priority existing section to the parking lot rather than\",\n    \"   overrunning the duration.\",\n    \"\",\n    \"3. **Register in the meeting index.** Append to\",\n    \"   `<meetingsRoot>/index.md` if not already listed.\",\n    \"\",\n    \"4. **Add forward links** from each doc in the agenda's\",\n    \"   `related_docs` frontmatter field (if any). Use relative markdown\",\n    \"   links.\",\n    \"\",\n    \"5. **Lock the agenda.** Update the agenda's frontmatter\",\n    \"   `status: proposed` → `status: locked` to signal the agenda is\",\n    \"   frozen before the meeting starts. Late-breaking items that\",\n    \"   arrive after this point go on the meeting's parking lot during\",\n    \"   the meeting itself, not the agenda.\",\n    \"\",\n    \"6. **Verify artifact set.** Confirm the dated folder has at least\",\n    \"   `agenda.md` and `index.md`. Do not wait for `notes.md` or a\",\n    \"   transcript — those land post-meeting via the meeting-analyst.\",\n    \"\",\n    \"7. **Commit and push.**\",\n    \"\",\n    \"---\",\n    \"\",\n    \"## Coordination with Other Agents\",\n    \"\",\n    \"### Downstream Consumers\",\n    \"\",\n    \"| Output | Consumed by |\",\n    \"|--------|------------|\",\n    \"| `agenda.md` in dated folder | Humans running the meeting; the `meeting-analyst` reads it when processing the resulting transcript. |\",\n    \"| Registry entry in `<meetingsRoot>/index.md` | Humans browsing meetings; search indexing. |\",\n    \"| Forward links from related docs | Human readers of those docs. |\",\n    \"\",\n    \"### Upstream Sources\",\n    \"\",\n    \"| Input | Produced by |\",\n    \"|-------|------------|\",\n    \"| Prior `notes.md` for recurring series | `meeting-analyst` (post-prior-meeting). |\",\n    \"| Sprint plan for planning-kind meetings | `meeting-analyst` Phase 4 or the orchestrator. |\",\n    \"| Roadmap for strategy-kind meetings | Product docs maintained by the `meeting-analyst`. |\",\n    \"| Company/people profiles for external-meeting pre-reads | `company-profile` / `people-profile` agents. |\",\n    \"\",\n    \"### File Boundaries\",\n    \"\",\n    \"- **Reads:** `<docsRoot>/` (any file, for pre-reads, related docs,\",\n    \"  and carryover lookup).\",\n    \"- **Writes:**\",\n    \"  - `<meetingsRoot>/<YYYY-MM-DD>-<slug>/agenda.md`\",\n    \"  - `<meetingsRoot>/<YYYY-MM-DD>-<slug>/index.md`\",\n    \"  - `<meetingsRoot>/index.md` (append registry entries)\",\n    \"  - Small cross-link edits to related docs (≤10 lines, forward\",\n    \"    links only)\",\n    \"- **Never writes to:**\",\n    \"  - `notes.md` in any meeting folder (the `meeting-analyst` owns\",\n    \"    this)\",\n    \"  - Transcript files in any meeting folder (tooling / human)\",\n    \"  - `<requirementsRoot>/`, `<bcmRoot>/`, `<peopleRoot>/`,\",\n    \"    `<companiesRoot>/`, `<softwareRoot>/`, `<industriesRoot>/`\",\n    \"    (specialist agents own these)\",\n    \"  - Meeting extraction files (the `meeting-analyst` owns extracts)\",\n    \"\",\n    \"---\",\n    \"\",\n    \"## Blocked Issues\",\n    \"\",\n    \"Follow your project's shared Blocked Issues procedure. Additional\",\n    \"block reasons specific to agenda drafting:\",\n    \"\",\n    \"- **Objective missing and not inferrable.** The issue body has no\",\n    \"  objective and no prior meeting notes or related docs that imply\",\n    \"  one.\",\n    \"- **Attendees unknown.** External meetings especially — an agenda\",\n    \"  cannot be tuned without knowing who is in the room.\",\n    \"- **Duration conflict.** The issue specifies a duration that cannot\",\n    \"  fit the stated outcomes even with aggressive time-boxing.\",\n    \"- **Unrecognized `meeting_type` and no fallback viable.** If\",\n    \"  `meeting_type` is unrecognized AND `_base.md` is insufficient\",\n    \"  (the meeting pattern does not fit any existing template), block\",\n    \"  so a human can either add a template or reclassify the meeting.\",\n    \"\",\n    \"---\",\n    \"\",\n    \"## Rules\",\n    \"\",\n    \"- **Objective or block.** No agenda ships without a stated\",\n    \"  objective and at least one desired outcome. If the issue does\",\n    \"  not supply one and none can be inferred, block — do not invent.\",\n    \"- **Time-box every section.** Sum must equal `duration_min` ± 5.\",\n    \"  No untimed sections except Parking Lot.\",\n    \"- **Intent tag per section.** Every timed section carries\",\n    \"  `[decide]`, `[discuss]`, `[inform]`, or `[brainstorm]`.\",\n    \"- **Link, don't copy.** Pre-reads are relative markdown links to\",\n    \"  existing docs. The agent never inlines content from another doc\",\n    \"  into the agenda.\",\n    \"- **Dated folder is canonical.** `agenda.md` lives alongside\",\n    \"  `notes.md` (landed post-meeting) in the same `YYYY-MM-DD-<slug>/`\",\n    \"  folder. The agent creates the folder if needed but never writes\",\n    \"  outside it for agenda content.\",\n    \"- **Async suggestion for decision-free meetings.** If the agent\",\n    \"  cannot identify any `[decide]` sections in a meeting that has no\",\n    \"  recurring-ritual justification, the agent should comment on the\",\n    \"  issue suggesting the meeting be converted to an async update\",\n    \"  before writing the agenda.\",\n    \"- **Recurring-series carryover.** For recurring meetings (kind\",\n    \"  `planning` or `review`), read the prior instance's `notes.md`\",\n    \"  and carry forward open items, unresolved questions, and\",\n    \"  follow-up commitments.\",\n    \"- **Registry freshness.** Every new agenda adds a row to\",\n    \"  `<meetingsRoot>/index.md`. No silent publishes.\",\n    \"- **Bidirectional traceability.** The agenda's `notes.md` link\",\n    \"  stub and the notes file's forward link to the agenda form the\",\n    \"  round-trip. Once `notes.md` is written by the meeting-analyst,\",\n    \"  both files link to each other via relative markdown paths.\",\n    \"- **Never cross agent boundaries.** Do not write `notes.md`,\",\n    \"  transcripts, extracts, requirements, ADRs, or profiles. If the\",\n    \"  agenda work surfaces a need for any of those, create the\",\n    \"  appropriate issue for the specialist agent instead.\",\n  ].join(\"\\n\"),\n};\n\n/** Skill that kicks off the draft phase of an agenda cycle. */\nconst draftAgendaSkill: AgentSkill = {\n  name: \"draft-agenda\",\n  description:\n    \"Kick off the draft phase of a meeting-agenda cycle. Creates an agenda:draft issue for the supplied meeting (type, date, slug, objective, outcomes) and dispatches Phase 1 of the agenda-analyst, which writes agenda.md to the meeting's dated folder.\",\n  disableModelInvocation: true,\n  userInvocable: true,\n  context: \"fork\",\n  agent: \"agenda-analyst\",\n  platforms: { cursor: { exclude: true } },\n  instructions: [\n    \"# Draft Agenda\",\n    \"\",\n    \"Kick off a meeting-agenda cycle. Creates an `agenda:draft` issue\",\n    \"targeted at the requested meeting and dispatches Phase 1 (Draft)\",\n    \"in the agenda-analyst agent. If a separate finalize pass is\",\n    \"needed, Phase 1 creates the `agenda:finalize` issue automatically;\",\n    \"otherwise the draft phase inline-finalizes in the same session.\",\n    \"\",\n    \"## Usage\",\n    \"\",\n    \"/draft-agenda <meeting-type>:<YYYY-MM-DD>-<slug>\",\n    \"\",\n    \"Where:\",\n    \"- `<meeting-type>` — one of the `id`s from the project's\",\n    \"  **Recognized meeting types** table (rendered into the\",\n    \"  agenda-analyst prompt when the consuming project declares\",\n    \"  `AgentConfigOptions.meetings.meetingTypes`).\",\n    \"- `<YYYY-MM-DD>` — the meeting date.\",\n    \"- `<slug>` — a kebab-case short name for the meeting (becomes the\",\n    \"  folder name suffix).\",\n    \"\",\n    \"Examples (the meeting-type `id`s below are illustrative — use\",\n    \"whatever `id`s your project declares in `meetingTypes`):\",\n    \"- `team-weekly:2026-04-24-weekly-sync`\",\n    \"- `customer-discovery:2026-04-28-prospect-intro`\",\n    \"\",\n    \"## Steps\",\n    \"\",\n    \"1. Create an `agenda:draft` issue with `type:agenda`,\",\n    \"   `priority:high`, and `status:ready`. The body must list:\",\n    \"   - `meeting_type` — from the `<meeting-type>` segment\",\n    \"   - `meeting_date` — from the `<YYYY-MM-DD>` segment\",\n    \"   - `meeting_slug` — from the `<slug>` segment\",\n    \"   - `duration_min` — optional (defaults to the type table value)\",\n    \"   - `attendees` — list of names/roles\",\n    \"   - `objective` — one-sentence decision-oriented goal\",\n    '   - `desired_outcomes` — 1–3 bullets describing \"done\"',\n    \"   - `pre_reads` — relative paths to existing docs (optional)\",\n    \"   - `related_docs` — relative paths for context (optional)\",\n    \"\",\n    ...renderIssueTypeAssignmentStep(),\n    \"\",\n    \"2. Execute Phase 1 (Draft) of the agenda-analyst agent.\",\n    \"3. If the draft phase inline-finalizes (default path), no\",\n    \"   downstream issues are created.\",\n    \"4. If finalize work is deferred, Phase 1 creates an\",\n    \"   `agenda:finalize` issue blocked on the draft issue.\",\n    \"\",\n    \"## Output\",\n    \"\",\n    \"- `<meetingsRoot>/<YYYY-MM-DD>-<slug>/agenda.md` — the agenda\",\n    \"  itself, with frontmatter, objective, outcomes, timed intent-\",\n    \"  tagged sections, pre-reads, and a parking lot.\",\n    \"- `<meetingsRoot>/<YYYY-MM-DD>-<slug>/index.md` — folder index\",\n    \"  page that appears in the docs sidebar.\",\n    \"- A registry row in `<meetingsRoot>/index.md`.\",\n    \"- An `agenda:finalize` issue (only when finalize work was\",\n    \"  deferred).\",\n  ].join(\"\\n\"),\n};\n\n/**\n * Skill that kicks off the finalize phase of an agenda cycle.\n * Only needed when the draft phase deferred finalize work — most\n * agenda cycles inline-finalize and do not need this skill.\n */\nconst finalizeAgendaSkill: AgentSkill = {\n  name: \"finalize-agenda\",\n  description:\n    \"Kick off the finalize phase of a meeting-agenda cycle. Creates an agenda:finalize issue for an already-drafted agenda and dispatches Phase 2 of the agenda-analyst, which incorporates late-added items, registers the agenda in the meeting index, cross-links related docs, and locks the agenda before the meeting starts.\",\n  disableModelInvocation: true,\n  userInvocable: true,\n  context: \"fork\",\n  agent: \"agenda-analyst\",\n  platforms: { cursor: { exclude: true } },\n  instructions: [\n    \"# Finalize Agenda\",\n    \"\",\n    \"Close the loop on a meeting-agenda cycle whose draft phase deferred\",\n    \"finalize work. Creates an `agenda:finalize` issue and dispatches\",\n    \"Phase 2 (Finalize) in the agenda-analyst agent.\",\n    \"\",\n    \"Phase 2 incorporates late-added items (from comments on the\",\n    \"finalize issue), registers the agenda in the meetings index,\",\n    \"cross-links related docs, and locks the agenda before the meeting\",\n    \"starts.\",\n    \"\",\n    \"Most cycles do not need this skill — Phase 1 (Draft) inline-\",\n    \"finalizes by default. Use this skill when:\",\n    \"- The draft phase explicitly deferred finalize work (an\",\n    \"  `agenda:finalize` issue was created during draft).\",\n    \"- The draft was produced by a human and only needs agent-side\",\n    \"  linking.\",\n    \"- Late-breaking items arrived after draft and need to be folded\",\n    \"  in before the meeting starts.\",\n    \"\",\n    \"## Usage\",\n    \"\",\n    \"/finalize-agenda <YYYY-MM-DD>-<slug>\",\n    \"\",\n    \"Where `<YYYY-MM-DD>-<slug>` identifies the dated meeting folder\",\n    \"that already contains an `agenda.md`.\",\n    \"\",\n    \"Example:\",\n    \"- `/finalize-agenda 2026-04-24-weekly-sync`\",\n    \"\",\n    \"## Steps\",\n    \"\",\n    \"1. Create an `agenda:finalize` issue with `type:agenda`,\",\n    \"   `priority:high`, and `status:ready`. Body must list:\",\n    \"   - Path to the draft agenda\",\n    \"     (`<meetingsRoot>/<YYYY-MM-DD>-<slug>/agenda.md`)\",\n    \"   - Any late-added items to incorporate\",\n    \"\",\n    ...renderIssueTypeAssignmentStep(),\n    \"\",\n    \"2. Execute Phase 2 (Finalize) of the agenda-analyst agent.\",\n    \"\",\n    \"## Output\",\n    \"\",\n    \"- Updates to `<meetingsRoot>/<YYYY-MM-DD>-<slug>/agenda.md`\",\n    \"  (frontmatter `status: proposed` → `status: locked`, plus\",\n    \"  incorporated late items).\",\n    \"- A new row in `<meetingsRoot>/index.md` (if not already\",\n    \"  registered).\",\n    \"- Small forward-link edits in related docs.\",\n  ].join(\"\\n\"),\n};\n\n/**\n * Agenda bundle — enabled by default.\n *\n * Consuming projects can disable it with\n * `excludeBundles: [\"agenda\"]`. `appliesWhen` always returns `true`\n * (peer-present assumption, same pattern as the other workflow\n * bundles).\n *\n * Provides a 2-phase pre-meeting agenda pipeline\n * (draft → finalize), complementing the post-meeting pipeline in\n * the `meeting-analysis` bundle. Ships a sub-agent, two user-\n * invocable skills (`/draft-agenda`, `/finalize-agenda`), and\n * `agenda:*` phase labels via the bundle `labels` mechanism so\n * consuming projects automatically pick up the label taxonomy\n * through the sync-labels workflow.\n *\n * Reuses the meeting-type taxonomy from\n * `AgentConfigOptions.meetings.meetingTypes` — the same table the\n * `meeting-analysis` bundle consumes for post-meeting extraction.\n */\nexport const agendaBundle: AgentRuleBundle = {\n  name: \"agenda\",\n  description:\n    \"Meeting-agenda authoring bundle. 2-phase pipeline (draft, finalize) with agenda:* phase labels for producing pre-meeting agendas from the project's meeting-type taxonomy. Complements the meeting-analysis bundle, which handles the post-meeting pipeline. Enabled by default.\",\n  appliesWhen: () => true,\n  rules: [\n    {\n      name: \"meeting-agenda-workflow\",\n      description:\n        \"Describes the 2-phase pre-meeting agenda pipeline, the agenda:* label taxonomy, and the relationship to the meeting-analysis bundle.\",\n      scope: AGENT_RULE_SCOPE.ALWAYS,\n      content: [\n        \"# Meeting Agenda Workflow\",\n        \"\",\n        \"Use `/draft-agenda <meeting-type>:<YYYY-MM-DD>-<slug>` to kick\",\n        \"off a pre-meeting agenda cycle. The pipeline runs in 2 phases —\",\n        \"draft and finalize — each tracked by its own GitHub issue\",\n        \"labeled `agenda:draft` or `agenda:finalize`. All issues carry\",\n        \"`type:agenda`.\",\n        \"\",\n        \"One additional user-invocable skill drives the finalize phase\",\n        \"on demand:\",\n        \"\",\n        \"- `/finalize-agenda <YYYY-MM-DD>-<slug>` — register the agenda\",\n        \"  in the meetings index, add cross-links, incorporate late-\",\n        \"  added items, and lock the agenda before the meeting starts.\",\n        \"  Phase 1 (Draft) normally inline-finalizes — this skill is\",\n        \"  the explicit entry point when finalize work was deferred or\",\n        \"  a human authored the draft.\",\n        \"\",\n        \"The agenda bundle *writes pre-meeting agendas*; the\",\n        \"`meeting-analysis` bundle *processes post-meeting transcripts\",\n        \"and notes*. Together they close the loop:\",\n        \"**agenda → meeting → transcript → notes → follow-up work**.\",\n        \"The agenda bundle reuses the `meeting_type` taxonomy declared\",\n        \"via `AgentConfigOptions.meetings.meetingTypes` — the same\",\n        \"taxonomy the `meeting-analysis` bundle consumes for post-\",\n        \"meeting extraction.\",\n        \"\",\n        \"See the `agenda-analyst` agent definition for full workflow\",\n        \"details and phase-by-phase instructions.\",\n      ].join(\"\\n\"),\n      platforms: {\n        cursor: { exclude: true },\n      },\n      tags: [\"workflow\"],\n    },\n  ],\n  skills: [draftAgendaSkill, finalizeAgendaSkill],\n  subAgents: [agendaAnalystSubAgent],\n  labels: [\n    {\n      name: \"type:agenda\",\n      color: \"5319E7\",\n      description:\n        \"Work that authors a pre-meeting agenda for a scheduled meeting\",\n    },\n    {\n      name: \"agenda:draft\",\n      color: \"C5DEF5\",\n      description:\n        \"Phase 1: draft an agenda for a scheduled meeting (template, objective, timed sections, pre-reads)\",\n    },\n    {\n      name: \"agenda:finalize\",\n      color: \"BFDADC\",\n      description:\n        \"Phase 2: register in meetings index, cross-link related docs, and lock the agenda before the meeting\",\n    },\n  ],\n};\n","import { Component, Project } from \"projen/lib\";\n\n/**\n * Return the project and/or subprojects that have a component of a given type.\n * Walks one level of subprojects (does not recurse into sub-subprojects).\n */\nexport function findProjectsWithComponent<T extends Component>(\n  project: Project,\n  ctor: new (...args: any[]) => T,\n): Array<Project> {\n  const out: Array<Project> = [];\n  if (project.components.some((c) => c instanceof ctor)) {\n    out.push(project);\n  }\n  for (const sub of project.subprojects) {\n    if (sub.components.some((c) => c instanceof ctor)) {\n      out.push(sub);\n    }\n  }\n  return out;\n}\n\n/**\n * Return the project and/or subprojects that declare a dependency with the\n * given name. Walks one level of subprojects.\n */\nexport function findProjectsWithDep(\n  project: Project,\n  name: string,\n): Array<Project> {\n  const out: Array<Project> = [];\n  if (project.deps.all.some((d) => d.name === name)) {\n    out.push(project);\n  }\n  for (const sub of project.subprojects) {\n    if (sub.deps.all.some((d) => d.name === name)) {\n      out.push(sub);\n    }\n  }\n  return out;\n}\n\n/**\n * Return the project and/or subprojects that contain a file with the given\n * name. Walks one level of subprojects.\n */\nexport function findProjectsWithFile(\n  project: Project,\n  filename: string,\n): Array<Project> {\n  const out: Array<Project> = [];\n  if (project.tryFindFile(filename) !== undefined) {\n    out.push(project);\n  }\n  for (const sub of project.subprojects) {\n    if (sub.tryFindFile(filename) !== undefined) {\n      out.push(sub);\n    }\n  }\n  return out;\n}\n\n/**\n * Check whether a component of a given type exists on the project or any subproject.\n */\nexport function hasComponent<T extends Component>(\n  project: Project,\n  ctor: new (...args: any[]) => T,\n): boolean {\n  return findProjectsWithComponent(project, ctor).length > 0;\n}\n\n/**\n * Check whether a dependency exists on the project or any subproject.\n */\nexport function hasDep(project: Project, name: string): boolean {\n  return findProjectsWithDep(project, name).length > 0;\n}\n\n/**\n * Check whether a file exists on the project or any subproject.\n */\nexport function hasFile(project: Project, filename: string): boolean {\n  return findProjectsWithFile(project, filename).length > 0;\n}\n","import { Project } from \"projen/lib\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\nimport { findProjectsWithDep, hasDep } from \"./utils\";\n\n/**\n * AWS CDK bundle — auto-detected when `aws-cdk-lib` is in dependencies.\n */\nexport const awsCdkBundle: AgentRuleBundle = {\n  name: \"aws-cdk\",\n  description:\n    \"AWS CDK construct patterns, L2/L3 conventions, IAM best practices\",\n  appliesWhen: (project: Project) => hasDep(project, \"aws-cdk-lib\"),\n  findApplicableProjects: (project: Project) =>\n    findProjectsWithDep(project, \"aws-cdk-lib\"),\n  rules: [\n    {\n      name: \"aws-cdk-conventions\",\n      description: \"AWS CDK construct patterns and best practices\",\n      scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n      filePatterns: [\"**/*.ts\"],\n      content: [\n        \"# AWS CDK Conventions\",\n        \"\",\n        \"## Construct Structure\",\n        \"\",\n        \"- All constructs extend `Construct` from `constructs`\",\n        \"- Use `readonly` for all props interfaces\",\n        \"- Include minimal JSDoc for configuration options\",\n        \"- Follow AWS CDK best practices for resource naming and organization\",\n        \"- Use proper TypeScript types from `aws-cdk-lib`\",\n        \"- Export constructs from `index.ts` for public API\",\n        \"\",\n        \"## CDK Construct Pattern\",\n        \"\",\n        \"```typescript\",\n        \"export interface MyConstructProps {\",\n        \"  /** Brief description. */\",\n        \"  readonly myProperty: string;\",\n        \"}\",\n        \"\",\n        \"export class MyConstruct extends Construct {\",\n        \"  constructor(scope: Construct, id: string, props: MyConstructProps) {\",\n        \"    super(scope, id);\",\n        \"    // Implementation\",\n        \"  }\",\n        \"}\",\n        \"```\",\n        \"\",\n        \"## L2 Over L1 Construct Preference\",\n        \"\",\n        \"- Always prefer L2 constructs (e.g., `s3.Bucket`, `lambda.Function`) over L1 escape hatches (`CfnBucket`, `CfnFunction`)\",\n        \"- Only drop to L1 when the L2 construct is missing the feature you need or does not exist yet\",\n        \"- When using L1, add a comment explaining why the L2 was insufficient\",\n        \"\",\n        \"## Filename / Class Name Matching\",\n        \"\",\n        \"- Kebab-case filenames must mirror PascalCase class names (e.g., `my-construct.ts` → `MyConstruct`)\",\n        \"- Name props interfaces `ClassNameProps` (e.g., `MyConstructProps`)\",\n        \"- One primary construct per file; supporting types (props interface, enums) live in the same file\",\n        \"- Test files follow the same pattern: `my-construct.spec.ts`\",\n        \"- When renaming, prefer renaming the class to match the filename\",\n        \"\",\n        \"## Cross-Stack Lookup Patterns\",\n        \"\",\n        \"- Lookups live on **service classes**, not component/construct classes — do not add `fromConstruct()` or similar lookup methods to component classes\",\n        \"- Use `*.of(this)` for stack or service references where the pattern exists in the codebase\",\n        \"- Within services, prefer creating resources in protected methods; expose retrieval via static methods on the owning service\",\n        \"- Use static methods for cross-stack lookups so consumers don't need an instance:\",\n        \"\",\n        \"```typescript\",\n        \"export class MyService {\",\n        \"  /** Look up a resource from another stack via SSM. */\",\n        \"  public static lookupArn(scope: Construct, id: string): string {\",\n        \"    return StringParameter.valueForStringParameter(\",\n        \"      scope,\",\n        \"      `/my-app/my-resource-arn`,\",\n        \"    );\",\n        \"  }\",\n        \"}\",\n        \"```\",\n        \"\",\n        \"- Store outputs in SSM parameters with well-known paths; do not pass values between stacks via props\",\n        \"\",\n        \"## AWS Best Practices\",\n        \"\",\n        \"- Use AWS CDK v2 (`aws-cdk-lib`)\",\n        \"- Follow AWS best practices for security and resource configuration\",\n        \"- Use proper IAM permissions (principle of least privilege)\",\n        \"- Include proper tags and descriptions for resources\",\n        \"- Use SSM parameters for cross-stack references when needed\",\n        \"- Do not pass values between stacks; use SSM parameters instead\",\n        \"\",\n        \"## Lambda Handlers (NodejsFunction)\",\n        \"\",\n        \"- When adding a `NodejsFunction` with a bundled handler, ensure the `entry` path is explicitly configured\",\n        \"- Verify the entry is included in the build tool config (e.g., tsup entry list) so the runtime can find the handler\",\n        \"\",\n        \"## Lambda Construct Encapsulation\",\n        \"\",\n        \"When a Lambda construct is event-driven, it should own:\",\n        \"\",\n        \"- The EventBridge Rule (or other trigger) that routes events to itself.\",\n        \"- The IAM permissions it needs on resources passed in via props.\",\n        \"\",\n        \"Pass the resources (event bus, table, queue, etc.) into the Lambda\",\n        \"construct's props rather than defining triggers and grants in the\",\n        \"enclosing workflow or service. The Lambda construct then becomes\",\n        'self-describing — \"what triggers me, what I write to\" lives in one',\n        \"file — and reverting or refactoring a single Lambda doesn't ripple\",\n        \"through unrelated constructs.\",\n        \"\",\n        \"```typescript\",\n        \"export interface MyLambdaProps {\",\n        \"  readonly eventBus: IEventBus;\",\n        \"  readonly dataStoreTable: ITable;\",\n        \"}\",\n        \"\",\n        \"export class MyLambda extends Construct {\",\n        \"  public readonly lambda: NodejsFunction;\",\n        \"  public readonly rule: Rule;\",\n        \"\",\n        \"  constructor(scope: Construct, props: MyLambdaProps) {\",\n        '    super(scope, \"my-lambda\");',\n        \"\",\n        '    this.lambda = new NodejsFunction(this, \"handler\", { /* ... */ });',\n        \"    props.dataStoreTable.grantReadWriteData(this.lambda);\",\n        '    this.rule = new Rule(this, \"rule\", {',\n        \"      eventBus: props.eventBus,\",\n        \"      eventPattern: { /* ... */ },\",\n        \"      targets: [new LambdaFunction(this.lambda)],\",\n        \"    });\",\n        \"  }\",\n        \"}\",\n        \"```\",\n        \"\",\n        \"A workflow or service construct then composes these Lambda constructs\",\n        \"without owning their triggers or grants directly.\",\n        \"\",\n        \"## CDK Testing\",\n        \"\",\n        \"- Mock `Code.fromAsset` in any test file that synthesizes CDK stacks\",\n        \"- Use static S3 values (`mock-assets-bucket`, `mock-asset-key.zip`) so snapshots are stable\",\n        \"- Add the mock in `beforeAll` and restore in `afterAll`:\",\n        \"\",\n        \"```typescript\",\n        \"let fromAssetMock: MockInstance;\",\n        \"\",\n        \"beforeAll(() => {\",\n        '  fromAssetMock = vi.spyOn(Code, \"fromAsset\").mockReturnValue({',\n        \"    isInline: false,\",\n        \"    bind: () => ({\",\n        \"      s3Location: {\",\n        '        bucketName: \"mock-assets-bucket\",',\n        '        objectKey: \"mock-asset-key.zip\",',\n        \"      },\",\n        \"    }),\",\n        \"    bindToResource: () => {},\",\n        \"  } as unknown as AssetCode);\",\n        \"});\",\n        \"\",\n        \"afterAll(() => {\",\n        \"  fromAssetMock.mockRestore();\",\n        \"});\",\n        \"```\",\n        \"\",\n        \"- Normalize the template before snapshotting when the stack includes asset-based Lambdas\",\n        \"- Use `Template.fromStack(stack)` and assert with `hasResourceProperties` for targeted checks\",\n      ].join(\"\\n\"),\n      tags: [\"infrastructure\"],\n    },\n  ],\n};\n","import {\n  IssueDefaultsConfig,\n  IssueDefaultsOverride,\n} from \"../agent-config-options\";\n\n/**\n * Valid `status:*` values that may appear in an\n * `IssueDefaultsOverride.status`. The list mirrors the canonical\n * status taxonomy documented in the `issue-label-conventions` rule\n * — every value here renders as a `status:<value>` label on the\n * downstream `gh issue create` invocation.\n *\n * `deferred` is included so consumers can route low-priority\n * downstream byproducts (e.g. `people:research` follow-ups in a\n * research-heavy planning repo) into a manually-promoted backlog\n * instead of the auto-dispatch queue.\n */\nexport const VALID_STATUS_VALUES = [\n  \"ready\",\n  \"blocked\",\n  \"in-progress\",\n  \"ready-for-review\",\n  \"needs-attention\",\n  \"done\",\n  \"deferred\",\n] as const;\n\nexport type IssueDefaultsStatus = (typeof VALID_STATUS_VALUES)[number];\n\n/**\n * Valid `priority:*` values that may appear in an\n * `IssueDefaultsOverride.priority`. Mirrors the five-level priority\n * taxonomy documented in the `issue-label-conventions` rule.\n */\nexport const VALID_PRIORITY_VALUES = [\n  \"critical\",\n  \"high\",\n  \"medium\",\n  \"low\",\n  \"trivial\",\n] as const;\n\nexport type IssueDefaultsPriority = (typeof VALID_PRIORITY_VALUES)[number];\n\n/**\n * Bundle-shipped defaults used when no `issueDefaults[<phase>]`\n * override is configured. `ready` / `medium` matches the historical\n * hardcoded values every bundle carried before this knob existed.\n */\nexport const DEFAULT_ISSUE_STATUS: IssueDefaultsStatus = \"ready\";\nexport const DEFAULT_ISSUE_PRIORITY: IssueDefaultsPriority = \"medium\";\n\n/**\n * Fully-resolved per-phase-label entry. Every field is filled in so\n * downstream callers can render `status:<value>` / `priority:<value>`\n * label lines without re-checking for `undefined`.\n */\nexport interface ResolvedIssueDefaultsEntry {\n  readonly status: IssueDefaultsStatus;\n  readonly priority: IssueDefaultsPriority;\n}\n\n/**\n * Fully-resolved issue-defaults configuration. The `overrides` map\n * is keyed by phase label (e.g. `people:research`, `company:draft`,\n * `req:write`) — not by `type:*` — so consumers can discriminate per\n * phase. The `defaults` field carries the bundle-shipped fallback\n * values (`ready` / `medium`) callers fall back to when no override\n * is configured for a given phase.\n */\nexport interface ResolvedIssueDefaults {\n  readonly defaults: ResolvedIssueDefaultsEntry;\n  readonly overrides: Readonly<Record<string, ResolvedIssueDefaultsEntry>>;\n}\n\n/**\n * Default-everything resolved instance. Used by bundle factories\n * when the consumer supplies no override at all (the common case).\n */\nexport const DEFAULT_RESOLVED_ISSUE_DEFAULTS: ResolvedIssueDefaults = {\n  defaults: {\n    status: DEFAULT_ISSUE_STATUS,\n    priority: DEFAULT_ISSUE_PRIORITY,\n  },\n  overrides: {},\n};\n\n/**\n * Resolve a (possibly absent) `IssueDefaultsConfig` into a canonical\n * `ResolvedIssueDefaults` with every override entry filled in.\n *\n * Each entry inside the consumer-supplied map may set `status`,\n * `priority`, or both. Missing fields cascade from the bundle\n * defaults (`ready` / `medium`) so a partially-specified entry\n * still resolves to a complete pair.\n *\n * Malformed configs throw a descriptive `Error`:\n *\n * - Empty / whitespace-only phase-label key.\n * - `status` set to a value outside `VALID_STATUS_VALUES`.\n * - `priority` set to a value outside `VALID_PRIORITY_VALUES`.\n * - Empty entry (neither `status` nor `priority` supplied) — the\n *   override would be a no-op and probably indicates a typo on the\n *   field name.\n */\nexport function resolveIssueDefaults(\n  config?: IssueDefaultsConfig,\n): ResolvedIssueDefaults {\n  if (config === undefined) {\n    return DEFAULT_RESOLVED_ISSUE_DEFAULTS;\n  }\n\n  const overrides: Record<string, ResolvedIssueDefaultsEntry> = {};\n  for (const [phaseLabel, override] of Object.entries(config)) {\n    assertValidPhaseLabel(phaseLabel);\n    assertValidOverride(phaseLabel, override);\n    overrides[phaseLabel] = {\n      status: override.status ?? DEFAULT_ISSUE_STATUS,\n      priority: override.priority ?? DEFAULT_ISSUE_PRIORITY,\n    };\n  }\n\n  return {\n    defaults: {\n      status: DEFAULT_ISSUE_STATUS,\n      priority: DEFAULT_ISSUE_PRIORITY,\n    },\n    overrides,\n  };\n}\n\n/**\n * Synth-time validation hook. Throws a descriptive `Error` when\n * the supplied `IssueDefaultsConfig` is malformed. Called by\n * `AgentConfig.preSynthesize` before any rendering so a misconfigured\n * override fails the build instead of silently shipping unrecognised\n * label values into bundle prompts. Returns the resolved config so\n * callers can write `const id = validateIssueDefaultsConfig(config)`\n * in one line.\n */\nexport function validateIssueDefaultsConfig(\n  config?: IssueDefaultsConfig,\n): ResolvedIssueDefaults {\n  return resolveIssueDefaults(config);\n}\n\n/**\n * Look up the effective `status` / `priority` pair for a phase label.\n * Returns the override entry when one is configured for the given\n * phase, otherwise the bundle defaults (`ready` / `medium`).\n *\n * The single canonical helper bundle prompt templates call when they\n * need to render the labels for a downstream filing — keeps every\n * filing site in sync with the same resolution rule.\n */\nexport function labelsForPhase(\n  resolved: ResolvedIssueDefaults,\n  phaseLabel: string,\n): ResolvedIssueDefaultsEntry {\n  return resolved.overrides[phaseLabel] ?? resolved.defaults;\n}\n\nfunction assertValidPhaseLabel(phaseLabel: string): void {\n  if (typeof phaseLabel !== \"string\" || phaseLabel.trim() === \"\") {\n    throw new Error(\n      \"AgentConfigOptions.issueDefaults: phase-label keys must be \" +\n        \"non-empty strings (e.g. `people:research`).\",\n    );\n  }\n}\n\nfunction assertValidOverride(\n  phaseLabel: string,\n  override: IssueDefaultsOverride,\n): void {\n  if (\n    override === null ||\n    typeof override !== \"object\" ||\n    Array.isArray(override)\n  ) {\n    throw new Error(\n      `AgentConfigOptions.issueDefaults[\"${phaseLabel}\"] must be an ` +\n        \"object with optional `status` and `priority` fields.\",\n    );\n  }\n\n  const { status, priority } = override;\n\n  if (status === undefined && priority === undefined) {\n    throw new Error(\n      `AgentConfigOptions.issueDefaults[\"${phaseLabel}\"] must declare ` +\n        \"at least one of `status` or `priority`. Empty entries are \" +\n        \"rejected because they are almost always a typo on the field name.\",\n    );\n  }\n\n  if (status !== undefined && !VALID_STATUS_VALUES.includes(status)) {\n    throw new Error(\n      `AgentConfigOptions.issueDefaults[\"${phaseLabel}\"].status=\"${status}\" ` +\n        `is not a recognised status value. Allowed values: ${VALID_STATUS_VALUES.join(\", \")}.`,\n    );\n  }\n\n  if (priority !== undefined && !VALID_PRIORITY_VALUES.includes(priority)) {\n    throw new Error(\n      `AgentConfigOptions.issueDefaults[\"${phaseLabel}\"].priority=\"${priority}\" ` +\n        `is not a recognised priority value. Allowed values: ${VALID_PRIORITY_VALUES.join(\", \")}.`,\n    );\n  }\n}\n","import {\n  renderPhaseTypeInvariantShellHelpers,\n  typeLabelForPhaseLabel,\n} from \"./bundle-ownership\";\nimport {\n  DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n  IssueDefaultsPriority,\n  IssueDefaultsStatus,\n  ResolvedIssueDefaults,\n  labelsForPhase,\n} from \"./issue-defaults\";\nimport {\n  DEFAULT_GITHUB_ISSUE_TYPE,\n  GithubIssueType,\n  SET_ISSUE_TYPE_HELPER_PATH,\n  githubIssueTypeForTitle,\n} from \"./issue-type\";\nimport { AgentRuleBundle, IssueTemplatesConfig } from \"../agent-config-options\";\n\n/**\n * Default master switch for the issue-templates convention. When no\n * config is supplied the convention ships **enabled** so every\n * configulator-consuming repo carries the canonical `gh issue create`\n * template reference in its rendered `CLAUDE.md`.\n *\n * @see IssueTemplatesConfig\n */\nexport const DEFAULT_ISSUE_TEMPLATES_ENABLED = true;\n\n/**\n * Default repo-relative path for the consolidated issue-templates\n * documentation page. Matches the singleton `/docs` site layout every\n * configulator-managed repo ships: a single Starlight docs site at\n * `/docs` with agent reference pages under\n * `docs/src/content/docs/agents/`.\n *\n * The file is never generated by configulator unless `emitStarterDoc`\n * is set — the canonical list of templates is repo-specific and grows\n * whenever a new phase label is minted, so consumers author and evolve\n * the page themselves. The starter doc is opt-in.\n *\n * @see IssueTemplatesConfig\n */\nexport const DEFAULT_ISSUE_TEMPLATES_PATH =\n  \"docs/src/content/docs/agents/issue-templates.md\";\n\n/**\n * Default list of glob patterns that identify \"bundle files\" — the\n * source files that compose agent prompts and skill instructions.\n * These are the locations the optional lint walks when checking that\n * `gh issue create` snippets are **referenced** rather than inlined.\n *\n * The defaults cover the locations bundle-like content lives in a\n * generic configulator-consuming repo:\n *\n * - `.claude/agents/**.md` / `.claude/skills/**` — agent and skill\n *   prompts in consuming repos that don't re-export configulator\n *   bundles.\n *\n * Repos that **also** host configulator's own bundle source as a\n * workspace package (only `codedrifters/packages` itself) should\n * append `packages/@codedrifters/configulator/src/agent/bundles/**.ts`\n * via `IssueTemplatesConfig.bundlePathPatterns` to lint those bundle\n * sources too. The default omits that pattern because it is dead\n * weight (matches nothing) in any other consumer.\n *\n * Consumers can replace the list outright via `bundlePathPatterns`\n * when their agent sources live elsewhere.\n *\n * @see IssueTemplatesConfig\n */\nexport const DEFAULT_ISSUE_TEMPLATES_BUNDLE_PATH_PATTERNS: ReadonlyArray<string> =\n  [\".claude/agents/**/*.md\", \".claude/skills/**/*.md\"];\n\n/**\n * Default for whether the convention emits the\n * `.claude/procedures/check-issue-templates.sh` lint to disk. The\n * script greps the provided files (stdin or positional args) for\n * inline `gh issue create` invocations and fails non-zero when any\n * are found outside a fenced example block that cites the canonical\n * templates doc.\n *\n * Disabled by default because many consumers prefer to enforce the\n * rule via review discipline and the rendered guidance alone; the\n * script is opt-in for repos that want a hard CI gate or pre-commit\n * hook.\n *\n * @see IssueTemplatesConfig\n */\nexport const DEFAULT_ISSUE_TEMPLATES_EMIT_CHECKER = false;\n\n/**\n * Default for whether the convention emits the issue-templates\n * scaffold to disk. The scaffold is two files:\n *\n * 1. A **write-once** starter page at `<templatesPath>` (projen\n *    `SampleFile`) carrying the expected structure — the \"How to use\"\n *    preamble and one example `## Template: <phase-label>` section —\n *    which the consumer then fleshes out by hand.\n * 2. An **always-regenerated** companion page at\n *    {@link issueTemplatesGeneratedPath}, carrying one label-correct\n *    recipe stub per phase label the consumer's active bundles emit.\n *\n * The split exists because a `SampleFile` never reaches a consumer\n * whose page already exists: repos that adopted the convention on an\n * older configulator would otherwise be frozen on whatever skeleton\n * shipped that day. Hand-authored bodies stay in the write-once page;\n * the generated label sets regenerate on every `projen` run so a new\n * phase label reaches every consumer on their next upgrade.\n *\n * Disabled by default because the hand-authored page conflicts with\n * the ad-hoc notes most repos already maintain when they adopt the\n * convention.\n *\n * @see IssueTemplatesConfig\n */\nexport const DEFAULT_ISSUE_TEMPLATES_EMIT_STARTER = false;\n\n/**\n * Filename suffix appended to the templates page's stem to derive the\n * always-regenerated companion page. Chosen so the companion can never\n * collide with a hand-authored router layout that splits recipes into\n * `<stem>/<child>.md` sibling pages.\n */\nexport const ISSUE_TEMPLATES_GENERATED_SUFFIX = \"-generated\";\n\n/**\n * Repo-relative path of the always-regenerated companion page for a\n * given `templatesPath`: the stem gains\n * {@link ISSUE_TEMPLATES_GENERATED_SUFFIX} and keeps its extension\n * (`…/issue-templates.md` → `…/issue-templates-generated.md`).\n */\nexport function issueTemplatesGeneratedPath(templatesPath: string): string {\n  const slash = templatesPath.lastIndexOf(\"/\");\n  const dot = templatesPath.lastIndexOf(\".\");\n  if (dot > slash) {\n    return `${templatesPath.slice(0, dot)}${ISSUE_TEMPLATES_GENERATED_SUFFIX}${templatesPath.slice(dot)}`;\n  }\n  return `${templatesPath}${ISSUE_TEMPLATES_GENERATED_SUFFIX}`;\n}\n\n/**\n * Glob matching the sibling child pages of a router-style templates\n * layout (`…/issue-templates.md` → `…/issue-templates/*.md`). The\n * label-consistency lint walks these so a repo that split its recipes\n * across child pages is checked against the same map.\n */\nexport function issueTemplatesChildGlob(templatesPath: string): string {\n  const slash = templatesPath.lastIndexOf(\"/\");\n  const dot = templatesPath.lastIndexOf(\".\");\n  const stem = dot > slash ? templatesPath.slice(0, dot) : templatesPath;\n  return `${stem}/*.md`;\n}\n\n/**\n * Default for whether the rendered rule body asserts that every\n * `gh issue create` recipe in a bundle or agent prompt **MUST** cite\n * the canonical templates doc rather than inline a full template.\n *\n * Defaults to `true` — the whole point of consolidation is that\n * templates live in one place, so the MUST phrasing is the correct\n * default. Consumers that treat consolidation as aspirational can\n * soften the phrasing by setting this to `false`.\n *\n * @see IssueTemplatesConfig\n */\nexport const DEFAULT_ISSUE_TEMPLATES_REQUIRE_REFERENCE = true;\n\n/**\n * Fully-resolved issue-templates settings. Every field is defaulted\n * so downstream renderers can reason about a single canonical shape.\n */\nexport interface ResolvedIssueTemplates {\n  readonly enabled: boolean;\n  readonly templatesPath: string;\n  readonly bundlePathPatterns: ReadonlyArray<string>;\n  readonly emitChecker: boolean;\n  readonly emitStarterDoc: boolean;\n  readonly requireReference: boolean;\n}\n\n/**\n * Resolve a (possibly absent) `IssueTemplatesConfig` into a canonical\n * `ResolvedIssueTemplates` with every field filled in. Unset fields\n * cascade from their documented defaults.\n *\n * Malformed configs — empty / whitespace-only or absolute\n * `templatesPath`, empty `bundlePathPatterns`, empty /\n * whitespace-only path entry — throw a descriptive `Error`.\n */\nexport function resolveIssueTemplates(\n  config?: IssueTemplatesConfig,\n): ResolvedIssueTemplates {\n  const templatesPath = config?.templatesPath ?? DEFAULT_ISSUE_TEMPLATES_PATH;\n  assertValidTemplatesPath(templatesPath);\n\n  const bundlePathPatterns =\n    config?.bundlePathPatterns ?? DEFAULT_ISSUE_TEMPLATES_BUNDLE_PATH_PATTERNS;\n  assertValidBundlePathPatterns(bundlePathPatterns);\n\n  return {\n    enabled: config?.enabled ?? DEFAULT_ISSUE_TEMPLATES_ENABLED,\n    templatesPath,\n    bundlePathPatterns,\n    emitChecker: config?.emitChecker ?? DEFAULT_ISSUE_TEMPLATES_EMIT_CHECKER,\n    emitStarterDoc:\n      config?.emitStarterDoc ?? DEFAULT_ISSUE_TEMPLATES_EMIT_STARTER,\n    requireReference:\n      config?.requireReference ?? DEFAULT_ISSUE_TEMPLATES_REQUIRE_REFERENCE,\n  };\n}\n\n/**\n * Synth-time validation hook. Throws a descriptive `Error` when the\n * supplied `IssueTemplatesConfig` is malformed. Called by\n * `AgentConfig.preSynthesize` before any rendering so a misconfigured\n * convention fails the build instead of silently shipping broken\n * guidance. Returns the resolved config unchanged so callers can\n * write `const it = validateIssueTemplatesConfig(config)` in one line.\n *\n * Malformed cases rejected here:\n *\n * - `templatesPath` empty, whitespace-only, or absolute.\n * - `bundlePathPatterns` not an array, empty, or contains an empty /\n *   whitespace-only entry.\n */\nexport function validateIssueTemplatesConfig(\n  config?: IssueTemplatesConfig,\n): ResolvedIssueTemplates {\n  return resolveIssueTemplates(config);\n}\n\n/**\n * Render the full body for the `issue-templates-convention` rule\n * shipped by the `base` bundle. The rule documents:\n *\n * - Why the convention exists (drift between duplicated\n *   `gh issue create` snippets across bundles).\n * - The on-disk contract — a single hand-authored page at\n *   `<templatesPath>` with one `## Template: <phase-label>` section\n *   per downstream issue kind.\n * - The **reference-don't-inline** rule, phrased as a hard\n *   requirement or a strong recommendation per `requireReference`.\n * - The set of paths the rule applies to.\n * - The optional lint script (cross-referenced only when emitted).\n *\n * When the convention is disabled, the rule renders a short stub.\n */\nexport function renderIssueTemplatesRuleContent(\n  it: ResolvedIssueTemplates,\n  hasDownstreamBundles: boolean = true,\n): string {\n  if (!it.enabled || !hasDownstreamBundles) {\n    return [\n      \"# Issue Templates\",\n      \"\",\n      \"**The issue-templates convention is disabled in this project.**\",\n      \"Bundles and agent prompts may inline full `gh issue create`\",\n      \"recipes locally. When two bundles drift apart on title format,\",\n      \"label set, or body shape, humans must reconcile them manually.\",\n      \"\",\n      \"Enable the convention via\",\n      \"`AgentConfigOptions.issueTemplates.enabled = true`.\",\n    ].join(\"\\n\");\n  }\n\n  const requirementVerb = it.requireReference ? \"MUST\" : \"SHOULD\";\n  const requirementAdverb = it.requireReference ? \"must\" : \"should\";\n\n  const lines: Array<string> = [\n    \"# Issue Templates\",\n    \"\",\n    \"This project maintains a single hand-authored issue-templates\",\n    \"reference page that lists one canonical `gh issue create` recipe\",\n    \"per downstream issue kind (`company:research`, `research:scope`,\",\n    \"`req:write`, `meeting:notes`, …). Bundle rules and agent prompts\",\n    \"that file downstream issues cite the matching section of that\",\n    \"page instead of inlining a fresh copy of the command.\",\n    \"\",\n    \"Without this convention, each phased-agent bundle grows its own\",\n    \"copy of the `gh issue create` invocation it dispatches. The title\",\n    \"format, the label set, and the body template drift subtly across\",\n    \"bundles over time — a new required label lands in one bundle but\",\n    \"not the other; one bundle still cites the old `status:new` label\",\n    \"while another uses the canonical `status:ready`; the body\",\n    \"template's `## Objective` section is called `## Purpose` in half\",\n    \"the bundles. Consolidation removes the drift surface.\",\n    \"\",\n    \"The canonical label taxonomy (`type:*`, `priority:*`, `status:*`,\",\n    \"phase label, `tier:*`) remains authoritative via the\",\n    \"`priority-rule` / `issue-label-conventions` / tier modules — the\",\n    \"issue-templates page is a **thin recipe catalogue** over that\",\n    \"taxonomy, not a second source of truth for it.\",\n    \"\",\n    \"## Templates Page\",\n    \"\",\n    `The issue-templates page lives at \\`${it.templatesPath}\\`. It`,\n    \"follows a stable structure so the lint rule (and humans reading\",\n    \"the page) can mechanically identify which section matches which\",\n    \"phase label:\",\n    \"\",\n    \"1. **How to use** — a short prose preamble that cites the label\",\n    \"   conventions (`priority:*`, `status:*`) and the duplicate-check\",\n    \"   protocol agents apply before filing a new issue.\",\n    \"2. **One section per phase label** — a `## Template: <phase-label>`\",\n    \"   heading followed by a single fenced `bash` block containing\",\n    \"   the canonical `gh issue create` invocation for that kind of\",\n    \"   issue. Bodies use angle-bracketed placeholders (`<Organization\",\n    \"   Name>`, `<parent-issue>`, `<slug>`) that callers substitute at\",\n    \"   invocation time.\",\n    \"3. **Callers list** — each template section names the bundles /\",\n    \"   agents that file that kind of issue, so a reader can trace\",\n    \"   back from a template to every workflow that emits it.\",\n    \"\",\n    \"Each template section is independent. Adding a new downstream\",\n    \"issue kind appends one section; retiring a kind removes one. The\",\n    \"label taxonomy, body template shape, and placeholder conventions\",\n    \"are shared across every section.\",\n    \"\",\n  ];\n\n  if (it.emitStarterDoc) {\n    lines.push(\n      \"## Scaffolded Starting Point\",\n      \"\",\n      \"The page is hand-authored, but it does not start empty. Two files\",\n      \"ship together:\",\n      \"\",\n      `1. \\`${it.templatesPath}\\` — **written once**, then yours. Titles,`,\n      \"   bodies, and the callers list are hand-authored here and never\",\n      \"   overwritten.\",\n      `2. \\`${issueTemplatesGeneratedPath(it.templatesPath)}\\` —`,\n      \"   **regenerated on every synth**. One\",\n      \"   `## Template: <phase-label>` stub per phase label the active\",\n      \"   bundles contribute to the label registry, with the phase label,\",\n      \"   the `type:<bundle>` label its owning bundle declares, and the\",\n      \"   configured `status:*` / `priority:*` defaults pre-filled.\",\n      \"\",\n      \"Only the **label set** is generated. Title and body stay\",\n      \"angle-bracket placeholders, so the scaffold answers *which labels*\",\n      \"without dictating *what the issue says*. Copy a stub into the\",\n      \"hand-authored page, flesh out its body, and leave the label block\",\n      \"as generated.\",\n      \"\",\n      \"The split is load-bearing. A write-once scaffold alone freezes\",\n      \"every consumer on whatever skeleton shipped the day they adopted\",\n      \"the convention — a new phase label minted upstream never reaches\",\n      \"them. Regenerating the label half fixes that without ever\",\n      \"clobbering an authored body.\",\n      \"\",\n    );\n  }\n\n  lines.push(\n    \"## Reference-Don't-Inline Rule\",\n    \"\",\n    `Every bundle rule, agent prompt, or skill instruction that files a`,\n    `downstream issue ${requirementVerb} cite the matching section of`,\n    `\\`${it.templatesPath}\\` instead of inlining a full`,\n    \"`gh issue create` invocation. The rule applies when any file in a\",\n    \"commit or PR matches one of the bundle-path patterns below:\",\n    \"\",\n    ...it.bundlePathPatterns.map((p) => `- \\`${p}\\``),\n    \"\",\n    \"Mechanically: a bundle file may **mention** `gh issue create` in\",\n    \"prose (to describe the step), cite the templates page as the\",\n    \"source of record, or reproduce a single-line fragment for\",\n    `illustration. It ${requirementAdverb} **not** include a full`,\n    \"multi-label `gh issue create --title ... --label ... --body ...`\",\n    \"recipe inline; that recipe belongs in the templates page.\",\n    \"\",\n    \"### What counts as an inline template\",\n    \"\",\n    \"The rule targets duplicate recipes, not any mention of the CLI.\",\n    \"Concretely:\",\n    \"\",\n    \"- A multi-line `gh issue create` block with `--title`, `--label`,\",\n    \"  and `--body` arguments — that is a full template and must live\",\n    \"  in the templates page.\",\n    '- A line like `--label \"type:foo\" --label \"status:ready\"` in a',\n    \"  bundle rule without pointing at the templates page — that is\",\n    \"  the label set half of a template and invites drift.\",\n    \"- A `## Issue Body Template` section that duplicates the template\",\n    \"  body in a bundle's workflow rule — the body belongs in the\",\n    \"  templates page section.\",\n    \"\",\n    \"Edits that do **not** require moving to the templates page:\",\n    \"\",\n    \"- Prose that mentions `gh issue create` without supplying a full\",\n    '  recipe (e.g. \"Phase 3 files a `research:scope` issue using the',\n    '  template documented in the issue-templates page.\").',\n    \"- A single-line illustrative fragment (e.g.\",\n    \"  `` `gh issue create --title '<type>: <description>'` ``) used\",\n    \"  to document a conventional prefix or title format — those are\",\n    \"  taxonomy, not templates.\",\n    \"- The canonical `create-issue-workflow` rule itself, which\",\n    \"  documents how humans type `create an issue` to invoke the\",\n    \"  workflow — that rule defines the taxonomy and is the one\",\n    \"  allowed place a full `gh issue create` call lives outside the\",\n    \"  templates page.\",\n    \"\",\n    \"## Authoring Checklist\",\n    \"\",\n    \"Authors and reviewers walk the following checklist before merging\",\n    \"any PR that touches a bundle path and mentions `gh issue create`:\",\n    \"\",\n    `1. **Is the recipe in the templates page?** If not, add a`,\n    `   \\`## Template: <phase-label>\\` section to \\`${it.templatesPath}\\``,\n    \"   before (or in the same commit as) the bundle change that needs\",\n    \"   it. The templates page is the first place a new recipe lands.\",\n    \"2. **Does the bundle rule cite the page?** The rule / prompt that\",\n    \"   dispatches the issue should name the specific\",\n    \"   `## Template: <phase-label>` section instead of reproducing\",\n    \"   the recipe.\",\n    \"3. **Do the labels match the taxonomy?** Every template recipe\",\n    \"   must carry exactly one `type:*` label, exactly one\",\n    \"   `priority:*` label, exactly one `status:*` label, and the\",\n    \"   phase label that identifies the downstream agent. Tier labels\",\n    \"   (`tier:platform`, `tier:industry`, …) are additional when the\",\n    \"   downstream agent is tier-aware.\",\n    \"4. **Are placeholder names stable?** Use angle-bracket\",\n    \"   placeholders (`<Organization Name>`, `<slug>`) that match\",\n    \"   existing templates. Consistency across sections lets callers\",\n    \"   substitute without re-reading the body every time.\",\n    \"5. **Does the recipe assign a GitHub issue type?** `gh issue\",\n    \"   create` cannot set it and the `type:*` label does not either, so\",\n    \"   every section ends with the follow-up call. An issue that skips\",\n    \"   it stays untyped forever.\",\n    \"\",\n  );\n\n  if (it.emitChecker) {\n    lines.push(\n      \"## Automated Lint\",\n      \"\",\n      \"The bundled `.claude/procedures/check-issue-templates.sh`\",\n      \"helper enforces the rule mechanically. Given a set of changed\",\n      \"files (as a newline-separated list on stdin or positional\",\n      \"arguments), it fails non-zero when any file matches a\",\n      \"bundle-path pattern and contains a multi-line\",\n      \"`gh issue create ... --title ... --label ...` invocation. It\",\n      \"exits `0` when no bundle files were touched or when every\",\n      \"`gh issue create` mention is a single-line fragment, a prose\",\n      \"reference, or lives in an allow-listed path.\",\n      \"\",\n      \"```bash\",\n      \"# Pre-commit (staged files):\",\n      \"git diff --cached --name-only \\\\\",\n      \"  | .claude/procedures/check-issue-templates.sh\",\n      \"\",\n      \"# CI (branch-vs-base):\",\n      \"git diff --name-only origin/main...HEAD \\\\\",\n      \"  | .claude/procedures/check-issue-templates.sh\",\n      \"```\",\n      \"\",\n      \"The lint allow-lists two paths by default: the templates page\",\n      `itself (\\`${it.templatesPath}\\`) and the`,\n      \"`github-workflow` bundle's `create-issue-workflow` rule source\",\n      \"(which documents the conventional `gh issue create` call shape\",\n      \"as taxonomy, not a downstream template). All other bundle\",\n      \"files in the pattern set are in scope.\",\n      \"\",\n      \"### Recipe label correctness\",\n      \"\",\n      \"A companion lint,\",\n      \"`.claude/procedures/check-issue-template-labels.sh`, checks the\",\n      \"recipes themselves rather than where they live. It walks the\",\n      \"templates page, its router-style child pages, and the generated\",\n      \"label-set companion, and fails non-zero when a\",\n      \"`## Template: <phase-label>` section:\",\n      \"\",\n      \"- never passes `--label <phase-label>` — the heading and the\",\n      \"  command disagree;\",\n      \"- carries no `type:*` label, more than one, or one that is not\",\n      \"  the `type:<bundle>` label the phase label's owning bundle\",\n      \"  declares;\",\n      \"- has no GitHub issue-type assignment step.\",\n      \"\",\n      \"```bash\",\n      \".claude/procedures/check-issue-template-labels.sh\",\n      \"```\",\n      \"\",\n      \"The phase-label → type-label pairing is generated from the same\",\n      \"bundle-ownership map that drives `.github/labels.yml` and the\",\n      \"orchestrator's invariant sweep, so a hand-edit can never\",\n      \"reintroduce a mismatch the registry has already ruled out.\",\n      \"Sections whose heading matches no bundle-owned phase label are\",\n      \"skipped — consumer-specific labels are deliberately not policed.\",\n      \"\",\n    );\n  }\n\n  lines.push(\n    \"## Out of Scope\",\n    \"\",\n    \"The convention intentionally does not:\",\n    \"\",\n    \"- Auto-generate recipe **bodies**. Only the label set is\",\n    \"  scaffolded, because labels are derivable from the bundle\",\n    \"  registry and bodies are not — repo-specific objectives,\",\n    \"  acceptance criteria, and callers lists stay hand-authored.\",\n    \"- Prescribe a fixed body shape across templates. Each section\",\n    \"  may carry its own `## Acceptance Criteria`, `## Scope Size`,\",\n    \"  or `## Output Path` fields as the downstream agent requires;\",\n    \"  the convention only asserts the recipe lives in one place.\",\n    \"- Gate every unrelated cleanup PR on a templates-page touch.\",\n    \"  The rule targets inline `gh issue create` recipes; pure\",\n    \"  cleanups that add no new recipe are exempt.\",\n  );\n\n  return lines.join(\"\\n\");\n}\n\n/**\n * Render the short issue-templates hook section injected into a\n * phased-agent bundle's workflow rule. The section cites the full\n * contract documented in the base bundle's\n * `issue-templates-convention` rule so individual bundles stay DRY.\n *\n * When the convention is disabled, the function returns an empty\n * string so callers can no-op their append path.\n */\nexport function renderIssueTemplatesBundleHook(\n  it: ResolvedIssueTemplates,\n  bundleLabel: string,\n): string {\n  if (!it.enabled) {\n    return \"\";\n  }\n\n  const verb = it.requireReference ? \"must\" : \"should\";\n\n  return [\n    \"## Issue Templates\",\n    \"\",\n    `Every downstream \\`gh issue create\\` invocation dispatched by the`,\n    `${bundleLabel} bundle ${verb} cite the matching`,\n    `\\`## Template: <phase-label>\\` section in \\`${it.templatesPath}\\``,\n    \"instead of inlining a full template. Inline `--title ...`\",\n    \"`--label ... --body ...` blocks drift across bundles; the\",\n    \"consolidated page is the single source of record for the recipe,\",\n    \"the placeholder names, and the label set. See the\",\n    \"`issue-templates-convention` rule for the full authoring\",\n    \"checklist, the path patterns the rule covers, and what counts\",\n    \"as an inline template vs. a prose mention.\",\n  ].join(\"\\n\");\n}\n\n/**\n * Render the write-once starter issue-templates page — the frontmatter,\n * the \"How to use\" preamble, a pointer at the always-regenerated\n * label-set companion, and a single example template section. Exported\n * so `AgentConfig` can emit it to disk when the consumer opts in via\n * `emitStarterDoc: true`.\n *\n * The starter stays deliberately sparse on **bodies**: it documents the\n * expected structure without committing the consumer to a particular\n * body shape. The correct-by-construction **label sets** live in the\n * companion page this one links to, which regenerates on every synth —\n * so a write-once starter can never freeze a consumer on a stale label\n * taxonomy.\n */\nexport function renderIssueTemplatesStarterPage(\n  it: ResolvedIssueTemplates,\n): string {\n  const generatedLink = `./${basename(issueTemplatesGeneratedPath(it.templatesPath))}`;\n  return [\n    \"---\",\n    \"title: Issue Templates\",\n    \"description: Canonical gh issue create recipes — one per downstream phase label.\",\n    \"---\",\n    \"\",\n    \"This page lists the canonical `gh issue create` recipe for every\",\n    \"downstream issue kind dispatched by an agent in this monorepo.\",\n    \"Bundles and agent prompts cite the matching section below instead\",\n    \"of inlining the recipe — see the\",\n    \"`issue-templates-convention` rule for the full contract.\",\n    \"\",\n    \"## How to use\",\n    \"\",\n    \"Each template shows the full `gh issue create` command with\",\n    \"angle-bracketed placeholders (`<...>`). Replace placeholders with\",\n    \"real values before running. Every recipe carries exactly one\",\n    \"`type:*` label, exactly one `priority:*` label, and exactly one\",\n    \"`status:*` label from the conventions documented in the\",\n    \"`issue-label-conventions` rule.\",\n    \"\",\n    \"Every recipe also ends with a **GitHub issue type** assignment.\",\n    \"`gh issue create` cannot set the issue type, so it takes a second\",\n    \"call — an issue that skips it stays untyped forever. Derive the type\",\n    \"from the title prefix (`epic:` → Epic, `feat:` → Feature, `fix:` →\",\n    \"Bug, everything else — including every bundle-phase prefix — →\",\n    \"Task); see **Assigning the GitHub issue type** in the\",\n    \"`issue-conventions` rule for the command and its fallback.\",\n    \"\",\n    \"Before creating any profile-style issue (people, companies,\",\n    \"software), run the duplicate check documented in the owning\",\n    \"bundle's rule — the issue-templates page is a recipe catalogue,\",\n    \"not a duplicate-check layer.\",\n    \"\",\n    \"## Generated label sets\",\n    \"\",\n    `[Generated Issue-Template Label Sets](${generatedLink}) carries one`,\n    \"correct-by-construction stub per phase label the active bundles\",\n    \"emit — the phase label paired with the `type:<bundle>` label its\",\n    \"owning bundle declares, plus the configured `status:*` /\",\n    \"`priority:*` defaults. That page regenerates on every `projen` run,\",\n    \"so it never goes stale as phase labels come and go.\",\n    \"\",\n    \"This page is the opposite: written once, then owned by you. Copy a\",\n    \"stub across, flesh out its title and body here, and leave the label\",\n    \"block exactly as generated — the label-consistency lint holds both\",\n    \"copies to the same pairing.\",\n    \"\",\n    \"## Template: example-phase\",\n    \"\",\n    \"Replace this example with the real templates for this repo. Each\",\n    \"section is independent; add or remove sections as phase labels\",\n    \"come and go.\",\n    \"\",\n    \"**Callers:** Name the bundles and agents that file this kind of\",\n    \"issue.\",\n    \"\",\n    \"```bash\",\n    \"gh issue create \\\\\",\n    '  --title \"<type>: <short description>\" \\\\',\n    '  --label \"type:<type>\" \\\\',\n    '  --label \"<phase-label>\" \\\\',\n    '  --label \"status:ready\" \\\\',\n    '  --label \"<priority-label>\" \\\\',\n    '  --body \"## Objective',\n    \"\",\n    \"<1-3 sentences describing the issue>.\",\n    \"\",\n    \"## Context\",\n    \"\",\n    \"- **Discovered in:** <source description> (#<parent-issue>)\",\n    \"\",\n    \"## Acceptance Criteria\",\n    \"\",\n    \"- [ ] <criterion 1>\",\n    \"- [ ] <criterion 2>\",\n    '\"',\n    \"```\",\n    \"\",\n    \"Then assign the GitHub issue type (`Task` for a phase-labelled\",\n    \"title):\",\n    \"\",\n    \"```bash\",\n    `${SET_ISSUE_TYPE_HELPER_PATH} <issue-number> ${DEFAULT_GITHUB_ISSUE_TYPE}`,\n    \"```\",\n  ].join(\"\\n\");\n}\n\n/*******************************************************************************\n *\n * Generated recipe stubs\n *\n ******************************************************************************/\n\n/**\n * One correct-by-construction recipe stub: a phase label plus every\n * label the recipe must carry, all derived rather than hand-copied.\n */\nexport interface IssueTemplateRecipeStub {\n  /** The phase label the recipe files (e.g. `people:research`). */\n  readonly phaseLabel: string;\n  /** The `type:<bundle>` label the phase-label invariant requires. */\n  readonly typeLabel: string;\n  /** Bundle that contributes the phase label to `.github/labels.yml`. */\n  readonly bundleName: string;\n  /** The label's registry description, used as the section blurb. */\n  readonly description: string;\n  /** Effective `status:*` value for this phase. */\n  readonly status: IssueDefaultsStatus;\n  /** Effective `priority:*` value for this phase. */\n  readonly priority: IssueDefaultsPriority;\n  /** GitHub issue type the filed issue must be assigned. */\n  readonly issueType: GithubIssueType;\n}\n\n/**\n * Derive one recipe stub per phase label the supplied bundles\n * contribute to `.github/labels.yml`.\n *\n * A contributed label counts as a phase label exactly when\n * `typeLabelForPhaseLabel` resolves it — i.e. when the canonical\n * bundle-ownership map claims it. That is the *same* map that drives\n * the label registry and the orchestrator's phase-label invariant, so\n * a generated stub can never pair a phase label with the wrong\n * `type:<bundle>` label. Consumer-specific labels no bundle owns are\n * skipped rather than guessed at.\n *\n * Results are deduplicated by phase label (co-owned `req:*` labels are\n * contributed by more than one requirements bundle) and sorted so the\n * rendered page is stable across synth runs.\n */\nexport function collectIssueTemplateRecipeStubs(\n  bundles: ReadonlyArray<AgentRuleBundle>,\n  issueDefaults: ResolvedIssueDefaults = DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n): ReadonlyArray<IssueTemplateRecipeStub> {\n  const stubs = new Map<string, IssueTemplateRecipeStub>();\n  for (const bundle of bundles) {\n    for (const label of bundle.labels ?? []) {\n      const typeLabel = typeLabelForPhaseLabel(label.name);\n      if (typeLabel === undefined) {\n        continue;\n      }\n      if (stubs.has(label.name)) {\n        continue;\n      }\n      const defaults = labelsForPhase(issueDefaults, label.name);\n      stubs.set(label.name, {\n        phaseLabel: label.name,\n        typeLabel,\n        bundleName: bundle.name,\n        description: label.description ?? \"\",\n        status: defaults.status,\n        priority: defaults.priority,\n        issueType: githubIssueTypeForTitle(`${label.name}: placeholder`),\n      });\n    }\n  }\n  return [...stubs.values()].sort((a, b) =>\n    a.phaseLabel.localeCompare(b.phaseLabel),\n  );\n}\n\n/**\n * Render the always-regenerated companion page that carries one\n * label-correct `## Template: <phase-label>` stub per phase label the\n * consumer's active bundles emit.\n *\n * Only the **label set** and the issue-type assignment are generated —\n * title and body stay angle-bracket placeholders, so the page is a\n * correct-by-construction starting point rather than a second source of\n * truth for recipe bodies. Consumers move a stub into their\n * hand-authored templates page and flesh out its body there; the\n * label-consistency lint then holds both copies to the same pairing.\n */\nexport function renderIssueTemplatesGeneratedPage(\n  it: ResolvedIssueTemplates,\n  stubs: ReadonlyArray<IssueTemplateRecipeStub>,\n): string {\n  const lines: Array<string> = [\n    \"---\",\n    \"title: Generated Issue-Template Label Sets\",\n    \"description: Auto-generated label-correct gh issue create stubs — one per phase label.\",\n    \"---\",\n    \"\",\n    \"**Generated file — do not edit.** Every section below is\",\n    \"regenerated from the active bundle set on each `projen` run; hand\",\n    \"edits are overwritten. The hand-authored recipes live in\",\n    `[the issue-templates page](./${basename(it.templatesPath)}) — this`,\n    \"page exists so the **label half** of every recipe stays\",\n    \"correct-by-construction as phase labels come and go.\",\n    \"\",\n    \"## How to use\",\n    \"\",\n    \"Each section carries the exact label set the phase-label invariant\",\n    \"requires: the phase label itself, the `type:<bundle>` label its\",\n    \"owning bundle declares, and the configured `status:*` / `priority:*`\",\n    \"defaults for that phase. Title and body are placeholders — copy the\",\n    \"stub into the hand-authored templates page and flesh out the body\",\n    \"there, or run it as-is when no repo-specific body exists yet.\",\n    \"\",\n    \"Every stub ends with the **GitHub issue type** assignment. `gh issue\",\n    \"create` cannot set the issue type and the `type:*` label does not\",\n    \"set it either, so an issue that skips the follow-up call stays\",\n    \"untyped forever. See **Assigning the GitHub issue type** in the\",\n    \"`issue-conventions` rule for the no-helper fallback.\",\n    \"\",\n  ];\n\n  if (stubs.length === 0) {\n    lines.push(\n      \"## No phase labels\",\n      \"\",\n      \"No active bundle contributes a phase label, so there is nothing to\",\n      \"scaffold. Enable a phased-pipeline bundle (or drop it from\",\n      \"`excludeBundles`) and re-run `projen`.\",\n    );\n    return lines.join(\"\\n\");\n  }\n\n  for (const stub of stubs) {\n    lines.push(\n      `## Template: ${stub.phaseLabel}`,\n      \"\",\n      ...(stub.description === \"\" ? [] : [stub.description, \"\"]),\n      `**Owning bundle:** \\`${stub.bundleName}\\` — **required type label:**`,\n      `\\`${stub.typeLabel}\\` (paired by the bundle-ownership map).`,\n      \"\",\n      \"**Callers:** <name the bundles and agents that file this issue>\",\n      \"\",\n      \"```bash\",\n      \"gh issue create \\\\\",\n      `  --title \"${stub.phaseLabel}: <short description>\" \\\\`,\n      `  --label \"${stub.typeLabel}\" \\\\`,\n      `  --label \"${stub.phaseLabel}\" \\\\`,\n      `  --label \"priority:${stub.priority}\" \\\\`,\n      `  --label \"status:${stub.status}\" \\\\`,\n      '  --body \"## Objective',\n      \"\",\n      \"<1-3 sentences describing the work>.\",\n      \"\",\n      \"## Context\",\n      \"\",\n      \"- **Discovered in:** <source description> (#<parent-issue>)\",\n      \"\",\n      \"## Acceptance Criteria\",\n      \"\",\n      \"- [ ] <criterion 1>\",\n      '\"',\n      \"```\",\n      \"\",\n      `Then assign the GitHub issue type (\\`${stub.issueType}\\`):`,\n      \"\",\n      \"```bash\",\n      `${SET_ISSUE_TYPE_HELPER_PATH} <issue-number> ${stub.issueType}`,\n      \"```\",\n      \"\",\n    );\n  }\n\n  // Drop the trailing blank so the file ends on a single newline.\n  lines.pop();\n  return lines.join(\"\\n\");\n}\n\n/**\n * Render the `.claude/procedures/check-issue-templates.sh` helper\n * script. Exported so `AgentConfig` can register it as an\n * `AgentProcedure` when the consumer opts in via `emitChecker: true`.\n *\n * The script accepts the list of changed files as either:\n *\n * 1. Positional arguments (one file per arg).\n * 2. Newline-separated entries on stdin (when no args supplied) —\n *    pipe `git diff --name-only` directly into it.\n *\n * It fails non-zero when any changed file matches a bundle-path\n * pattern and contains a multi-line `gh issue create ... --title`\n * invocation that isn't in the configured allow list (the templates\n * page itself and the `create-issue-workflow` rule source).\n */\nexport function renderIssueTemplatesCheckerScript(\n  it: ResolvedIssueTemplates,\n): string {\n  const patternsLiteral = it.bundlePathPatterns\n    .map((p) => `  ${JSON.stringify(p)}`)\n    .join(\"\\n\");\n\n  return [\n    \"#!/usr/bin/env bash\",\n    \"# check-issue-templates.sh — Enforce the reference-don't-inline rule.\",\n    \"#\",\n    \"# Usage:\",\n    \"#   .claude/procedures/check-issue-templates.sh <file>...\",\n    \"#   git diff --name-only HEAD | .claude/procedures/check-issue-templates.sh\",\n    \"#\",\n    \"# Fails non-zero when any changed file matches a bundle-path pattern\",\n    \"# and contains a multi-line `gh issue create` invocation — i.e. one\",\n    \"# that includes a `--title` flag on a subsequent line. Single-line\",\n    \"# fragments and prose mentions are permitted.\",\n    \"#\",\n    \"# Five paths are allow-listed: the templates page itself, the\",\n    \"# `github-workflow` bundle's `create-issue-workflow` rule source,\",\n    \"# the `upstream-configulator-docs` bundle's rule source, the\",\n    \"# `issue-templates` bundle source (which renders the templates\",\n    \"# page and so necessarily embeds the recipes as its content), and\",\n    \"# the `issue-templates` test source (which contains recipe fixtures\",\n    \"# used to exercise this very lint). All five legitimately contain\",\n    \"# `gh issue create` recipes as taxonomy, content, or test fixtures.\",\n    \"#\",\n    \"# The bundle-path patterns and templates path are rendered from the\",\n    \"# consumer's IssueTemplatesConfig at synth time — do not edit by\",\n    \"# hand; regenerate via `pnpm exec projen`.\",\n    \"#\",\n    \"# Patterns support the `**` recursive-segment wildcard even though\",\n    \"# bash's native `[[ $file == $glob ]]` pattern matching does not:\",\n    \"# each glob is converted to a POSIX-extended regex internally and\",\n    \"# matched with `=~`, so the script works uniformly on bash 3.2\",\n    \"# (macOS default) and bash 4+ (Linux / CI) without depending on\",\n    \"# `shopt -s globstar`.\",\n    \"\",\n    \"set -uo pipefail\",\n    \"\",\n    \"err() {\",\n    '  printf \"check-issue-templates.sh: %s\\\\n\" \"$*\" >&2',\n    \"}\",\n    \"\",\n    `templates_path=${JSON.stringify(it.templatesPath)}`,\n    \"\",\n    \"# Allow-listed paths: the templates page itself, the\",\n    \"# create-issue-workflow rule source, the upstream-configulator-docs\",\n    \"# rule source, and the issue-templates bundle source + test (which\",\n    \"# render and exercise the lint and so necessarily embed recipes).\",\n    \"allowlist=(\",\n    `  \"$templates_path\"`,\n    '  \"packages/@codedrifters/configulator/src/agent/bundles/github-workflow.ts\"',\n    '  \"packages/@codedrifters/configulator/src/agent/bundles/upstream-configulator-docs.ts\"',\n    '  \"packages/@codedrifters/configulator/src/agent/bundles/issue-templates.ts\"',\n    '  \"packages/@codedrifters/configulator/src/agent/bundles/issue-templates.test.ts\"',\n    \")\",\n    \"\",\n    \"# Bundle-path glob patterns. Translated to anchored POSIX-extended\",\n    \"# regexes at runtime by `glob_to_regex` below so `**` matches\",\n    \"# recursively across path segments.\",\n    \"bundle_patterns=(\",\n    patternsLiteral,\n    \")\",\n    \"\",\n    \"# Convert a bash-style glob into an anchored POSIX-extended regex:\",\n    \"#   **/   → (.+/)?   (zero or more path segments plus trailing slash)\",\n    \"#   **    → .*       (anywhere, including `/`)\",\n    \"#   *     → [^/]*    (single path segment)\",\n    \"#   ?     → [^/]     (single non-slash char)\",\n    \"# Every other char is passed through, with regex metacharacters\",\n    \"# backslash-escaped so literal `.` / `+` / `(` etc. match themselves.\",\n    \"glob_to_regex() {\",\n    '  local glob=\"$1\"',\n    '  local regex=\"\"',\n    \"  local i=0\",\n    \"  local len=${#glob}\",\n    \"  while (( i < len )); do\",\n    '    local c=\"${glob:i:1}\"',\n    '    if [[ \"$c\" == \"*\" ]]; then',\n    '      local next=\"${glob:i+1:1}\"',\n    '      if [[ \"$next\" == \"*\" ]]; then',\n    '        local after=\"${glob:i+2:1}\"',\n    '        if [[ \"$after\" == \"/\" ]]; then',\n    '          regex+=\"(.+/)?\"',\n    \"          i=$(( i + 3 ))\",\n    \"        else\",\n    '          regex+=\".*\"',\n    \"          i=$(( i + 2 ))\",\n    \"        fi\",\n    \"      else\",\n    '        regex+=\"[^/]*\"',\n    \"        i=$(( i + 1 ))\",\n    \"      fi\",\n    '    elif [[ \"$c\" == \"?\" ]]; then',\n    '      regex+=\"[^/]\"',\n    \"      i=$(( i + 1 ))\",\n    \"    else\",\n    '      case \"$c\" in',\n    \"        '.'|'+'|'^'|'$'|'('|')'|'{'|'}'|'|'|'['|']'|'\\\\\\\\')\",\n    '          regex+=\"\\\\\\\\$c\"',\n    \"          ;;\",\n    \"        *)\",\n    '          regex+=\"$c\"',\n    \"          ;;\",\n    \"      esac\",\n    \"      i=$(( i + 1 ))\",\n    \"    fi\",\n    \"  done\",\n    '  printf \"^%s$\" \"$regex\"',\n    \"}\",\n    \"\",\n    \"# Check whether a file has a multi-line `gh issue create` recipe.\",\n    \"# Heuristic: the file contains a line matching `gh issue create`\",\n    \"# followed — within the next 20 lines — by a line carrying a\",\n    \"# `--title` flag. Single-line fragments and prose mentions that\",\n    \"# don't include `--title` on a near-by line are permitted.\",\n    \"has_multiline_recipe() {\",\n    '  local file=\"$1\"',\n    \"  awk '\",\n    \"    /gh issue create/ { hit = NR }\",\n    '    hit && NR > hit && NR - hit <= 20 && /--title/ { print \"FOUND\"; exit }',\n    '  \\' \"$file\" 2>/dev/null | grep -q FOUND',\n    \"}\",\n    \"\",\n    \"is_allowlisted() {\",\n    '  local file=\"$1\"',\n    '  for entry in \"${allowlist[@]}\"; do',\n    '    if [[ \"$file\" == \"$entry\" ]]; then',\n    \"      return 0\",\n    \"    fi\",\n    \"  done\",\n    \"  return 1\",\n    \"}\",\n    \"\",\n    \"# Collect the input file list: positional args override stdin.\",\n    \"if [[ $# -gt 0 ]]; then\",\n    '  files=(\"$@\")',\n    \"else\",\n    \"  files=()\",\n    \"  while IFS= read -r line; do\",\n    '    [[ -z \"$line\" ]] && continue',\n    '    files+=(\"$line\")',\n    \"  done\",\n    \"fi\",\n    \"\",\n    \"if [[ ${#files[@]} -eq 0 ]]; then\",\n    \"  exit 0\",\n    \"fi\",\n    \"\",\n    \"bundle_regexes=()\",\n    'for pattern in \"${bundle_patterns[@]}\"; do',\n    '  bundle_regexes+=(\"$(glob_to_regex \"$pattern\")\")',\n    \"done\",\n    \"\",\n    \"violations=()\",\n    \"\",\n    'for file in \"${files[@]}\"; do',\n    '  if is_allowlisted \"$file\"; then',\n    \"    continue\",\n    \"  fi\",\n    \"  matches_pattern=0\",\n    '  for regex in \"${bundle_regexes[@]}\"; do',\n    '    if [[ \"$file\" =~ $regex ]]; then',\n    \"      matches_pattern=1\",\n    \"      break\",\n    \"    fi\",\n    \"  done\",\n    '  if [[ \"$matches_pattern\" -eq 0 ]]; then',\n    \"    continue\",\n    \"  fi\",\n    '  if [[ ! -f \"$file\" ]]; then',\n    \"    continue\",\n    \"  fi\",\n    '  if has_multiline_recipe \"$file\"; then',\n    '    violations+=(\"$file\")',\n    \"  fi\",\n    \"done\",\n    \"\",\n    \"if [[ ${#violations[@]} -gt 0 ]]; then\",\n    '  err \"inline \\\\`gh issue create\\\\` recipes found in the following files:\"',\n    '  for v in \"${violations[@]}\"; do',\n    '    err \"  - $v\"',\n    \"  done\",\n    \"  err \\\"move each recipe into a '## Template: <phase-label>' section of '$templates_path' and cite that section from the bundle rule\\\"\",\n    \"  exit 1\",\n    \"fi\",\n    \"\",\n    \"exit 0\",\n  ].join(\"\\n\");\n}\n\n/**\n * Render the `.claude/procedures/check-issue-template-labels.sh`\n * companion lint. Exported so `AgentConfig` can emit it alongside the\n * reference-don't-inline lint when the consumer opts in via\n * `emitChecker: true`.\n *\n * Where `check-issue-templates.sh` polices *where* recipes live, this\n * one polices *what they say*. For every\n * `## Template: <phase-label>` section on the templates page, its\n * router-style child pages, and the generated companion, it asserts:\n *\n * 1. The recipe passes `--label <phase-label>` — the heading and the\n *    command agree.\n * 2. It carries exactly one `type:*` label, and that label is the\n *    `type:<bundle>` the phase-label invariant requires.\n * 3. It carries a GitHub issue-type assignment step (the\n *    `set-issue-type.sh` helper or the `updateIssueIssueType` GraphQL\n *    flow it wraps) — an issue filed without one stays untyped forever.\n *\n * Sections whose heading matches no bundle-owned phase label are\n * skipped, not failed: unrecognised `foo:bar` labels are\n * consumer-specific and deliberately not policed, exactly as the\n * orchestrator's invariant sweep treats them.\n *\n * The phase-label → type-label resolver is rendered from the same\n * `PHASE_LABEL_TYPE_MAP` that drives the label registry and the\n * orchestrator sweep, so the lint can never enforce a stale pairing.\n */\nexport function renderIssueTemplateLabelsCheckerScript(\n  it: ResolvedIssueTemplates,\n): string {\n  const generatedPath = issueTemplatesGeneratedPath(it.templatesPath);\n  const childGlob = issueTemplatesChildGlob(it.templatesPath);\n\n  return [\n    \"#!/usr/bin/env bash\",\n    \"# check-issue-template-labels.sh — Enforce recipe label correctness.\",\n    \"#\",\n    \"# Usage:\",\n    \"#   .claude/procedures/check-issue-template-labels.sh [<file>...]\",\n    \"#\",\n    \"# With no arguments the lint walks the templates page, its\",\n    \"# router-style child pages, and the generated label-set companion.\",\n    \"# Positional arguments override that default set.\",\n    \"#\",\n    \"# For every `## Template: <phase-label>` section it asserts the\",\n    \"# recipe passes the heading's phase label, carries exactly one\",\n    \"# `type:*` label matching the phase-label invariant, and assigns a\",\n    \"# GitHub issue type. Sections whose heading matches no bundle-owned\",\n    \"# phase label are skipped — unrecognised labels are consumer-\",\n    \"# specific and deliberately not policed.\",\n    \"#\",\n    \"# The resolver below is generated from the canonical bundle-\",\n    \"# ownership map — do not edit by hand; regenerate via\",\n    \"# `pnpm exec projen`.\",\n    \"\",\n    \"set -uo pipefail\",\n    \"\",\n    \"err() {\",\n    '  printf \"check-issue-template-labels.sh: %s\\\\n\" \"$*\" >&2',\n    \"}\",\n    \"\",\n    renderPhaseTypeInvariantShellHelpers(),\n    \"\",\n    `templates_path=${JSON.stringify(it.templatesPath)}`,\n    `generated_path=${JSON.stringify(generatedPath)}`,\n    `child_glob=${JSON.stringify(childGlob)}`,\n    \"\",\n    \"# Emit one TAB-separated record per `## Template:` section:\",\n    \"#   <file>\\\\t<line>\\\\t<phase-label>\\\\t<comma-joined labels>\\\\t<0|1 typed>\",\n    \"# Quote characters are folded to spaces up front so a recipe written\",\n    \"# with single quotes, double quotes, or none at all parses the same.\",\n    \"# Fenced blocks are tracked so the `## Objective` heading inside a\",\n    \"# recipe's --body string never reads as the end of the section.\",\n    \"scan_file() {\",\n    '  local file=\"$1\"',\n    \"  tr '\\\\042\\\\047' '  ' < \\\"$file\\\" | awk -v FNAME=\\\"$file\\\" '\",\n    \"    function flush() {\",\n    '      if (phase != \"\") {',\n    '        printf \"%s\\\\t%d\\\\t%s\\\\t%s\\\\t%d\\\\n\", FNAME, start, phase, labels, hastype;',\n    \"      }\",\n    '      phase = \"\"; labels = \"\"; hastype = 0;',\n    \"    }\",\n    \"    {\",\n    \"      if ($0 ~ /^[ \\\\t]*```/) {\",\n    \"        fence = 1 - fence;\",\n    '      } else if (fence == 0 && index($0, \"## \") == 1) {',\n    \"        flush();\",\n    '        if (index($0, \"## Template: \") == 1) {',\n    \"          phase = substr($0, 14);\",\n    '          gsub(/[ \\\\t`]/, \"\", phase);',\n    \"          start = NR;\",\n    \"        }\",\n    \"        next;\",\n    \"      }\",\n    '      if (phase == \"\") next;',\n    \"      if ($0 ~ /set-issue-type\\\\.sh/ || $0 ~ /updateIssueIssueType/) {\",\n    \"        hastype = 1;\",\n    \"      }\",\n    \"      line = $0;\",\n    \"      while (match(line, /--label[ \\\\t]+[^ \\\\t]+/)) {\",\n    \"        tok = substr(line, RSTART, RLENGTH);\",\n    \"        line = substr(line, RSTART + RLENGTH);\",\n    '        sub(/^--label[ \\\\t]+/, \"\", tok);',\n    '        gsub(/[\\\\\\\\`]/, \"\", tok);',\n    '        labels = labels tok \",\";',\n    \"      }\",\n    \"    }\",\n    \"    END { flush(); }\",\n    \"  '\",\n    \"}\",\n    \"\",\n    \"# Collect the file list: positional args override the default set.\",\n    \"files=()\",\n    \"if [[ $# -gt 0 ]]; then\",\n    '  files=(\"$@\")',\n    \"else\",\n    '  [[ -f \"$templates_path\" ]] && files+=(\"$templates_path\")',\n    '  [[ -f \"$generated_path\" ]] && files+=(\"$generated_path\")',\n    \"  for child in $child_glob; do\",\n    '    [[ -f \"$child\" ]] && files+=(\"$child\")',\n    \"  done\",\n    \"fi\",\n    \"\",\n    \"if [[ ${#files[@]} -eq 0 ]]; then\",\n    \"  exit 0\",\n    \"fi\",\n    \"\",\n    \"violations=()\",\n    \"checked=0\",\n    \"\",\n    'for file in \"${files[@]}\"; do',\n    '  [[ -f \"$file\" ]] || continue',\n    \"  while IFS=$'\\\\t' read -r rec_file rec_line phase labels hastype; do\",\n    '    [[ -z \"$phase\" ]] && continue',\n    '    required=$(phase_label_type_of \"$phase\")',\n    '    [[ -z \"$required\" ]] && continue',\n    \"    checked=$(( checked + 1 ))\",\n    '    case \",${labels}\" in',\n    '      *\",${phase},\"*) ;;',\n    \"      *) violations+=(\\\"$rec_file:$rec_line: recipe for '$phase' never passes --label $phase\\\") ;;\",\n    \"    esac\",\n    '    type_labels=\"\"',\n    \"    type_count=0\",\n    '    for entry in $(printf \"%s\" \"$labels\" | tr , \" \"); do',\n    '      case \"$entry\" in',\n    \"        type:*)\",\n    '          type_labels=\"${type_labels}${entry} \"',\n    \"          type_count=$(( type_count + 1 ))\",\n    \"          ;;\",\n    \"      esac\",\n    \"    done\",\n    '    if [[ \"$type_count\" -eq 0 ]]; then',\n    \"      violations+=(\\\"$rec_file:$rec_line: recipe for '$phase' carries no type:* label (expected $required)\\\")\",\n    '    elif [[ \"$type_count\" -gt 1 ]]; then',\n    \"      violations+=(\\\"$rec_file:$rec_line: recipe for '$phase' carries ${type_count} type:* labels (${type_labels% }); exactly one is allowed\\\")\",\n    '    elif [[ \"${type_labels% }\" != \"$required\" ]]; then',\n    \"      violations+=(\\\"$rec_file:$rec_line: recipe for '$phase' carries ${type_labels% } but the phase label requires $required\\\")\",\n    \"    fi\",\n    '    if [[ \"$hastype\" != \"1\" ]]; then',\n    \"      violations+=(\\\"$rec_file:$rec_line: recipe for '$phase' has no GitHub issue-type assignment step\\\")\",\n    \"    fi\",\n    '  done < <(scan_file \"$file\")',\n    \"done\",\n    \"\",\n    \"if [[ ${#violations[@]} -gt 0 ]]; then\",\n    '  err \"issue-template recipes disagree with the phase-label invariant:\"',\n    '  for v in \"${violations[@]}\"; do',\n    '    err \"  - $v\"',\n    \"  done\",\n    \"  err \\\"each '## Template: <phase-label>' recipe must pass its own phase label, exactly one matching type:<bundle> label, and a set-issue-type.sh (or updateIssueIssueType) step\\\"\",\n    \"  exit 1\",\n    \"fi\",\n    \"\",\n    'printf \"check-issue-template-labels.sh: %d recipe(s) OK\\\\n\" \"$checked\"',\n    \"exit 0\",\n  ].join(\"\\n\");\n}\n\n/*******************************************************************************\n *\n * Internal helpers\n *\n ******************************************************************************/\n\n/** Final path segment of a repo-relative path. */\nfunction basename(path: string): string {\n  const slash = path.lastIndexOf(\"/\");\n  return slash === -1 ? path : path.slice(slash + 1);\n}\n\nfunction assertValidTemplatesPath(value: string): void {\n  if (typeof value !== \"string\" || value.trim().length === 0) {\n    throw new Error(\n      `IssueTemplatesConfig.templatesPath must be a non-empty string; got ${JSON.stringify(\n        value,\n      )}`,\n    );\n  }\n  if (value.startsWith(\"/\")) {\n    throw new Error(\n      `IssueTemplatesConfig.templatesPath must be a repo-relative path (no leading '/'); got ${JSON.stringify(\n        value,\n      )}`,\n    );\n  }\n}\n\nfunction assertValidBundlePathPatterns(value: ReadonlyArray<string>): void {\n  if (!Array.isArray(value)) {\n    throw new Error(\n      `IssueTemplatesConfig.bundlePathPatterns must be an array; got ${JSON.stringify(\n        value,\n      )}`,\n    );\n  }\n  if (value.length === 0) {\n    throw new Error(\n      \"IssueTemplatesConfig.bundlePathPatterns must not be empty — supply at least one pattern or omit the field to use the defaults\",\n    );\n  }\n  for (const entry of value) {\n    if (typeof entry !== \"string\" || entry.trim().length === 0) {\n      throw new Error(\n        `IssueTemplatesConfig.bundlePathPatterns entries must be non-empty strings; got ${JSON.stringify(\n          entry,\n        )}`,\n      );\n    }\n  }\n}\n","import { AgentPathsConfig } from \"../agent-config-options\";\n\n/**\n * Fully-resolved requirement category subdirectory names, relative to\n * the requirements root. Every property is required.\n */\nexport interface ResolvedRequirementCategoryDirs {\n  readonly business: string;\n  readonly functional: string;\n  readonly nonFunctional: string;\n  readonly technical: string;\n  readonly architecturalDecisions: string;\n  readonly security: string;\n  readonly data: string;\n  readonly integration: string;\n  readonly operational: string;\n  readonly ux: string;\n  readonly multiTenancy: string;\n}\n\n/**\n * Fully-resolved agent output-path roots. Every property is required.\n *\n * This is the shape that bundle code consumes at module-eval time via\n * `DEFAULT_AGENT_PATHS`, and the shape that `resolveAgentPaths()`\n * returns when consumers supply a partial `AgentPathsConfig` override.\n */\nexport interface ResolvedAgentPaths {\n  readonly docsRoot: string;\n  readonly researchRoot: string;\n  readonly profilesRoot: string;\n  readonly meetingsRoot: string;\n  readonly requirementsRoot: string;\n  readonly researchRequirementsRoot: string;\n  readonly bcmRoot: string;\n  readonly peopleRoot: string;\n  readonly companiesRoot: string;\n  readonly softwareRoot: string;\n  readonly industriesRoot: string;\n  readonly requirementCategoryDirs: ResolvedRequirementCategoryDirs;\n}\n\n/**\n * Canonical default subdirectory name for each requirement category.\n * These mirror the hardcoded `functional/`, `non-functional/`, … dirs\n * that the requirements bundles emitted before category dirs became\n * configurable, so the generated requirements snapshot is unchanged\n * unless a consumer overrides an entry.\n */\nexport const DEFAULT_REQUIREMENT_CATEGORY_DIRS: ResolvedRequirementCategoryDirs =\n  Object.freeze({\n    business: \"business\",\n    functional: \"functional\",\n    nonFunctional: \"non-functional\",\n    technical: \"technical\",\n    architecturalDecisions: \"architectural-decisions\",\n    security: \"security\",\n    data: \"data\",\n    integration: \"integration\",\n    operational: \"operational\",\n    ux: \"ux\",\n    multiTenancy: \"multi-tenancy\",\n  });\n\n/**\n * Canonical default values for every agent path. These mirror the\n * hardcoded paths that bundles used before `AgentPathsConfig` existed,\n * so `DEFAULT_AGENT_PATHS.*` can be substituted into bundle rule\n * content at module-eval time without changing the generated\n * `.claude/rules/*.md` snapshot.\n *\n * Consumers override the defaults by passing an `AgentPathsConfig`\n * through `AgentConfigOptions.paths` and resolving it with\n * `resolveAgentPaths()`. Every path-aware bundle threads the resolved\n * struct through its rule / skill / sub-agent content, so an override\n * propagates into the rendered output.\n */\nexport const DEFAULT_AGENT_PATHS: ResolvedAgentPaths = Object.freeze({\n  docsRoot: \"docs/src/content/docs\",\n  researchRoot: \"docs/research\",\n  profilesRoot: \"docs/src/content/docs/profiles\",\n  meetingsRoot: \"docs/src/content/docs/meetings\",\n  requirementsRoot: \"docs/src/content/docs/requirements\",\n  researchRequirementsRoot: \"docs/research/requirements\",\n  bcmRoot: \"docs/src/content/docs/concepts\",\n  peopleRoot: \"docs/src/content/docs/profiles/people\",\n  companiesRoot: \"docs/src/content/docs/profiles/companies\",\n  softwareRoot: \"docs/src/content/docs/profiles/software\",\n  industriesRoot: \"docs/src/content/docs/profiles/industries\",\n  requirementCategoryDirs: DEFAULT_REQUIREMENT_CATEGORY_DIRS,\n});\n\n/**\n * Resolve a partial `AgentPathsConfig` into a fully-populated\n * `ResolvedAgentPaths`. Unset fields cascade from their parent root:\n *\n * - `profilesRoot`, `meetingsRoot`, `requirementsRoot`, and `bcmRoot`\n *   derive from `docsRoot` when not explicitly set.\n * - `researchRequirementsRoot` derives from `researchRoot` when not\n *   explicitly set.\n * - `peopleRoot`, `companiesRoot`, `softwareRoot`, and `industriesRoot`\n *   derive from the resolved `profilesRoot` when not explicitly set,\n *   so that overriding `docsRoot` alone (or overriding `profilesRoot`\n *   alone) propagates correctly through every dependent root.\n */\nexport function resolveAgentPaths(\n  paths?: AgentPathsConfig,\n): ResolvedAgentPaths {\n  const docsRoot = paths?.docsRoot ?? DEFAULT_AGENT_PATHS.docsRoot;\n  const researchRoot = paths?.researchRoot ?? DEFAULT_AGENT_PATHS.researchRoot;\n\n  const profilesRoot = paths?.profilesRoot ?? `${docsRoot}/profiles`;\n  const meetingsRoot = paths?.meetingsRoot ?? `${docsRoot}/meetings`;\n  const requirementsRoot =\n    paths?.requirementsRoot ?? `${docsRoot}/requirements`;\n  const bcmRoot = paths?.bcmRoot ?? `${docsRoot}/concepts`;\n\n  const researchRequirementsRoot =\n    paths?.researchRequirementsRoot ?? `${researchRoot}/requirements`;\n\n  const peopleRoot = paths?.peopleRoot ?? `${profilesRoot}/people`;\n  const companiesRoot = paths?.companiesRoot ?? `${profilesRoot}/companies`;\n  const softwareRoot = paths?.softwareRoot ?? `${profilesRoot}/software`;\n  const industriesRoot = paths?.industriesRoot ?? `${profilesRoot}/industries`;\n\n  const categoryOverrides = paths?.requirementCategoryDirs;\n  const requirementCategoryDirs: ResolvedRequirementCategoryDirs = {\n    business:\n      categoryOverrides?.business ?? DEFAULT_REQUIREMENT_CATEGORY_DIRS.business,\n    functional:\n      categoryOverrides?.functional ??\n      DEFAULT_REQUIREMENT_CATEGORY_DIRS.functional,\n    nonFunctional:\n      categoryOverrides?.nonFunctional ??\n      DEFAULT_REQUIREMENT_CATEGORY_DIRS.nonFunctional,\n    technical:\n      categoryOverrides?.technical ??\n      DEFAULT_REQUIREMENT_CATEGORY_DIRS.technical,\n    architecturalDecisions:\n      categoryOverrides?.architecturalDecisions ??\n      DEFAULT_REQUIREMENT_CATEGORY_DIRS.architecturalDecisions,\n    security:\n      categoryOverrides?.security ?? DEFAULT_REQUIREMENT_CATEGORY_DIRS.security,\n    data: categoryOverrides?.data ?? DEFAULT_REQUIREMENT_CATEGORY_DIRS.data,\n    integration:\n      categoryOverrides?.integration ??\n      DEFAULT_REQUIREMENT_CATEGORY_DIRS.integration,\n    operational:\n      categoryOverrides?.operational ??\n      DEFAULT_REQUIREMENT_CATEGORY_DIRS.operational,\n    ux: categoryOverrides?.ux ?? DEFAULT_REQUIREMENT_CATEGORY_DIRS.ux,\n    multiTenancy:\n      categoryOverrides?.multiTenancy ??\n      DEFAULT_REQUIREMENT_CATEGORY_DIRS.multiTenancy,\n  };\n\n  return {\n    docsRoot,\n    researchRoot,\n    profilesRoot,\n    meetingsRoot,\n    requirementsRoot,\n    researchRequirementsRoot,\n    bcmRoot,\n    peopleRoot,\n    companiesRoot,\n    softwareRoot,\n    industriesRoot,\n    requirementCategoryDirs,\n  };\n}\n","import { ProgressFilesConfig } from \"../agent-config-options\";\n\n/**\n * Default master switch for the progress-file convention. When no\n * config is supplied, the convention ships **enabled** so every phased\n * agent writes a progress file on claim and reads it on resume.\n *\n * @see ProgressFilesConfig\n */\nexport const DEFAULT_PROGRESS_FILES_ENABLED = true;\n\n/**\n * Default on-disk root for progress files, relative to the repo root.\n * Every progress file resolves to\n * `<stateDir>/<filename>` where `<filename>` is produced from\n * `filenamePattern` at runtime.\n *\n * Lives at the top-level `.state/` directory so the path stays\n * harness-neutral — any agent runtime (Claude Code, Cursor, a\n * bespoke worker) can read and write the same progress files\n * without having to scope under a harness-specific tree.\n *\n * @see ProgressFilesConfig\n */\nexport const DEFAULT_PROGRESS_FILES_STATE_DIR = \".state\";\n\n/**\n * Default filename pattern for a progress file. The `<ISSUE_NUMBER>`\n * placeholder is substituted at runtime with the numeric id of the\n * issue the agent is working on (e.g. `479-progress.json`).\n *\n * The placeholder uses the angle-bracketed uppercase-snake form — not\n * `{{curly-brace}}` form — because `AgentConfig`'s template resolver\n * claims the curly-brace namespace at rule generation time.\n *\n * @see ProgressFilesConfig\n */\nexport const DEFAULT_PROGRESS_FILES_FILENAME_PATTERN =\n  \"<ISSUE_NUMBER>-progress.json\";\n\n/**\n * Default serialization format for a progress file body. JSON is the\n * default because it is trivially machine-parseable (e.g. for scripted\n * resume logic) while still remaining human-readable when opened.\n * Consumers that prefer the openhi-style markdown body can override.\n *\n * @see ProgressFilesConfig\n */\nexport const DEFAULT_PROGRESS_FILES_FORMAT: \"json\" | \"markdown\" = \"json\";\n\n/**\n * Default stale-threshold (hours) for branches carrying a progress\n * file. When the orchestrator's stale-branch decision tree finds a\n * progress file older than this many hours **and** no matching open\n * PR, it treats the branch as abandoned and resets the issue to\n * `status:ready`. Mirrors the 72-hour in-progress threshold used by\n * the orchestrator bundle's triage walk.\n *\n * @see ProgressFilesConfig\n */\nexport const DEFAULT_PROGRESS_FILES_STALE_AFTER_HOURS = 72;\n\n/**\n * Allowed values for `ProgressFilesConfig.format`. Exported so\n * consumers can reference the canonical set without hard-coding\n * literals.\n */\nexport const PROGRESS_FILES_FORMAT_VALUES = [\"json\", \"markdown\"] as const;\n\n/**\n * Fully-resolved progress-file settings. Every field is defaulted so\n * downstream renderers can reason about a single canonical shape.\n */\nexport interface ResolvedProgressFiles {\n  readonly enabled: boolean;\n  readonly stateDir: string;\n  readonly filenamePattern: string;\n  readonly format: \"json\" | \"markdown\";\n  readonly cleanupOnComplete: boolean;\n  readonly staleAfterHours: number;\n}\n\n/**\n * Resolve a (possibly absent) `ProgressFilesConfig` into a canonical\n * `ResolvedProgressFiles` with every field filled in. Unset fields\n * cascade from their documented defaults.\n *\n * Malformed configs — empty / whitespace-only `stateDir`, absolute\n * `stateDir`, empty / whitespace-only `filenamePattern`, `filenamePattern`\n * missing the `<ISSUE_NUMBER>` placeholder, unknown `format` value,\n * non-positive `staleAfterHours` — throw a descriptive `Error`.\n */\nexport function resolveProgressFiles(\n  config?: ProgressFilesConfig,\n): ResolvedProgressFiles {\n  const stateDir = config?.stateDir ?? DEFAULT_PROGRESS_FILES_STATE_DIR;\n  assertValidStateDir(stateDir);\n\n  const filenamePattern =\n    config?.filenamePattern ?? DEFAULT_PROGRESS_FILES_FILENAME_PATTERN;\n  assertValidFilenamePattern(filenamePattern);\n\n  const format = config?.format ?? DEFAULT_PROGRESS_FILES_FORMAT;\n  assertValidFormat(format);\n\n  const staleAfterHours =\n    config?.staleAfterHours ?? DEFAULT_PROGRESS_FILES_STALE_AFTER_HOURS;\n  assertValidStaleAfterHours(staleAfterHours);\n\n  return {\n    enabled: config?.enabled ?? DEFAULT_PROGRESS_FILES_ENABLED,\n    stateDir,\n    filenamePattern,\n    format,\n    cleanupOnComplete: config?.cleanupOnComplete ?? true,\n    staleAfterHours,\n  };\n}\n\n/**\n * Synth-time validation hook. Throws a descriptive `Error` when the\n * supplied `ProgressFilesConfig` is malformed. Called by\n * `AgentConfig.preSynthesize` before any rendering so a misconfigured\n * convention fails the build instead of silently shipping broken\n * resume semantics. Returns the resolved config unchanged so callers\n * can write `const pf = validateProgressFilesConfig(config)` in\n * one line.\n *\n * Malformed cases rejected here:\n *\n * - `stateDir` empty, whitespace-only, or absolute.\n * - `filenamePattern` empty, whitespace-only, or missing the\n *   `<ISSUE_NUMBER>` placeholder.\n * - `format` not one of `\"json\"` / `\"markdown\"`.\n * - `staleAfterHours` non-integer, zero, or negative.\n */\nexport function validateProgressFilesConfig(\n  config?: ProgressFilesConfig,\n): ResolvedProgressFiles {\n  return resolveProgressFiles(config);\n}\n\n/**\n * Resolve the runtime filename for a progress file given an issue\n * number and a resolved config. `<ISSUE_NUMBER>` placeholders in the\n * pattern are substituted; the returned value is **just** the filename\n * (no directory prefix).\n *\n * Exported so consumer-side scripts (or the `partial-resume-protocol`\n * rule renderer) can compute the on-disk path deterministically.\n */\nexport function renderProgressFileName(\n  pf: ResolvedProgressFiles,\n  issueNumber: number | string,\n): string {\n  return pf.filenamePattern.replace(/<ISSUE_NUMBER>/g, String(issueNumber));\n}\n\n/**\n * Resolve the runtime path (directory + filename) for a progress file\n * given an issue number and a resolved config.\n */\nexport function renderProgressFilePath(\n  pf: ResolvedProgressFiles,\n  issueNumber: number | string,\n): string {\n  return `${pf.stateDir}/${renderProgressFileName(pf, issueNumber)}`;\n}\n\n/**\n * Render the full body for the `progress-file-convention` rule shipped\n * by the `base` bundle. The rule documents:\n *\n * - The progress-file schema and on-disk path contract.\n * - The partial-resume protocol (read-before-write + acceptance\n *   criteria replay).\n * - The stale-branch decision tree (clone-level recovery) that every\n *   worker runs at session start.\n * - The `[BLOCKED]` structured comment format used when an agent\n *   cannot proceed.\n *\n * When the convention is disabled, the rule renders a short stub that\n * tells agents the project does not enforce progress files and they\n * must pick up work from scratch on every session.\n */\nexport function renderProgressFilesRuleContent(\n  pf: ResolvedProgressFiles,\n): string {\n  if (!pf.enabled) {\n    return [\n      \"# Progress File Convention\",\n      \"\",\n      \"**Progress files are disabled in this project.** Agents do not\",\n      \"write a progress file when claiming an issue, and resumed\",\n      \"sessions start from scratch rather than reading per-session\",\n      \"state. The partial-resume protocol (below) still applies when an\",\n      \"output file exists from a partial write — agents always check\",\n      \"the Output Path before starting.\",\n      \"\",\n      \"Enable progress files via\",\n      \"`AgentConfigOptions.progressFiles.enabled = true`.\",\n      \"\",\n      ...partialResumeSection(),\n      \"\",\n      ...staleBranchSection(),\n      \"\",\n      ...blockedCommentSection(),\n    ].join(\"\\n\");\n  }\n\n  const examplePath = renderProgressFilePath(pf, \"<N>\");\n  const lines: Array<string> = [\n    \"# Progress File Convention\",\n    \"\",\n    \"Every phased agent session writes a small **progress file** to\",\n    \"disk as its first action after claiming an issue, updates it after\",\n    \"each non-trivial step, and deletes it in the final commit that\",\n    \"closes the issue. If the session crashes, the next session reads\",\n    \"the progress file, confirms on-disk state matches reality, and\",\n    \"resumes from the next uncompleted step instead of starting over.\",\n    \"\",\n    \"Progress files are the **work-level** recovery mechanism. They\",\n    \"complement the clone-level stale-branch recovery documented in\",\n    '\"Stale Branch Recovery\" below — that step restores the checkout',\n    \"to a clean main; this convention restores the *deliverable* to a\",\n    \"partially-complete state that resumed work can build on.\",\n    \"\",\n    \"## On-disk Contract\",\n    \"\",\n    `Progress files live at \\`${examplePath}\\`, where \\`<N>\\` is the`,\n    \"numeric issue id the agent is working on. The directory\",\n    `\\`${pf.stateDir}\\` is gitignored — progress files stay on the`,\n    \"working branch until the issue closes and are removed at that\",\n    \"time; they must never land on the default branch.\",\n    \"\",\n    `**Serialization format:** \\`${pf.format}\\`.`,\n    \"\",\n  ];\n\n  if (pf.format === \"json\") {\n    lines.push(\n      \"### Schema (JSON)\",\n      \"\",\n      \"```json\",\n      \"{\",\n      '  \"issue\": <N>,',\n      '  \"agent\": \"<agent-name>\",',\n      '  \"phase\": \"<phase-label>\",',\n      '  \"started\": \"YYYY-MM-DDTHH:MM:SSZ\",',\n      '  \"last_updated\": \"YYYY-MM-DDTHH:MM:SSZ\",',\n      '  \"checkpoints\": [',\n      '    { \"name\": \"read-inputs\",       \"status\": \"done\",        \"note\": \"N files\" },',\n      '    { \"name\": \"draft-section-1\",   \"status\": \"done\",        \"note\": \"lines 1-45\" },',\n      '    { \"name\": \"draft-section-2\",   \"status\": \"in-progress\", \"note\": \"60% done\" },',\n      '    { \"name\": \"draft-section-3\",   \"status\": \"todo\" }',\n      \"  ],\",\n      '  \"decisions\": [',\n      '    \"<key decision and rationale>\"',\n      \"  ],\",\n      '  \"next_action\": \"<what the next session should do first>\"',\n      \"}\",\n      \"```\",\n      \"\",\n      \"**Required fields:** `issue`, `agent`, `phase`, `started`,\",\n      \"`last_updated`, `checkpoints`, `next_action`.\",\n      \"\",\n      \"**`checkpoints[].status`** is one of `todo`, `in-progress`,\",\n      \"`done`. Always order entries to match execution order — the\",\n      \"resumed agent walks the array left-to-right and picks up at the\",\n      \"first non-`done` entry.\",\n      \"\",\n      \"**`decisions`** is optional and may be omitted when no key\",\n      \"decisions have been made.\",\n      \"\",\n    );\n  } else {\n    lines.push(\n      \"### Schema (Markdown)\",\n      \"\",\n      \"```markdown\",\n      \"---\",\n      \"issue: <N>\",\n      \"agent: <agent-name>\",\n      \"phase: <phase-label>\",\n      \"started: YYYY-MM-DDTHH:MM:SSZ\",\n      \"last_updated: YYYY-MM-DDTHH:MM:SSZ\",\n      \"---\",\n      \"\",\n      \"## Progress\",\n      \"- [x] Read inputs (N files)\",\n      \"- [x] Section 1: <name> (written, lines 1-45)\",\n      \"- [ ] Section 2: <name> (in progress, ~60% done)\",\n      \"- [ ] Section 3: <name>\",\n      \"\",\n      \"## Decisions Made\",\n      \"- <key decision and rationale>\",\n      \"\",\n      \"## Next Action\",\n      \"<what the next session should do first>\",\n      \"```\",\n      \"\",\n      \"Checkboxes map directly to checkpoint state: `[x]` is `done`,\",\n      \"`[ ]` with inline progress text is `in-progress`, and a plain\",\n      \"`[ ]` is `todo`.\",\n      \"\",\n    );\n  }\n\n  lines.push(\n    \"## Write Rules\",\n    \"\",\n    \"1. **Write on claim.** Create the progress file as the first\",\n    \"   action after claiming an issue — before reading inputs, before\",\n    \"   starting any deliverable work. Commit the file in the same\",\n    \"   commit that records the claim.\",\n    \"2. **Update after each step.** After completing a section, reading\",\n    \"   a key input, or making a significant decision, update the\",\n    \"   progress file and include it in the next commit.\",\n    \"3. **Commit progress alongside work.** Never commit deliverable\",\n    \"   changes without also updating the progress file in the same\",\n    \"   commit. Mixed commits keep the work-level recovery atomic.\",\n    \"4. **Set `last_updated` on every write.** Use an ISO-8601\",\n    \"   UTC timestamp (`YYYY-MM-DDTHH:MM:SSZ`). Stale `last_updated`\",\n    \"   values feed the stale-branch decision tree below.\",\n  );\n\n  if (pf.cleanupOnComplete) {\n    lines.push(\n      \"5. **Delete on completion.** The final commit that closes the\",\n      \"   issue must remove the progress file. Progress files are a\",\n      \"   working-branch artefact; they do not land on the default\",\n      \"   branch.\",\n    );\n  } else {\n    lines.push(\n      \"5. **Retention on completion.** This project retains progress\",\n      \"   files on the default branch as an audit trail — the final\",\n      \"   commit does **not** remove them. Downstream tooling that\",\n      \"   scans `\" + pf.stateDir + \"` should skip completed issues by reading\",\n      \"   the `phase` field.\",\n    );\n  }\n\n  lines.push(\n    \"\",\n    ...partialResumeSection(),\n    \"\",\n    ...staleBranchSection(pf.staleAfterHours),\n    \"\",\n    ...blockedCommentSection(),\n  );\n\n  return lines.join(\"\\n\");\n}\n\n/**\n * Render the short progress-file hook section injected into a\n * phased-agent bundle's workflow rule (bcm-writer, research-pipeline,\n * etc.). The section cites the full contract documented in the base\n * bundle's `progress-file-convention` rule so individual bundles stay\n * DRY.\n *\n * When the convention is disabled, the function returns an empty\n * string so callers can no-op their append path.\n */\nexport function renderProgressFilesBundleHook(\n  pf: ResolvedProgressFiles,\n  bundleLabel: string,\n): string {\n  if (!pf.enabled) {\n    return \"\";\n  }\n\n  const examplePath = renderProgressFilePath(pf, \"<N>\");\n  return [\n    \"## Progress File\",\n    \"\",\n    `Every ${bundleLabel} session writes a progress file to`,\n    `\\`${examplePath}\\` on claim, updates it after each phase step,`,\n    \"and deletes it in the final commit that closes the issue. See\",\n    \"the `progress-file-convention` rule for the full schema, write\",\n    \"rules, and partial-resume protocol.\",\n    \"\",\n    \"On startup, check for an existing progress file before doing any\",\n    \"substantive work. If one exists, read it and continue from the\",\n    \"`next_action` rather than starting the phase over.\",\n  ].join(\"\\n\");\n}\n\n/*******************************************************************************\n *\n * Internal helpers\n *\n ******************************************************************************/\n\nfunction partialResumeSection(): Array<string> {\n  return [\n    \"## Partial-Resume Protocol\",\n    \"\",\n    \"Before writing any Output Path file, always check whether the\",\n    \"file already exists (from a previous crashed session or partial\",\n    \"write). If it does:\",\n    \"\",\n    \"1. **Read the existing file** in full.\",\n    \"2. **Compare it against the Acceptance Criteria** from the issue\",\n    \"   body.\",\n    \"3. **Identify which criteria are already met** by the existing\",\n    \"   content.\",\n    \"4. **Resume from the first unmet criterion** — do not rewrite\",\n    \"   sections that already satisfy their criterion.\",\n    \"5. **Comment on the issue:** `Resuming from partial deliverable\",\n    \"   (N/M criteria already met).`\",\n    \"\",\n    \"### When the existing file is complete\",\n    \"\",\n    \"If the existing file satisfies **every** acceptance criterion:\",\n    \"\",\n    \"1. Verify cross-references are intact.\",\n    \"2. Skip to the commit / PR step — the issue may already be done.\",\n    \"3. Comment: `Output file already satisfies all acceptance\",\n    \"   criteria. Proceeding to mark done.`\",\n    \"\",\n    \"This protocol applies to every agent and supersedes the generic\",\n    '\"read it first\" guidance. The progress file provides additional',\n    \"context about what was completed, but even without a progress\",\n    \"file the partial-resume check ensures no work is lost.\",\n  ];\n}\n\nfunction staleBranchSection(staleAfterHours?: number): Array<string> {\n  const hours = staleAfterHours ?? DEFAULT_PROGRESS_FILES_STALE_AFTER_HOURS;\n  return [\n    \"## Stale Branch Recovery\",\n    \"\",\n    \"Agent sessions work inside a dedicated checkout of the repository\",\n    \"that persists between sessions. If a session crashes before\",\n    \"returning to the default branch, the next session inherits a\",\n    \"stale branch. Every agent runs the following decision tree at\",\n    \"session start, **before** any other work:\",\n    \"\",\n    \"| Clone state at session start | Action |\",\n    \"|------------------------------|--------|\",\n    \"| On the default branch | Normal flow — proceed. |\",\n    \"| On a branch, no local changes, no new commits | Delete the branch and check out the default branch. |\",\n    \"| On a branch, uncommitted changes | Stash the changes (retained in the clone for inspection) and check out the default branch. |\",\n    \"| On a branch, commits exist, no open PR | Push the branch, leave a comment on the linked issue citing the branch name, then check out the default branch. |\",\n    \"| On a branch, open PR exists | Check out the default branch — the work is already submitted. |\",\n    \"\",\n    \"### Resume hand-off\",\n    \"\",\n    \"After clone-level recovery returns the checkout to the default\",\n    \"branch, the orchestrator's stale-issue recovery may reset the\",\n    \"crashed issue to `status:ready`. The next worker session picks\",\n    \"up the issue, reads the progress file from the working branch\",\n    \"(e.g. via `git show origin/<branch>:<progress-file-path>`), and\",\n    \"continues from the `next_action` recorded there.\",\n    \"\",\n    `**Stale threshold:** a branch whose progress file's`,\n    `\\`last_updated\\` is older than **${hours} hours** and that has`,\n    \"no matching open PR is considered abandoned. Operators may flip\",\n    \"the issue back to `status:ready` so a fresh session can claim it;\",\n    \"the partial-resume protocol above ensures the new session picks\",\n    \"up the partial deliverable rather than starting over.\",\n  ];\n}\n\nfunction blockedCommentSection(): Array<string> {\n  return [\n    \"## Blocked-Comment Format\",\n    \"\",\n    \"When an agent cannot proceed — missing upstream file, ambiguous\",\n    \"dependency, unresolved human decision — it posts a structured\",\n    \"`[BLOCKED]` comment on the issue before stopping:\",\n    \"\",\n    \"```\",\n    \"[BLOCKED] Reason: <description>\",\n    \"Depends on: #<N> (if formal dependency) or\",\n    '  \"No formal dependency — needs human input\"',\n    \"Expected resolution: <what needs to happen to unblock>\",\n    \"```\",\n    \"\",\n    \"The `Depends on:` line uses the repository's standard dependency\",\n    \"syntax so the block integrates with the orchestrator's dependency\",\n    \"sweep. Blocks with no formal dependency are escalated by the\",\n    \"orchestrator's triage walk after the project's ambiguous-block\",\n    \"threshold elapses.\",\n  ];\n}\n\nfunction assertValidStateDir(value: string): void {\n  if (typeof value !== \"string\" || value.trim().length === 0) {\n    throw new Error(\n      `ProgressFilesConfig.stateDir must be a non-empty string; got ${JSON.stringify(\n        value,\n      )}`,\n    );\n  }\n  if (value.startsWith(\"/\")) {\n    throw new Error(\n      `ProgressFilesConfig.stateDir must be a repo-relative path (no leading '/'); got ${JSON.stringify(\n        value,\n      )}`,\n    );\n  }\n}\n\nfunction assertValidFilenamePattern(value: string): void {\n  if (typeof value !== \"string\" || value.trim().length === 0) {\n    throw new Error(\n      `ProgressFilesConfig.filenamePattern must be a non-empty string; got ${JSON.stringify(\n        value,\n      )}`,\n    );\n  }\n  if (!value.includes(\"<ISSUE_NUMBER>\")) {\n    throw new Error(\n      `ProgressFilesConfig.filenamePattern must contain the '<ISSUE_NUMBER>' placeholder; got ${JSON.stringify(\n        value,\n      )}`,\n    );\n  }\n  if (value.includes(\"/\")) {\n    throw new Error(\n      `ProgressFilesConfig.filenamePattern must not contain '/' — use 'stateDir' for the directory; got ${JSON.stringify(\n        value,\n      )}`,\n    );\n  }\n}\n\nfunction assertValidFormat(value: string): void {\n  if (!PROGRESS_FILES_FORMAT_VALUES.includes(value as \"json\" | \"markdown\")) {\n    throw new Error(\n      `ProgressFilesConfig.format must be one of ${PROGRESS_FILES_FORMAT_VALUES.join(\n        \", \",\n      )}; got ${JSON.stringify(value)}`,\n    );\n  }\n}\n\nfunction assertValidStaleAfterHours(value: number): void {\n  if (\n    typeof value !== \"number\" ||\n    !Number.isInteger(value) ||\n    value <= 0 ||\n    !Number.isFinite(value)\n  ) {\n    throw new Error(\n      `ProgressFilesConfig.staleAfterHours must be a positive integer; got ${JSON.stringify(\n        value,\n      )}`,\n    );\n  }\n}\n","import { SharedEditingConfig } from \"../agent-config-options\";\n\n/**\n * Default master switch for the shared-editing convention. When no\n * config is supplied, the convention ships **enabled** so every agent\n * that edits an index file follows the single-entry / verify /\n * re-sort protocol.\n *\n * @see SharedEditingConfig\n */\nexport const DEFAULT_SHARED_EDITING_ENABLED = true;\n\n/**\n * Default list of path patterns considered \"shared index files\". The\n * patterns are plain glob strings rendered verbatim into the rule body\n * — agents match against them when deciding whether the shared-editing\n * contract applies to the file they are about to edit.\n *\n * The defaults cover the registry / index files every configulator\n * consumer ships by convention:\n *\n * - A monorepo-wide docs site at `/docs` with one or more `index.md` /\n *   `README.md` registry tables.\n * - Category landing pages under `docs/src/content/docs/**` that list\n *   every profile, requirement, or capability in their category.\n * - Feature matrices produced by the `software-profile` bundle.\n *\n * Consumers can replace the list outright via `sharedIndexPaths` or\n * append project-specific registries.\n *\n * @see SharedEditingConfig\n */\nexport const DEFAULT_SHARED_INDEX_PATHS: ReadonlyArray<string> = [\n  \"docs/src/content/docs/**/index.md\",\n  \"docs/src/content/docs/**/README.md\",\n  \"docs/src/content/docs/**/feature-matrix.md\",\n];\n\n/**\n * Default conflict-resolution strategy rendered into the rule body.\n * `rebase` matches the `git pull --rebase` workflow every\n * configulator-managed repo already uses for feature branches; the\n * alternative (`merge`) is documented for projects that keep a\n * merge-commit-only history.\n *\n * @see SharedEditingConfig\n */\nexport const DEFAULT_SHARED_EDITING_CONFLICT_STRATEGY: \"rebase\" | \"merge\" =\n  \"rebase\";\n\n/**\n * Default for whether the convention renders the commit-path\n * verification protocol (read-back + single-row assertion). The\n * verification step is cheap, catches staging / path bugs that would\n * otherwise land on the branch, and is the core safety net the openhi\n * reference promotes — so it ships **on** by default.\n *\n * @see SharedEditingConfig\n */\nexport const DEFAULT_SHARED_EDITING_VERIFY_COMMIT = true;\n\n/**\n * Default for whether the convention emits the\n * `.claude/procedures/verify-index-row.sh` helper to disk. The helper\n * is opt-in because many consumers prefer to do the verification\n * inline via the documented `git show HEAD:<path>` recipe rather than\n * shell out to a dedicated script. Consumers that want the script\n * available to sub-agents enable the emission explicitly.\n *\n * @see SharedEditingConfig\n */\nexport const DEFAULT_SHARED_EDITING_EMIT_HELPER = false;\n\n/**\n * Allowed values for `SharedEditingConfig.conflictStrategy`. Exported\n * so consumers can reference the canonical set without hard-coding\n * literals.\n */\nexport const SHARED_EDITING_CONFLICT_STRATEGY_VALUES = [\n  \"rebase\",\n  \"merge\",\n] as const;\n\n/**\n * Fully-resolved shared-editing settings. Every field is defaulted so\n * downstream renderers can reason about a single canonical shape.\n */\nexport interface ResolvedSharedEditing {\n  readonly enabled: boolean;\n  readonly sharedIndexPaths: ReadonlyArray<string>;\n  readonly verifyCommit: boolean;\n  readonly conflictStrategy: \"rebase\" | \"merge\";\n  readonly emitHelper: boolean;\n}\n\n/**\n * Resolve a (possibly absent) `SharedEditingConfig` into a canonical\n * `ResolvedSharedEditing` with every field filled in. Unset fields\n * cascade from their documented defaults.\n *\n * Malformed configs — empty / whitespace-only `sharedIndexPaths`\n * entry, unknown `conflictStrategy` — throw a descriptive `Error`.\n */\nexport function resolveSharedEditing(\n  config?: SharedEditingConfig,\n): ResolvedSharedEditing {\n  const sharedIndexPaths =\n    config?.sharedIndexPaths ?? DEFAULT_SHARED_INDEX_PATHS;\n  assertValidSharedIndexPaths(sharedIndexPaths);\n\n  const conflictStrategy =\n    config?.conflictStrategy ?? DEFAULT_SHARED_EDITING_CONFLICT_STRATEGY;\n  assertValidConflictStrategy(conflictStrategy);\n\n  return {\n    enabled: config?.enabled ?? DEFAULT_SHARED_EDITING_ENABLED,\n    sharedIndexPaths,\n    verifyCommit: config?.verifyCommit ?? DEFAULT_SHARED_EDITING_VERIFY_COMMIT,\n    conflictStrategy,\n    emitHelper: config?.emitHelper ?? DEFAULT_SHARED_EDITING_EMIT_HELPER,\n  };\n}\n\n/**\n * Synth-time validation hook. Throws a descriptive `Error` when the\n * supplied `SharedEditingConfig` is malformed. Called by\n * `AgentConfig.preSynthesize` before any rendering so a misconfigured\n * convention fails the build instead of silently shipping broken\n * shared-editing guidance. Returns the resolved config unchanged so\n * callers can write `const se = validateSharedEditingConfig(config)`\n * in one line.\n *\n * Malformed cases rejected here:\n *\n * - `sharedIndexPaths` contains an empty / whitespace-only entry, or\n *   the array is supplied but empty.\n * - `conflictStrategy` is not one of `\"rebase\"` / `\"merge\"`.\n */\nexport function validateSharedEditingConfig(\n  config?: SharedEditingConfig,\n): ResolvedSharedEditing {\n  return resolveSharedEditing(config);\n}\n\n/**\n * Render the full body for the `shared-editing-safety` rule shipped\n * by the `base` bundle. The rule documents:\n *\n * - The catalog of shared index files the contract applies to.\n * - The pre-edit read-latest protocol (pull + re-read before editing).\n * - The single-entry, deterministic-sort row-insert rule.\n * - The commit-path verification step (read-back + count assertion).\n * - The merge-conflict resolution recipe (rebase, re-sort, re-verify).\n *\n * When the convention is disabled, the rule renders a short stub that\n * tells agents the project does not enforce the convention and that\n * concurrent edits to shared index files may require manual conflict\n * resolution.\n */\nexport function renderSharedEditingRuleContent(\n  se: ResolvedSharedEditing,\n): string {\n  if (!se.enabled) {\n    return [\n      \"# Shared-Editing Safety\",\n      \"\",\n      \"**Shared-editing safety is disabled in this project.** Agents\",\n      \"may edit index files without running the single-entry /\",\n      \"verify / re-sort protocol documented by configulator. When two\",\n      \"agents complete work in parallel and both write to the same\",\n      \"registry, humans must resolve any resulting merge conflicts\",\n      \"manually.\",\n      \"\",\n      \"Enable the convention via\",\n      \"`AgentConfigOptions.sharedEditing.enabled = true`.\",\n    ].join(\"\\n\");\n  }\n\n  const lines: Array<string> = [\n    \"# Shared-Editing Safety\",\n    \"\",\n    \"Multiple concurrent agent sessions frequently need to edit the\",\n    \"same **shared index file** — registry `README.md` / `index.md`\",\n    \"row tables, category landing pages, feature matrices. Without a\",\n    \"shared contract, parallel sessions conflict on the index even\",\n    \"when their content contributions are completely independent, and\",\n    \"the resolver may accidentally drop a row when reconciling the\",\n    \"conflict.\",\n    \"\",\n    \"This rule codifies the convention every agent follows when\",\n    \"touching a shared index file: pull the latest, make a\",\n    \"single-entry edit in deterministic sort order, verify the row\",\n    \"landed in the commit, and follow a scripted recipe when a\",\n    \"conflict does arise.\",\n    \"\",\n    \"## What Counts as a Shared Index File\",\n    \"\",\n    \"Agents treat any file matching one of the following patterns as\",\n    \"a shared index — the contract in this rule applies before\",\n    \"committing to it:\",\n    \"\",\n    ...se.sharedIndexPaths.map((p) => `- \\`${p}\\``),\n    \"\",\n    \"Registry tables, category landing pages, and feature matrices\",\n    \"embedded inside a larger document are also shared indexes — the\",\n    \"table itself is the index, not the file. Treat those sections\",\n    \"as append-only where possible: add a new row instead of\",\n    \"rewriting existing rows.\",\n    \"\",\n    \"## Index File Format Contract\",\n    \"\",\n    \"Every shared index follows the same three-part format so the\",\n    \"insert position is mechanical rather than editorial:\",\n    \"\",\n    \"1. **Header** — a stable opening (title, prose intro, table\",\n    \"   header row). Agents never edit the header when adding a row.\",\n    \"2. **Separator** — a markdown table separator (`|---|---|`) or\",\n    \"   an equivalent horizontal rule between header and rows.\",\n    \"3. **Rows** — one entry per shared item, sorted by a single\",\n    \"   deterministic key documented at the top of the file\",\n    \"   (alphabetical on the first column, chronological on a date\",\n    \"   column, etc.). If the file does not document a key, sort\",\n    \"   alphabetically on the first column.\",\n    \"\",\n    \"## Pre-Edit Protocol\",\n    \"\",\n    \"Before writing a new row to a shared index file:\",\n    \"\",\n    \"1. **Pull the latest default branch into your working branch**:\",\n    \"\",\n    \"   ```bash\",\n    \"   git fetch origin\",\n    `   git pull --${se.conflictStrategy} origin <default-branch>`,\n    \"   ```\",\n    \"\",\n    \"2. **Read the current file** from the updated checkout — not a\",\n    \"   cached copy from earlier in the session. Identify the header,\",\n    \"   separator, and existing rows.\",\n    \"\",\n    \"3. **Compute the insert position** by walking the existing rows\",\n    \"   in declared sort order and finding the first row whose sort\",\n    \"   key is greater than your new row's key.\",\n    \"\",\n    \"4. **Insert exactly one row** for your new entry. Do not rewrite\",\n    \"   neighbouring rows, do not reorder the file, and do not batch\",\n    \"   unrelated index changes into the same edit.\",\n    \"\",\n    \"5. **Commit the index edit immediately**, in its own focused\",\n    \"   commit. Small index-only commits keep the merge-conflict\",\n    \"   surface tiny; bundling index rows with large content changes\",\n    \"   makes conflict resolution harder.\",\n    \"\",\n  ];\n\n  if (se.verifyCommit) {\n    lines.push(\n      \"## Commit-Path Verification\",\n      \"\",\n      \"After committing the index edit, confirm the row landed in the\",\n      \"commit before proceeding. This catches the class of failures\",\n      \"where the file was written to the working tree but not staged\",\n      \"— the test suite passes, the index looks right in the editor,\",\n      \"and the row silently fails to ship.\",\n      \"\",\n      \"Run the following check before pushing:\",\n      \"\",\n      \"```bash\",\n      \"# 1. Confirm the index file is in the last commit.\",\n      \"git show --name-only --pretty=format: HEAD | grep -Fxq '<index-path>' \\\\\",\n      \"  || { echo 'ERROR: index file not in last commit'; exit 1; }\",\n      \"\",\n      \"# 2. Confirm your row appears exactly once in the committed file.\",\n      \"count=$(git show HEAD:'<index-path>' | grep -Fc '<row-unique-marker>')\",\n      '[ \"$count\" = \"1\" ] \\\\',\n      '  || { echo \"ERROR: row count $count, expected 1\"; exit 1; }',\n      \"```\",\n      \"\",\n      \"`<row-unique-marker>` is a substring of the new row that is\",\n      \"unique across the whole file — typically the sort key, or the\",\n      \"link target the new row wraps. The `=1` assertion rejects both\",\n      \"the missing-row case (count `0`) and the duplicate-row case\",\n      \"(count `>=2`) that happens after a mis-merged conflict.\",\n      \"\",\n    );\n\n    if (se.emitHelper) {\n      lines.push(\n        \"The bundled `.claude/procedures/verify-index-row.sh` helper\",\n        \"runs the same two-step check in a single invocation — pass it\",\n        \"the index path and a unique-marker substring:\",\n        \"\",\n        \"```bash\",\n        \".claude/procedures/verify-index-row.sh <index-path> <row-unique-marker>\",\n        \"```\",\n        \"\",\n        \"The helper exits non-zero with a descriptive diagnostic on\",\n        \"any failure, so it plugs directly into pre-push hooks and CI\",\n        \"checks without further glue.\",\n        \"\",\n      );\n    }\n  }\n\n  lines.push(\n    \"## Defer Shared-Index Commit to Final Pre-Push Step\",\n    \"\",\n    \"Even with the single-entry, deterministic-sort discipline above,\",\n    \"two sessions that **prepare** their row inserts at the same time\",\n    \"still race on push: whichever session pushes second sees the\",\n    \"first session's commit on the remote and has to rebase its own\",\n    \"commit on top, regenerating the same insert position calculation\",\n    \"against a now-changed file. Repeated rebases multiply the chance\",\n    \"of a mis-merge that silently drops a row.\",\n    \"\",\n    \"Sessions that produce both content and a shared-index row insert\",\n    \"shrink this race window by deferring the index commit to the\",\n    \"**final pre-push step** — after every content commit has landed\",\n    \"locally, and immediately before `git push`:\",\n    \"\",\n    \"1. **Commit content first.** Write and commit every non-index\",\n    \"   change that the session produces (profile body, transcript\",\n    \"   extraction, requirement document, etc.) in its own focused\",\n    \"   commit or commits.\",\n    \"2. **Rebase against the remote default branch** before touching\",\n    \"   the shared index:\",\n    \"\",\n    \"   ```bash\",\n    \"   git fetch origin\",\n    `   git pull --${se.conflictStrategy} origin <default-branch>`,\n    \"   ```\",\n    \"\",\n    \"3. **Re-read the shared index** from the now-up-to-date working\",\n    \"   tree. Another session may have appended a row while this\",\n    \"   session's content commits were in flight.\",\n    \"4. **Re-compute the insert position** in declared sort order\",\n    \"   against the freshly-read rows. Do not assume the position\",\n    \"   computed earlier in the session is still correct.\",\n    \"5. **Insert the row and commit the index edit on its own** —\",\n    \"   one focused commit whose only file is the shared index. Run\",\n    \"   the commit-path verification (above) against that commit\",\n    \"   before continuing.\",\n    \"6. **Push immediately.** The shorter the wall-clock gap between\",\n    \"   the rebase / re-read in step 2 and the push, the smaller the\",\n    \"   window in which another session can land a competing row.\",\n    \"\",\n    \"Per-agent workflows that touch a shared index file should call\",\n    \"out this defer-to-final-commit sequence explicitly — see the\",\n    \"`meeting-analyst` and `software-profile-analyst` sub-agent\",\n    \"prompts for the canonical wording. The pattern is mechanical\",\n    \"(rebase, re-read, re-compute, focused commit, push) rather than\",\n    \"editorial, so the same recipe applies to every shared-index\",\n    \"row-producing agent regardless of what content surrounds it.\",\n    \"\",\n    \"## Merge-Conflict Resolution\",\n    \"\",\n    \"When `git push` reports a conflict on a shared index file (two\",\n    \"agents both added a row, both pushed), resolve it with the\",\n    \"following recipe instead of hand-merging the conflict markers:\",\n    \"\",\n    \"```bash\",\n    `git pull --${se.conflictStrategy} origin <branch>`,\n    \"# If the conflict is in a shared index file:\",\n    \"# 1. Abort any auto-merge that dropped either row.\",\n    \"# 2. Re-read the updated file (now contains the other agent's row).\",\n    \"# 3. Re-compute the insert position for your row in sort order.\",\n    \"# 4. Re-insert your row (single entry, correct position).\",\n    \"# 5. Stage the resolved file and continue.\",\n    \"git add <index-path>\",\n    `git ${se.conflictStrategy === \"rebase\" ? \"rebase --continue\" : \"commit\"}`,\n    \"git push\",\n    \"```\",\n    \"\",\n    \"After resolution, re-run the commit-path verification step to\",\n    \"confirm both rows (yours and the other agent's) appear in the\",\n    \"final committed file. A count of `2` against the column-header\",\n    \"separator, or a count of `1` against each agent's unique marker,\",\n    \"proves both contributions survived the merge.\",\n    \"\",\n    \"## Append-Only Where Possible\",\n    \"\",\n    \"Prefer append-only edits on shared indexes. Adding a row rarely\",\n    \"conflicts; rewriting or reordering existing rows almost always\",\n    \"does. If a shared index needs a structural change (column\",\n    \"added, sort key changed), file a dedicated issue for the change\",\n    \"rather than bundling it into a content-contributing PR.\",\n    \"\",\n    \"## Section Index Page Shape\",\n    \"\",\n    \"When any agent creates or updates an `index.md` (or `README.md`)\",\n    \"in a docs subdirectory under a Starlight content root, the file's\",\n    \"body must include:\",\n    \"\",\n    \"1. **A 1–2 paragraph summary** of the section's purpose and how\",\n    \"   it fits into the larger research, requirements, or capability\",\n    \"   area. Readers landing on the page should understand what's in\",\n    \"   the section without falling back to the sidebar.\",\n    \"\",\n    \"2. **A grouped, linked listing of the directory's children**\",\n    \"   (table or bullet list). When a natural taxonomy exists (e.g.\",\n    \"   organizations grouped by sub-segment, regulations grouped by\",\n    \"   jurisdiction, capabilities grouped by tier), use it. Otherwise\",\n    \"   sort alphabetically by title. Every listing entry must link\",\n    \"   to the child page.\",\n    \"\",\n    \"3. **No body `# Heading`.** Starlight renders the frontmatter\",\n    \"   `title:` as the page H1 automatically — a body H1 produces a\",\n    \"   duplicate. The same no-body-H1 contract that applies to skill\",\n    \"   templates and inline agent templates also applies to every\",\n    \"   index page emitted by an agent.\",\n    \"\",\n    \"### When this applies\",\n    \"\",\n    \"The convention applies to every `index.md` / `README.md` file\",\n    \"covered by the shared-index path globs listed above:\",\n    \"\",\n    \"- `docs/src/content/docs/**/index.md`\",\n    \"- `docs/src/content/docs/**/README.md`\",\n    \"\",\n    \"Any agent that scaffolds a new directory under a Starlight\",\n    \"content root MUST populate the directory's index page following\",\n    \"this contract — a one-sentence stub is not acceptable.\",\n    \"\",\n    \"### Reference shapes\",\n    \"\",\n    \"Existing rich indexes are the canonical reference shape. Examples:\",\n    \"\",\n    \"- A `<MEETINGS_ROOT>/<YYYY-MM-DD>-<slug>/index.md` populated by\",\n    \"  the `agenda-analyst` bundle: frontmatter `title` /\",\n    \"  `description`, a 2–4 sentence summary, and a `## Documents`\",\n    \"  section listing every page in the folder.\",\n    \"- A regulations scope index that opens with two paragraphs of\",\n    \"  context and groups every linked regulation under a\",\n    \"  `## Regulations` table by jurisdiction.\",\n    \"- A standards-organizations index that groups every linked\",\n    \"  organization under a `## Organizations` heading by role\",\n    \"  (governance, working group, implementer).\",\n    \"\",\n    \"### Out of scope\",\n    \"\",\n    \"- Auto-generated child listings via Astro/Starlight components.\",\n    \"  Agents emit hand-curated tables or bullet lists; the rule\",\n    \"  defines the shape, not the rendering technology.\",\n    \"- Backfilling pre-existing stub indexes is a downstream-consumer\",\n    \"  cleanup task, not a configulator change.\",\n  );\n\n  return lines.join(\"\\n\");\n}\n\n/**\n * Render the short shared-editing hook section injected into a\n * phased-agent bundle's workflow rule (company-profile,\n * people-profile, software-profile, etc.). The section cites the\n * full contract documented in the base bundle's\n * `shared-editing-safety` rule so individual bundles stay DRY.\n *\n * When the convention is disabled, the function returns an empty\n * string so callers can no-op their append path.\n */\nexport function renderSharedEditingBundleHook(\n  se: ResolvedSharedEditing,\n  bundleLabel: string,\n): string {\n  if (!se.enabled) {\n    return \"\";\n  }\n\n  return [\n    \"## Shared Index Editing\",\n    \"\",\n    `Every ${bundleLabel} run that adds a row to a shared registry`,\n    \"or feature-matrix file follows the shared-editing contract: pull\",\n    \"the latest default branch before editing, insert exactly one row\",\n    \"in deterministic sort position, commit the index edit in its own\",\n    \"focused commit, and verify the row is present in the commit\",\n    \"before pushing. **Defer the index commit to the final pre-push\",\n    \"step** — land every content commit first, then rebase against\",\n    \"the remote default branch, re-read the index, re-compute the\",\n    \"insert position, write the row, commit the index on its own,\",\n    \"and push immediately. See the `shared-editing-safety` rule for\",\n    \"the full protocol, the list of files covered, the\",\n    \"defer-to-final-commit sequence, and the merge-conflict\",\n    \"resolution recipe.\",\n  ].join(\"\\n\");\n}\n\n/**\n * Render the `.claude/procedures/verify-index-row.sh` helper script.\n * Exported so `AgentConfig` can register it as an `AgentProcedure`\n * when the consumer opts in via `emitHelper: true`.\n *\n * The script takes two positional arguments:\n *\n * 1. `<index-path>` — repo-relative path to the shared index file.\n * 2. `<row-unique-marker>` — substring unique to the new row.\n *\n * It exits non-zero on any of the following:\n *\n * - Wrong argument count.\n * - Index file is not present in `HEAD` (i.e. not staged).\n * - The unique-marker substring appears zero times (row missing)\n *   or more than once (duplicate row from a mis-merged conflict).\n */\nexport function renderSharedEditingHelperScript(\n  _se: ResolvedSharedEditing,\n): string {\n  return [\n    \"#!/usr/bin/env bash\",\n    \"# verify-index-row.sh — Verify a shared-index row landed in HEAD.\",\n    \"#\",\n    \"# Usage:\",\n    \"#   .claude/procedures/verify-index-row.sh <index-path> <row-unique-marker>\",\n    \"#\",\n    \"# Exits 0 when <index-path> is in the last commit and\",\n    \"# <row-unique-marker> appears exactly once in the committed file.\",\n    \"# Exits non-zero with a clear diagnostic on stderr on any failure.\",\n    \"#\",\n    \"# This helper implements the commit-path verification step\",\n    \"# documented by the shared-editing-safety rule.\",\n    \"\",\n    \"set -uo pipefail\",\n    \"\",\n    \"err() {\",\n    '  printf \"verify-index-row.sh: %s\\\\n\" \"$*\" >&2',\n    \"}\",\n    \"\",\n    \"if [[ $# -ne 2 ]]; then\",\n    '  err \"expected 2 arguments, got $#\"',\n    '  err \"usage: verify-index-row.sh <index-path> <row-unique-marker>\"',\n    \"  exit 2\",\n    \"fi\",\n    \"\",\n    'index_path=\"$1\"',\n    'marker=\"$2\"',\n    \"\",\n    'if [[ -z \"${index_path// /}\" ]]; then',\n    '  err \"index path must be non-empty\"',\n    \"  exit 2\",\n    \"fi\",\n    \"\",\n    'if [[ -z \"${marker// /}\" ]]; then',\n    '  err \"row unique marker must be non-empty\"',\n    \"  exit 2\",\n    \"fi\",\n    \"\",\n    \"# 1. Confirm the index file is in the last commit.\",\n    'if ! git show --name-only --pretty=format: HEAD 2>/dev/null | grep -Fxq \"$index_path\"; then',\n    \"  err \\\"index file '$index_path' not in last commit (staging bug?)\\\"\",\n    \"  exit 3\",\n    \"fi\",\n    \"\",\n    \"# 2. Confirm the marker appears exactly once in the committed file.\",\n    'committed=$(git show \"HEAD:$index_path\" 2>/dev/null) || {',\n    \"  err \\\"could not read '$index_path' from HEAD\\\"\",\n    \"  exit 4\",\n    \"}\",\n    \"\",\n    'count=$(printf \"%s\" \"$committed\" | grep -Fc \"$marker\" || true)',\n    \"\",\n    'if [[ \"$count\" -eq 0 ]]; then',\n    \"  err \\\"row marker '$marker' not present in '$index_path' (row missing)\\\"\",\n    \"  exit 5\",\n    'elif [[ \"$count\" -gt 1 ]]; then',\n    \"  err \\\"row marker '$marker' appears $count times in '$index_path' (duplicate from mis-merged conflict?)\\\"\",\n    \"  exit 6\",\n    \"fi\",\n    \"\",\n    \"exit 0\",\n  ].join(\"\\n\");\n}\n\n/*******************************************************************************\n *\n * Internal helpers\n *\n ******************************************************************************/\n\nfunction assertValidSharedIndexPaths(value: ReadonlyArray<string>): void {\n  if (!Array.isArray(value)) {\n    throw new Error(\n      `SharedEditingConfig.sharedIndexPaths must be an array; got ${JSON.stringify(\n        value,\n      )}`,\n    );\n  }\n  if (value.length === 0) {\n    throw new Error(\n      \"SharedEditingConfig.sharedIndexPaths must not be empty — supply at least one path pattern or omit the field to use the defaults\",\n    );\n  }\n  for (const entry of value) {\n    if (typeof entry !== \"string\" || entry.trim().length === 0) {\n      throw new Error(\n        `SharedEditingConfig.sharedIndexPaths entries must be non-empty strings; got ${JSON.stringify(\n          entry,\n        )}`,\n      );\n    }\n  }\n}\n\nfunction assertValidConflictStrategy(value: string): void {\n  if (\n    !SHARED_EDITING_CONFLICT_STRATEGY_VALUES.includes(\n      value as \"rebase\" | \"merge\",\n    )\n  ) {\n    throw new Error(\n      `SharedEditingConfig.conflictStrategy must be one of ${SHARED_EDITING_CONFLICT_STRATEGY_VALUES.join(\n        \", \",\n      )}; got ${JSON.stringify(value)}`,\n    );\n  }\n}\n","import { SkillEvalsConfig } from \"../agent-config-options\";\n\n/**\n * Default master switch for the skill-eval harness convention. When no\n * config is supplied, the convention ships **enabled** so every skill\n * that ships an `evals/evals.json` file has a documented schema,\n * runner entry-point, and product-context injection contract.\n *\n * @see SkillEvalsConfig\n */\nexport const DEFAULT_SKILL_EVALS_ENABLED = true;\n\n/**\n * Default root directory (relative to the repo root) that holds every\n * skill's SKILL.md. The harness contract says that any skill SKILL.md\n * under this root may ship an `evals/evals.json` file alongside it —\n * the runner discovers eval suites by walking\n * `<skillsRoot>/<skill-name>/evals/evals.json`.\n *\n * Defaults to `.claude/skills`, which matches the location every\n * configulator-managed project ships skills to on disk.\n *\n * @see SkillEvalsConfig\n */\nexport const DEFAULT_SKILL_EVALS_SKILLS_ROOT = \".claude/skills\";\n\n/**\n * Default path to the product-context fixture consumed by every eval\n * suite. Configulator ships with a `docs/src/content/docs/project-context.md`\n * file that every agent already loads at session start; the eval harness\n * re-uses that file so eval prompts are parameterised by the consuming\n * project's domain vocabulary, in-scope capabilities, and stakeholders\n * without the evals needing per-project forks.\n *\n * @see SkillEvalsConfig\n */\nexport const DEFAULT_PRODUCT_CONTEXT_PATH =\n  \"docs/src/content/docs/project-context.md\";\n\n/**\n * Default policy for whether the harness should **require** a\n * product-context file to be present before running the suite.\n *\n * `true` (default) — the runner fails fast when the file is missing,\n * because an eval that silently runs without its product-context\n * fixture is a false-positive waiting to happen.\n *\n * `false` — the runner emits a warning to stderr but still runs the\n * suite. Useful for bootstrapping a new consuming repo that has not\n * yet authored its `project-context.md`.\n *\n * @see SkillEvalsConfig\n */\nexport const DEFAULT_REQUIRE_PRODUCT_CONTEXT = true;\n\n/**\n * Default for whether the convention emits the\n * `.claude/procedures/run-skill-evals.sh` helper to disk. The helper\n * is opt-in because many consumers run evals from CI or ad-hoc from\n * their own scripts rather than through the bundled harness; consumers\n * who want a ready-to-invoke runner flip this to `true`.\n *\n * @see SkillEvalsConfig\n */\nexport const DEFAULT_SKILL_EVALS_EMIT_RUNNER = false;\n\n/**\n * Fully-resolved skill-evals settings. Every field is defaulted so\n * downstream renderers can reason about a single canonical shape.\n */\nexport interface ResolvedSkillEvals {\n  readonly enabled: boolean;\n  readonly skillsRoot: string;\n  readonly productContextPath: string;\n  readonly requireProductContext: boolean;\n  readonly emitRunner: boolean;\n}\n\n/**\n * Resolve a (possibly absent) `SkillEvalsConfig` into a canonical\n * `ResolvedSkillEvals` with every field filled in. Unset fields\n * cascade from their documented defaults.\n *\n * Malformed configs — empty / whitespace-only or absolute `skillsRoot`,\n * empty / whitespace-only or absolute `productContextPath` — throw a\n * descriptive `Error`.\n */\nexport function resolveSkillEvals(\n  config?: SkillEvalsConfig,\n): ResolvedSkillEvals {\n  const skillsRoot = config?.skillsRoot ?? DEFAULT_SKILL_EVALS_SKILLS_ROOT;\n  assertValidSkillsRoot(skillsRoot);\n\n  const productContextPath =\n    config?.productContextPath ?? DEFAULT_PRODUCT_CONTEXT_PATH;\n  assertValidProductContextPath(productContextPath);\n\n  return {\n    enabled: config?.enabled ?? DEFAULT_SKILL_EVALS_ENABLED,\n    skillsRoot,\n    productContextPath,\n    requireProductContext:\n      config?.requireProductContext ?? DEFAULT_REQUIRE_PRODUCT_CONTEXT,\n    emitRunner: config?.emitRunner ?? DEFAULT_SKILL_EVALS_EMIT_RUNNER,\n  };\n}\n\n/**\n * Synth-time validation hook. Throws a descriptive `Error` when the\n * supplied `SkillEvalsConfig` is malformed. Called by\n * `AgentConfig.preSynthesize` before any rendering so a misconfigured\n * convention fails the build instead of silently shipping a broken\n * eval harness. Returns the resolved config unchanged so callers can\n * write `const se = validateSkillEvalsConfig(config)` in one line.\n *\n * Malformed cases rejected here:\n *\n * - `skillsRoot` empty, whitespace-only, or absolute.\n * - `productContextPath` empty, whitespace-only, or absolute.\n */\nexport function validateSkillEvalsConfig(\n  config?: SkillEvalsConfig,\n): ResolvedSkillEvals {\n  return resolveSkillEvals(config);\n}\n\n/**\n * Render the full body for the `skill-evals` rule shipped by the\n * `base` bundle. The rule documents:\n *\n * - The on-disk contract (where `evals/evals.json` lives).\n * - The JSON schema every eval file follows.\n * - The product-context injection protocol (how evals reference and\n *   interpolate the repo's `project-context.md` without forking).\n * - The runner entry-point (`run-skill-evals.sh` when opted in, or\n *   the inline `jq`-driven recipe when not).\n *\n * When the convention is disabled, the rule renders a short stub that\n * tells agents the project does not ship skill evals and that skill\n * changes ride on review alone.\n */\nexport function renderSkillEvalsRuleContent(se: ResolvedSkillEvals): string {\n  if (!se.enabled) {\n    return [\n      \"# Skill Evals\",\n      \"\",\n      \"**Skill evals are disabled in this project.** Skills do not\",\n      \"ship `evals/evals.json` regression suites, and changes to skill\",\n      \"prompts are caught only via review and downstream user-visible\",\n      \"failures. There is no harness contract; the runner script and\",\n      \"per-skill hooks are not rendered.\",\n      \"\",\n      \"Enable the convention via\",\n      \"`AgentConfigOptions.skillEvals.enabled = true`.\",\n    ].join(\"\\n\");\n  }\n\n  const lines: Array<string> = [\n    \"# Skill Evals\",\n    \"\",\n    \"Every skill that ships under `\" + se.skillsRoot + \"/<skill-name>/` may\",\n    \"carry a regression-test suite in an adjacent\",\n    \"`evals/evals.json` file. Suites are declarative prompt/expected-output\",\n    \"fixtures parameterised by a shared **product-context** fixture so the\",\n    \"same eval shape works across every project that depends on\",\n    \"configulator — each consuming repo supplies its own\",\n    \"`project-context.md`, not its own forked eval files.\",\n    \"\",\n    \"Without this harness, behavioural regressions in a skill prompt are\",\n    \"caught only when a downstream workflow breaks. Evals promote the\",\n    \"regression check to pull-request time: a reviewer (or CI) can\",\n    \"replay a known prompt against the updated skill and confirm the\",\n    \"output still matches the expected shape.\",\n    \"\",\n    \"## On-Disk Contract\",\n    \"\",\n    \"```\",\n    \"\" + se.skillsRoot + \"/\",\n    \"  <skill-name>/\",\n    \"    SKILL.md         # skill prompt (already shipped)\",\n    \"    evals/\",\n    \"      evals.json     # regression suite for this skill\",\n    \"```\",\n    \"\",\n    \"The runner walks `\" + se.skillsRoot + \"` and picks up any directory\",\n    \"containing both a `SKILL.md` and an `evals/evals.json` file. Skills\",\n    \"without an `evals/` subdirectory are silently skipped — evals are\",\n    \"always opt-in per skill, never required.\",\n    \"\",\n    \"## Eval File Schema (JSON)\",\n    \"\",\n    \"```json\",\n    \"{\",\n    '  \"skill_name\": \"<matches parent directory name>\",',\n    '  \"product_context\": \"<path to product-context fixture, optional>\",',\n    '  \"evals\": [',\n    \"    {\",\n    '      \"id\": 1,',\n    '      \"prompt\": \"<user prompt sent to the skill>\",',\n    '      \"expected_output\": \"<prose description of the acceptable output shape>\",',\n    '      \"files\": [],',\n    '      \"product_context_refs\": [\"<domain-vocabulary term the prompt relies on>\"]',\n    \"    }\",\n    \"  ]\",\n    \"}\",\n    \"```\",\n    \"\",\n    \"**Required fields:** `skill_name`, `evals`. Each `evals[]` entry\",\n    \"requires `id`, `prompt`, and `expected_output`.\",\n    \"\",\n    \"**`skill_name`** must match the parent directory name exactly — the\",\n    \"runner asserts the two agree and fails the suite on mismatch.\",\n    \"\",\n    \"**`product_context`** is optional and defaults to the project's\",\n    \"configured `productContextPath` (`\" +\n      se.productContextPath +\n      \"`). Override it\",\n    \"per-suite only when a specific skill needs a different fixture;\",\n    \"the overwhelmingly common case is to omit the field and rely on\",\n    \"the default.\",\n    \"\",\n    \"**`evals[].expected_output`** is prose, not a strict matcher. The\",\n    \"runner surfaces both the prompt and this description to the human\",\n    \"or model evaluating the suite — matching is a judgement call on\",\n    \"whether the skill produced the described shape, not a byte-for-byte\",\n    \"equality check. This keeps evals robust to acceptable prompt-\",\n    \"output variance while still catching structural regressions.\",\n    \"\",\n    \"**`evals[].files`** lists additional fixture files the prompt\",\n    \"references (meeting transcripts, existing requirement documents,\",\n    \"etc.). Paths are relative to the repo root. The default is an\",\n    \"empty array.\",\n    \"\",\n    \"**`evals[].product_context_refs`** (optional) lists the domain-\",\n    \"vocabulary terms or sections of the product-context fixture the\",\n    \"prompt depends on. The runner reports these alongside the prompt\",\n    \"so an evaluator can quickly confirm the fixture still carries the\",\n    \"referenced concepts after a `project-context.md` edit.\",\n    \"\",\n    \"## Product-Context Injection\",\n    \"\",\n    \"Every eval suite runs against the repository's\",\n    \"`\" + se.productContextPath + \"` fixture, which is the same document every\",\n    \"agent already loads at session start to frame judgement calls. The\",\n    \"harness does **not** fork or duplicate this file — it references\",\n    \"the canonical path so a single edit to `project-context.md`\",\n    \"propagates to every eval suite.\",\n    \"\",\n  ];\n\n  if (se.requireProductContext) {\n    lines.push(\n      \"The runner **requires** `\" + se.productContextPath + \"` to exist. A\",\n      \"missing file fails the suite before any eval runs, because an\",\n      \"eval that silently ran without its fixture would produce a\",\n      \"false-positive pass.\",\n      \"\",\n    );\n  } else {\n    lines.push(\n      \"The runner does **not** require `\" + se.productContextPath + \"` to\",\n      \"exist. A missing file emits a warning to stderr but the suite\",\n      \"continues — useful for bootstrapping a repo that has not yet\",\n      \"authored its product-context fixture.\",\n      \"\",\n    );\n  }\n\n  lines.push(\n    \"When authoring a new eval, always cite the specific terms from\",\n    \"`project-context.md` the prompt leans on via the optional\",\n    \"`product_context_refs` array. An eval that does not declare its\",\n    \"refs silently drifts out of sync with the fixture; a declaring\",\n    \"eval can be grep-checked after any `project-context.md` edit.\",\n    \"\",\n    \"## Runner Contract\",\n    \"\",\n    \"Every eval runner — whether the bundled helper, a CI workflow, or\",\n    \"a hand-rolled script — follows the same contract:\",\n    \"\",\n    \"1. **Discover.** Walk `\" + se.skillsRoot + \"` and collect every\",\n    \"   `<skill>/evals/evals.json` file.\",\n    \"2. **Validate.** Parse each file as JSON, assert `skill_name`\",\n    \"   matches the parent directory, assert every `evals[]` entry has\",\n    \"   `id`, `prompt`, and `expected_output`.\",\n    \"3. **Load the product-context.** Read the per-suite\",\n    \"   `product_context` path (or fall back to the project default\",\n    \"   `\" + se.productContextPath + \"`).\",\n  );\n\n  if (se.requireProductContext) {\n    lines.push(\"   Fail the suite when the file is missing.\");\n  } else {\n    lines.push(\"   Warn on stderr but continue when the file is missing.\");\n  }\n\n  lines.push(\n    \"4. **Emit a plan.** Print a JSON execution plan to stdout — one\",\n    \"   entry per `(skill, eval)` pair with the prompt, expected\",\n    \"   output, resolved product-context path, and list of\",\n    \"   `product_context_refs`. The plan is consumed by whatever human\",\n    \"   or model actually runs the prompts against the skill; the\",\n    \"   harness itself never invokes an LLM.\",\n    \"5. **Exit non-zero on any validation failure.** Schema violations,\",\n    \"   `skill_name` / directory mismatch, malformed JSON, and (when\",\n    \"   required) missing product-context all fail the suite.\",\n    \"\",\n    \"Keeping the harness declarative means every configulator consumer\",\n    \"runs the same contract whether the actual LLM dispatch happens in\",\n    \"CI via the Anthropic SDK, in a hosted eval platform, or from an\",\n    \"interactive `claude-code` session replaying prompts by hand. The\",\n    \"harness is a schema validator and discovery layer — not an LLM\",\n    \"runtime.\",\n    \"\",\n  );\n\n  if (se.emitRunner) {\n    lines.push(\n      \"## Bundled Runner\",\n      \"\",\n      \"The `.claude/procedures/run-skill-evals.sh` helper implements\",\n      \"the full runner contract in one invocation:\",\n      \"\",\n      \"```bash\",\n      \".claude/procedures/run-skill-evals.sh                 # run every suite\",\n      \".claude/procedures/run-skill-evals.sh <skill-name>    # run one suite\",\n      \"```\",\n      \"\",\n      \"The helper depends on `jq` (for JSON parsing) and writes the\",\n      \"execution plan to stdout. It exits non-zero with a descriptive\",\n      \"diagnostic on any validation failure, so it plugs directly into\",\n      \"pre-push hooks and CI jobs without further glue.\",\n      \"\",\n    );\n  } else {\n    lines.push(\n      \"## Inline Runner Recipe\",\n      \"\",\n      \"Projects that prefer to roll their own runner can implement the\",\n      \"contract with `jq` and `find`:\",\n      \"\",\n      \"```bash\",\n      \"find \" + se.skillsRoot + \" -path '*/evals/evals.json' -print0 \\\\\",\n      \"  | while IFS= read -r -d '' eval_file; do\",\n      '      jq -e \".skill_name, .evals[0].id, .evals[0].prompt, .evals[0].expected_output\" \"$eval_file\" > /dev/null \\\\',\n      '        || { echo \"ERROR: malformed $eval_file\"; exit 1; }',\n      \"    done\",\n      \"```\",\n      \"\",\n      \"Flip `skillEvals.emitRunner = true` in `AgentConfigOptions` to\",\n      \"have configulator write `.claude/procedures/run-skill-evals.sh`\",\n      \"into the repo automatically.\",\n      \"\",\n    );\n  }\n\n  lines.push(\n    \"## Authoring Guidelines\",\n    \"\",\n    \"1. **Ship evals with the skill change.** When you update a\",\n    \"   SKILL.md prompt in a way that could change output shape, add\",\n    \"   or update at least one eval in the same commit so the\",\n    \"   regression is caught on the next suite run.\",\n    \"2. **Keep prompts realistic.** An eval prompt should look like\",\n    \"   something a user would actually type or paste into the skill,\",\n    \"   not a synthetic stress test.\",\n    \"3. **Describe, do not assert.** Write `expected_output` as prose\",\n    \"   that a human or model can use to judge the actual output,\",\n    \"   not a regex or exact string. Byte-for-byte matching is too\",\n    \"   brittle for skill evals.\",\n    \"4. **Cover the representative branches.** Two or three evals per\",\n    \"   skill is usually enough — one happy path, one branch that\",\n    \"   defers a decision (if the skill has a decision-authority\",\n    \"   rule), and one that draws on product-context vocabulary.\",\n    \"5. **Declare product-context refs.** Any term the prompt leans on\",\n    \"   from `project-context.md` belongs in `product_context_refs`.\",\n    \"   A grep-able ref list is the only sustainable way to catch\",\n    \"   evals that drift out of sync with the fixture.\",\n  );\n\n  return lines.join(\"\\n\");\n}\n\n/**\n * Render the short skill-evals hook section injected into a skill's\n * owning bundle rule (requirements-writer, bcm-writer, etc.). The\n * section cites the full contract documented in the base bundle's\n * `skill-evals` rule so individual bundles stay DRY.\n *\n * When the convention is disabled, the function returns an empty\n * string so callers can no-op their append path.\n */\nexport function renderSkillEvalsBundleHook(\n  se: ResolvedSkillEvals,\n  skillLabel: string,\n): string {\n  if (!se.enabled) {\n    return \"\";\n  }\n\n  return [\n    \"## Skill Evals\",\n    \"\",\n    `The ${skillLabel} skill ships a regression suite at`,\n    `\\`${se.skillsRoot}/${skillLabel}/evals/evals.json\\` when one exists.`,\n    \"When updating the skill prompt in a way that could change output\",\n    \"shape, add or update at least one eval in the same commit. The\",\n    \"harness is parameterised by the repository's\",\n    `\\`${se.productContextPath}\\` fixture — prompts that lean on domain`,\n    \"vocabulary declare the referenced terms via\",\n    \"`product_context_refs` so the suite can be cross-checked after any\",\n    \"edit to the product-context file. See the `skill-evals` rule for\",\n    \"the full JSON schema, runner contract, and authoring guidelines.\",\n  ].join(\"\\n\");\n}\n\n/**\n * Render the `.claude/procedures/run-skill-evals.sh` helper script.\n * Exported so `AgentConfig` can register it as an `AgentProcedure`\n * when the consumer opts in via `emitRunner: true`.\n *\n * The script takes zero or one positional arguments:\n *\n * 1. `[<skill-name>]` — optional, restricts the run to one skill.\n *\n * It exits non-zero on any of the following:\n *\n * - `jq` is not available on `PATH`.\n * - A discovered `evals.json` is malformed or missing required fields.\n * - `skill_name` inside the file does not match the parent directory.\n * - The product-context fixture is missing and `requireProductContext`\n *   is `true` in the resolved config.\n */\nexport function renderSkillEvalsRunnerScript(se: ResolvedSkillEvals): string {\n  const requireProductContextLiteral = se.requireProductContext\n    ? \"true\"\n    : \"false\";\n\n  return [\n    \"#!/usr/bin/env bash\",\n    \"# run-skill-evals.sh — Discover and validate skill eval suites.\",\n    \"#\",\n    \"# Usage:\",\n    \"#   .claude/procedures/run-skill-evals.sh            # run every suite\",\n    \"#   .claude/procedures/run-skill-evals.sh <skill>    # run one suite\",\n    \"#\",\n    \"# Walks the skills root, discovers `<skill>/evals/evals.json`\",\n    \"# files, validates the JSON against the skill-evals schema, asserts\",\n    \"# the product-context fixture is reachable, and prints a JSON\",\n    \"# execution plan to stdout. The plan is consumed by whatever human\",\n    \"# or model actually replays the prompts against the skill — this\",\n    \"# helper does not invoke an LLM.\",\n    \"#\",\n    \"# This helper implements the runner contract documented by the\",\n    \"# skill-evals rule.\",\n    \"\",\n    \"set -uo pipefail\",\n    \"\",\n    'SKILLS_ROOT=\"' + se.skillsRoot + '\"',\n    'PRODUCT_CONTEXT_PATH=\"' + se.productContextPath + '\"',\n    'REQUIRE_PRODUCT_CONTEXT=\"' + requireProductContextLiteral + '\"',\n    \"\",\n    \"err() {\",\n    '  printf \"run-skill-evals.sh: %s\\\\n\" \"$*\" >&2',\n    \"}\",\n    \"\",\n    \"if ! command -v jq >/dev/null 2>&1; then\",\n    '  err \"jq is required on PATH\"',\n    \"  exit 2\",\n    \"fi\",\n    \"\",\n    'target_skill=\"${1:-}\"',\n    \"\",\n    \"# Resolve the product-context file. When it is missing and the\",\n    \"# convention requires it, fail the suite. When the convention\",\n    \"# permits it to be absent, warn and continue.\",\n    'if [[ ! -f \"$PRODUCT_CONTEXT_PATH\" ]]; then',\n    '  if [[ \"$REQUIRE_PRODUCT_CONTEXT\" == \"true\" ]]; then',\n    '    err \"product-context fixture not found at $PRODUCT_CONTEXT_PATH\"',\n    \"    exit 3\",\n    \"  else\",\n    '    err \"warning: product-context fixture not found at $PRODUCT_CONTEXT_PATH (continuing)\"',\n    \"  fi\",\n    \"fi\",\n    \"\",\n    \"# Collect every eval suite on disk. The find pattern matches both\",\n    \"# `evals/evals.json` and `evals.json` in case a skill author inlines\",\n    \"# the file without the subdirectory (supported but not recommended).\",\n    \"suites=()\",\n    'while IFS= read -r -d \"\" f; do',\n    '  suites+=(\"$f\")',\n    'done < <(find \"$SKILLS_ROOT\" -type f \\\\( -path \"*/evals/evals.json\" -o -path \"*/evals.json\" \\\\) -print0 2>/dev/null)',\n    \"\",\n    \"if [[ ${#suites[@]} -eq 0 ]]; then\",\n    '  err \"no eval suites found under $SKILLS_ROOT\"',\n    \"  exit 0\",\n    \"fi\",\n    \"\",\n    \"failed=0\",\n    \"plan_entries=()\",\n    \"\",\n    'for eval_file in \"${suites[@]}\"; do',\n    '  skill_dir=\"$(dirname \"$(dirname \"$eval_file\")\")\"',\n    '  skill_name_from_dir=\"$(basename \"$skill_dir\")\"',\n    \"\",\n    \"  # Skip when the caller asked for a specific skill and this is not it.\",\n    '  if [[ -n \"$target_skill\" && \"$target_skill\" != \"$skill_name_from_dir\" ]]; then',\n    \"    continue\",\n    \"  fi\",\n    \"\",\n    '  if ! declared_name=$(jq -re \".skill_name\" \"$eval_file\" 2>/dev/null); then',\n    '    err \"malformed eval file: $eval_file (missing skill_name)\"',\n    \"    failed=$((failed + 1))\",\n    \"    continue\",\n    \"  fi\",\n    \"\",\n    '  if [[ \"$declared_name\" != \"$skill_name_from_dir\" ]]; then',\n    \"    err \\\"$eval_file: skill_name '$declared_name' does not match directory '$skill_name_from_dir'\\\"\",\n    \"    failed=$((failed + 1))\",\n    \"    continue\",\n    \"  fi\",\n    \"\",\n    \"  # Validate every eval entry has id, prompt, and expected_output.\",\n    '  if ! jq -e \\'.evals | type == \"array\" and length > 0 and all(.[]; has(\"id\") and has(\"prompt\") and has(\"expected_output\"))\\' \"$eval_file\" > /dev/null 2>&1; then',\n    '    err \"$eval_file: evals array is missing or entries are missing required fields\"',\n    \"    failed=$((failed + 1))\",\n    \"    continue\",\n    \"  fi\",\n    \"\",\n    \"  # Compute the resolved product-context path (per-suite override\",\n    \"  # wins over the project default).\",\n    '  suite_context=$(jq -r \".product_context // empty\" \"$eval_file\")',\n    '  if [[ -z \"$suite_context\" ]]; then',\n    '    suite_context=\"$PRODUCT_CONTEXT_PATH\"',\n    \"  fi\",\n    \"\",\n    '  plan_entries+=(\"$(jq -n \\\\',\n    '    --arg skill \"$skill_name_from_dir\" \\\\',\n    '    --arg file \"$eval_file\" \\\\',\n    '    --arg ctx \"$suite_context\" \\\\',\n    '    --slurpfile body \"$eval_file\" \\\\',\n    \"    '{skill: $skill, file: $file, product_context: $ctx, evals: $body[0].evals}')\\\")\",\n    \"done\",\n    \"\",\n    \"if [[ $failed -gt 0 ]]; then\",\n    '  err \"$failed eval suite(s) failed validation\"',\n    \"  exit 4\",\n    \"fi\",\n    \"\",\n    \"if [[ ${#plan_entries[@]} -eq 0 ]]; then\",\n    '  err \"no matching eval suites\"',\n    \"  exit 0\",\n    \"fi\",\n    \"\",\n    \"# Emit the execution plan as a single JSON array on stdout.\",\n    'printf \"%s\\\\n\" \"${plan_entries[@]}\" | jq -s \\'.\\'',\n    \"\",\n    \"exit 0\",\n  ].join(\"\\n\");\n}\n\n/*******************************************************************************\n *\n * Internal helpers\n *\n ******************************************************************************/\n\nfunction assertValidSkillsRoot(value: string): void {\n  if (typeof value !== \"string\" || value.trim().length === 0) {\n    throw new Error(\n      `SkillEvalsConfig.skillsRoot must be a non-empty string; got ${JSON.stringify(\n        value,\n      )}`,\n    );\n  }\n  if (value.startsWith(\"/\")) {\n    throw new Error(\n      `SkillEvalsConfig.skillsRoot must be a repo-relative path (no leading '/'); got ${JSON.stringify(\n        value,\n      )}`,\n    );\n  }\n}\n\nfunction assertValidProductContextPath(value: string): void {\n  if (typeof value !== \"string\" || value.trim().length === 0) {\n    throw new Error(\n      `SkillEvalsConfig.productContextPath must be a non-empty string; got ${JSON.stringify(\n        value,\n      )}`,\n    );\n  }\n  if (value.startsWith(\"/\")) {\n    throw new Error(\n      `SkillEvalsConfig.productContextPath must be a repo-relative path (no leading '/'); got ${JSON.stringify(\n        value,\n      )}`,\n    );\n  }\n}\n","import { TemporalFramingConfig } from \"../agent-config-options\";\n\n/**\n * Default master switch for the temporal-framing convention. When no\n * config is supplied the convention ships **enabled** so every\n * configulator-consuming repo's analyst agents apply the\n * \"as of [date]\" qualifier rule.\n *\n * @see TemporalFramingConfig\n */\nexport const DEFAULT_TEMPORAL_FRAMING_ENABLED = true;\n\n/**\n * Default path globs the rule applies to — every Markdown file under\n * the profile / research subtrees of a repo's Starlight docs site.\n * Consumers may override the list when their content layout differs.\n *\n * Out-of-scope locations (meeting notes, requirements, the\n * project-context page) are excluded by design: their own dating\n * conventions (file-name date prefix, version frontmatter, living\n * snapshot under direct human review) already anchor the temporal\n * meaning of their content.\n *\n * @see TemporalFramingConfig\n */\nexport const DEFAULT_TEMPORAL_FRAMING_PATHS: ReadonlyArray<string> = [\n  \"docs/src/content/docs/profiles/**/*.md\",\n  \"docs/src/content/docs/industry-research/**/*.md\",\n  \"docs/src/content/docs/software-research/**/*.md\",\n  \"docs/src/content/docs/regulatory-research/**/*.md\",\n  \"docs/src/content/docs/standards-research/**/*.md\",\n  \"docs/src/content/docs/customer-research/**/*.md\",\n];\n\n/**\n * The five canonical time-sensitive claim categories surfaced by the\n * May 2026 sampled drift audit. The category names are shipped as the\n * key set for `TemporalFramingConfig.cadences` so consumers can dial\n * the per-category refresh cadence without inventing their own\n * category names.\n */\nexport const TEMPORAL_FRAMING_CATEGORY_VALUES = [\n  \"ownership\",\n  \"company-leadership\",\n  \"regulatory-status\",\n  \"litigation\",\n  \"dated-metrics\",\n] as const;\n\nexport type TemporalFramingCategory =\n  (typeof TEMPORAL_FRAMING_CATEGORY_VALUES)[number];\n\n/**\n * Default per-category refresh cadences (in days). Fast-decay claims\n * (regulatory status, litigation) carry a 30-day cadence because a\n * single press release can invalidate them between scheduled refresh\n * passes. Slow-decay claims (ownership, dated metrics from press\n * releases or filings) carry a 180-day cadence — material changes\n * still happen but rarely outpace a half-yearly refresh. Leadership\n * tenure sits in the middle at 90 days.\n *\n * Consumers may override any subset of categories via\n * `TemporalFramingConfig.cadences`; unspecified entries fall through\n * to these defaults.\n */\nexport const DEFAULT_TEMPORAL_FRAMING_CADENCES: {\n  readonly [K in TemporalFramingCategory]: number;\n} = {\n  ownership: 180,\n  \"company-leadership\": 90,\n  \"regulatory-status\": 30,\n  litigation: 30,\n  \"dated-metrics\": 180,\n};\n\n/**\n * Default for whether the convention emits the\n * `.claude/procedures/check-temporal-framing.sh` lint script to disk.\n * Disabled by default — consumers opt in when they want a hard\n * pre-commit or CI gate. The rule body itself ships unconditionally\n * regardless of the lint script.\n *\n * @see TemporalFramingConfig\n */\nexport const DEFAULT_TEMPORAL_FRAMING_EMIT_CHECKER = false;\n\n/**\n * Fully-resolved temporal-framing settings. Every field is defaulted\n * so downstream renderers can reason about a single canonical shape.\n */\nexport interface ResolvedTemporalFraming {\n  readonly enabled: boolean;\n  readonly paths: ReadonlyArray<string>;\n  readonly cadences: { readonly [K in TemporalFramingCategory]: number };\n  readonly emitChecker: boolean;\n}\n\n/**\n * Resolve a (possibly absent) `TemporalFramingConfig` into a canonical\n * `ResolvedTemporalFraming` with every field filled in. Unset fields\n * cascade from their documented defaults.\n *\n * Malformed configs throw a descriptive `Error`:\n *\n * - `paths` containing empty / whitespace-only entries.\n * - `cadences` containing non-integer or non-positive values.\n */\nexport function resolveTemporalFraming(\n  config?: TemporalFramingConfig,\n): ResolvedTemporalFraming {\n  const paths = config?.paths ?? DEFAULT_TEMPORAL_FRAMING_PATHS;\n  assertValidPaths(paths);\n\n  const cadences = resolveCadences(config?.cadences);\n\n  return {\n    enabled: config?.enabled ?? DEFAULT_TEMPORAL_FRAMING_ENABLED,\n    paths,\n    cadences,\n    emitChecker: config?.emitChecker ?? DEFAULT_TEMPORAL_FRAMING_EMIT_CHECKER,\n  };\n}\n\n/**\n * Synth-time validation hook. Throws a descriptive `Error` when the\n * supplied `TemporalFramingConfig` is malformed. Called by\n * `AgentConfig.preSynthesize` before any rendering so a misconfigured\n * convention fails the build instead of silently shipping broken\n * paths or cadences. Returns the resolved config unchanged so callers\n * can write `const tf = validateTemporalFramingConfig(config)` in\n * one line.\n *\n * Malformed cases rejected here:\n *\n * - `paths` containing empty or whitespace-only entries.\n * - `cadences` containing non-integer or non-positive values.\n */\nexport function validateTemporalFramingConfig(\n  config?: TemporalFramingConfig,\n): ResolvedTemporalFraming {\n  return resolveTemporalFraming(config);\n}\n\n/**\n * Render the body for the `temporal-framing-convention` rule shipped\n * by the `base` bundle. The rule documents:\n *\n * - The \"as of [date]\" qualifier requirement on time-sensitive claims.\n * - The five canonical time-sensitive claim categories.\n * - Refresh-agent behaviour (grep for `as of `, re-verify against the\n *   category-specific cadence).\n * - The scope of applicability (profile / research sections only).\n *\n * When the convention is disabled, the rule renders a short stub that\n * tells agents the project does not enforce explicit temporal\n * qualifiers and that staleness is caught by review alone.\n */\nexport function renderTemporalFramingRuleContent(\n  tf: ResolvedTemporalFraming,\n): string {\n  if (!tf.enabled) {\n    return [\n      \"# Temporal Framing Convention\",\n      \"\",\n      \"**Temporal framing is not enforced in this project.** Agents are\",\n      \"not required to add `as of [date]` qualifiers to time-sensitive\",\n      \"claims, and refresh passes do not use a mechanical grep to find\",\n      \"stale framing. Staleness is caught by review and downstream user\",\n      \"reports alone.\",\n      \"\",\n      \"Enable the convention via\",\n      \"`AgentConfigOptions.temporalFraming.enabled = true`.\",\n    ].join(\"\\n\");\n  }\n\n  const lines: Array<string> = [\n    \"# Temporal Framing Convention\",\n    \"\",\n    \"Every factual claim that can change over time MUST carry an inline\",\n    \"`as of [YYYY-MM-DD]` or `as of [Month YYYY]` qualifier on the\",\n    \"**first** occurrence of the claim in the document. Once qualified\",\n    \"once, subsequent references to the same fact in the same document\",\n    \"do not need to repeat the qualifier — the first qualifier governs\",\n    \"the document's snapshot date for that fact.\",\n    \"\",\n    \"The qualifier is mechanical, not editorial. Refresh agents grep\",\n    \"for `as of ` to find the time-bounded claims; without the\",\n    \"qualifier, a refresh pass has no cheap way to tell stale framing\",\n    \"from stable facts.\",\n    \"\",\n    \"## What counts as time-sensitive\",\n    \"\",\n    \"A claim is time-sensitive (and must carry the qualifier) when it\",\n    \"describes a state that **a single public event could invalidate\",\n    \"within the document's expected refresh cadence**. Five recurring\",\n    \"categories cover the common cases:\",\n    \"\",\n    \"| Category | Examples |\",\n    \"|----------|----------|\",\n    '| **Ownership and investors** | \"co-owned by X, Y, Z\"; \"majority-owned by\"; \"minority stake held by\"; cap table; current investor lists |',\n    '| **Leadership tenure** | \"X is CEO\"; \"X chairs the committee\"; \"X serves as\"; current board chair; current executive team |',\n    '| **Regulatory or rule status** | \"is in force\"; \"under public consultation\"; \"pending finalization\"; \"currently enjoined\"; \"under active investigation\" |',\n    '| **Litigation and enforcement** | \"is under active scrutiny\"; \"investigation is ongoing\"; \"appeal is pending\"; \"consent decree remains in effect\" |',\n    '| **Pricing, valuation, and metrics** | \"valued at $XB\"; \"annual revenue ~$X\"; \"processes N transactions\"; \"serves N customers\" — when the figure is sourced from a dated press release or filing |',\n    \"\",\n    \"A claim is **not** time-sensitive (and does not need the qualifier)\",\n    \"when it describes a historical event, a statutory text, or a\",\n    \"structural fact that does not change without amendment. Examples\",\n    \"that are safe without a qualifier:\",\n    \"\",\n    '- \"Acquired by Advent International in May 2019\" (a dated historical event — the date itself is the anchor)',\n    '- \"21 CFR Part 11 establishes criteria for electronic records\" (statutory text)',\n    '- \"Headquartered in Dallas, Texas\" (changes only on a documented move)',\n    '- \"Founded in 1999\" (a one-time event)',\n    \"\",\n    \"## Format\",\n    \"\",\n    \"Two acceptable forms:\",\n    \"\",\n    \"```markdown\",\n    \"As of May 2026, Acme is owned by ...\",\n    \"... Acme's CEO (as of May 2026) is ...\",\n    \"```\",\n    \"\",\n    \"Use the granularity that matches the source citation:\",\n    \"\",\n    \"- `as of YYYY-MM-DD` when the source is a specific filing, press release, or court order with a precise date.\",\n    \"- `as of Month YYYY` when the source is a self-reported page (e.g., a company's `About` page) where only the month-of-snapshot is meaningful.\",\n    \"- Do **not** write `as of 2026` (year-only) — that's too coarse to drive a refresh decision.\",\n    \"\",\n    \"## Examples\",\n    \"\",\n    \"### Wrong — present-tense framing of a state that can change\",\n    \"\",\n    \"```markdown\",\n    \"Availity is co-owned by major Blue Cross Blue Shield plans\",\n    \"(HCSC, Elevance Health/Anthem, BCBS Minnesota), Francisco\",\n    \"Partners, Novo Holdings, and Prettybrook Partners.\",\n    \"```\",\n    \"\",\n    \"This claim might have been true at a specific date but goes stale\",\n    \"as soon as any one investor exits. A refresh agent has no\",\n    \"mechanical signal that the claim is time-sensitive.\",\n    \"\",\n    \"### Right — explicit qualifier on the first claim\",\n    \"\",\n    \"```markdown\",\n    \"As of May 2026, Availity is co-owned by a mix of health plan\",\n    \"strategic investors (HCSC, Elevance Health/Anthem, BCBS\",\n    \"Minnesota, Humana, GuideWell) and financial sponsors (Novo\",\n    \"Holdings, Prettybrook Partners).\",\n    \"```\",\n    \"\",\n    \"The `as of May 2026` anchors the document's snapshot for the\",\n    \"ownership claim. Subsequent references to Availity's ownership in\",\n    \"the same document inherit that snapshot date.\",\n    \"\",\n    \"## When the convention applies\",\n    \"\",\n    \"The rule applies to every Markdown document any agent writes under\",\n    \"the following path globs:\",\n    \"\",\n    ...tf.paths.map((p) => `- \\`${p}\\``),\n    \"\",\n    \"It does **not** apply to:\",\n    \"\",\n    \"- Meeting notes (`meetings/**`) — the meeting date itself is the implicit `as of` anchor.\",\n    \"- Requirement documents (`requirements/**`) — formal requirements are versioned and dated via their own frontmatter.\",\n    \"- The project context page (`project-context.md`) — maintained as a living snapshot under direct human review.\",\n    \"\",\n    \"## Refresh-agent behaviour\",\n    \"\",\n    \"A refresh pass on any covered document MUST:\",\n    \"\",\n    \"1. Grep for `as of ` (case-insensitive) in the document.\",\n    \"2. For each qualifier, compute `today - <qualifier-date>` in days.\",\n    \"3. Classify each qualified claim against the category-specific\",\n    \"   cadence table below.\",\n    \"4. Re-verify every claim whose qualifier is older than its cadence.\",\n    \"5. Update the qualifier to today's date on every re-verified claim\",\n    \"   that remains accurate.\",\n    \"6. Treat documents that omit qualifiers entirely as needing\",\n    \"   **back-fill** before any other verification is attempted — the\",\n    \"   absence of qualifiers is itself a refresh finding.\",\n    \"\",\n    \"### Refresh cadence table\",\n    \"\",\n    \"Each category carries its own refresh cadence in days. Faster-decay\",\n    \"claims (regulatory status, litigation) refresh more often;\",\n    \"slower-decay claims (ownership, dated metrics) refresh less often.\",\n    \"\",\n    \"| Category | Cadence (days) |\",\n    \"|----------|----------------|\",\n    `| \\`ownership\\` | ${tf.cadences.ownership} |`,\n    `| \\`company-leadership\\` | ${tf.cadences[\"company-leadership\"]} |`,\n    `| \\`regulatory-status\\` | ${tf.cadences[\"regulatory-status\"]} |`,\n    `| \\`litigation\\` | ${tf.cadences.litigation} |`,\n    `| \\`dated-metrics\\` | ${tf.cadences[\"dated-metrics\"]} |`,\n    \"\",\n    \"Consumers may override any subset of cadences via\",\n    \"`AgentConfigOptions.temporalFraming.cadences`. Unspecified\",\n    \"categories fall through to the defaults above.\",\n  ];\n\n  if (tf.emitChecker) {\n    lines.push(\n      \"\",\n      \"## Lint\",\n      \"\",\n      \"The bundled `.claude/procedures/check-temporal-framing.sh` helper\",\n      \"enforces the rule mechanically. Given a set of changed files (as\",\n      \"positional arguments or a newline-separated list on stdin), it\",\n      \"fails non-zero when any file matches a configured path glob and\",\n      \"carries time-sensitive framing without an `as of ` qualifier.\",\n      \"\",\n      \"```bash\",\n      \"# Pre-commit (staged files):\",\n      \"git diff --cached --name-only \\\\\",\n      \"  | .claude/procedures/check-temporal-framing.sh\",\n      \"\",\n      \"# CI (branch-vs-base):\",\n      \"git diff --name-only origin/main...HEAD \\\\\",\n      \"  | .claude/procedures/check-temporal-framing.sh\",\n      \"```\",\n      \"\",\n      \"The lint is a coarse signal — it flags files that look\",\n      \"time-sensitive but carry no qualifier. Authors and reviewers are\",\n      \"still expected to validate that each qualifier is correctly\",\n      \"anchored to its source citation.\",\n    );\n  }\n\n  lines.push(\n    \"\",\n    \"## Out of scope\",\n    \"\",\n    \"- Auto-generating qualifiers from source-citation dates. Authors\",\n    \"  read the source and write the qualifier explicitly.\",\n    \"- Replacing existing dated frontmatter conventions. Frontmatter\",\n    \"  `date:` fields anchor the document's overall snapshot; the\",\n    \"  inline qualifier anchors individual time-sensitive claims so a\",\n    \"  refresh pass can re-verify them without re-reading the whole\",\n    \"  document.\",\n    \"- Back-filling pre-existing documents in bulk. Refresh passes\",\n    \"  back-fill qualifiers on the documents they touch; bulk\",\n    \"  back-fill is a downstream consumer cleanup task, not a\",\n    \"  configulator change.\",\n  );\n\n  return lines.join(\"\\n\");\n}\n\n/**\n * Render the `.claude/procedures/check-temporal-framing.sh` helper\n * script. Exported so `AgentConfig` can register it when the consumer\n * opts in via `emitChecker: true`.\n *\n * The script accepts the list of changed files as either:\n *\n * 1. Positional arguments (one file per arg).\n * 2. Newline-separated entries on stdin (when no args supplied) —\n *    pipe `git diff --name-only` directly into it.\n *\n * It fails non-zero when any changed file matches a configured path\n * pattern and contains time-sensitive framing (present-tense forms of\n * the canonical category triggers) but lacks an `as of ` qualifier\n * anywhere in the file. The lint is intentionally coarse — file-level\n * not line-level — so the cost of running it on every PR stays low.\n */\nexport function renderTemporalFramingCheckerScript(\n  tf: ResolvedTemporalFraming,\n): string {\n  const patternsLiteral = tf.paths\n    .map((p) => `  ${JSON.stringify(p)}`)\n    .join(\"\\n\");\n\n  return [\n    \"#!/usr/bin/env bash\",\n    \"# check-temporal-framing.sh — Enforce the temporal-framing convention.\",\n    \"#\",\n    \"# Usage:\",\n    \"#   .claude/procedures/check-temporal-framing.sh <file>...\",\n    \"#   git diff --name-only HEAD | .claude/procedures/check-temporal-framing.sh\",\n    \"#\",\n    \"# Fails non-zero when any changed file matches a configured path\",\n    \"# pattern AND contains present-tense framing of a time-sensitive\",\n    \"# claim category AND does NOT carry an `as of ` qualifier anywhere\",\n    \"# in the file. The lint is file-level, not line-level — the cheap\",\n    \"# coarse signal is enough to catch the failure mode the convention\",\n    \"# targets, and a finer-grained check would carry too much false\",\n    \"# positive cost.\",\n    \"#\",\n    \"# The path patterns are rendered from the consumer's\",\n    \"# TemporalFramingConfig at synth time — do not edit by hand;\",\n    \"# regenerate via `pnpm exec projen`.\",\n    \"#\",\n    \"# Patterns support the `**` recursive-segment wildcard even though\",\n    \"# bash's native `[[ $file == $glob ]]` pattern matching does not:\",\n    \"# each glob is converted to a POSIX-extended regex internally and\",\n    \"# matched with `=~`, so the script works uniformly on bash 3.2\",\n    \"# (macOS default) and bash 4+ (Linux / CI).\",\n    \"\",\n    \"set -uo pipefail\",\n    \"\",\n    \"err() {\",\n    '  printf \"check-temporal-framing.sh: %s\\\\n\" \"$*\" >&2',\n    \"}\",\n    \"\",\n    \"# Path glob patterns. Translated to anchored POSIX-extended regexes\",\n    \"# at runtime by `glob_to_regex` below so `**` matches recursively\",\n    \"# across path segments.\",\n    \"path_patterns=(\",\n    patternsLiteral,\n    \")\",\n    \"\",\n    \"# Triggers — present-tense framing keywords that indicate a\",\n    \"# time-sensitive claim category. Match is case-insensitive and\",\n    \"# whole-word; the keyword list is deliberately small (one or two\",\n    \"# canonical phrases per category) to keep false positives low.\",\n    \"triggers=(\",\n    '  \"is owned by\"',\n    '  \"co-owned by\"',\n    '  \"majority-owned by\"',\n    '  \"minority-owned by\"',\n    '  \"is co-owned\"',\n    '  \"is currently\"',\n    '  \"currently chairs\"',\n    '  \"currently serves\"',\n    '  \"is in force\"',\n    '  \"under public consultation\"',\n    '  \"under active investigation\"',\n    '  \"is pending\"',\n    '  \"investigation is ongoing\"',\n    \")\",\n    \"\",\n    \"# Convert a bash-style glob into an anchored POSIX-extended regex:\",\n    \"#   **/   → (.+/)?   (zero or more path segments plus trailing slash)\",\n    \"#   **    → .*       (anywhere, including `/`)\",\n    \"#   *     → [^/]*    (single path segment)\",\n    \"#   ?     → [^/]     (single non-slash char)\",\n    \"glob_to_regex() {\",\n    '  local glob=\"$1\"',\n    '  local regex=\"\"',\n    \"  local i=0\",\n    \"  local len=${#glob}\",\n    \"  while (( i < len )); do\",\n    '    local c=\"${glob:i:1}\"',\n    '    if [[ \"$c\" == \"*\" ]]; then',\n    '      local next=\"${glob:i+1:1}\"',\n    '      if [[ \"$next\" == \"*\" ]]; then',\n    '        local after=\"${glob:i+2:1}\"',\n    '        if [[ \"$after\" == \"/\" ]]; then',\n    '          regex+=\"(.+/)?\"',\n    \"          i=$((i+3))\",\n    \"          continue\",\n    \"        fi\",\n    '        regex+=\".*\"',\n    \"        i=$((i+2))\",\n    \"        continue\",\n    \"      fi\",\n    '      regex+=\"[^/]*\"',\n    \"      i=$((i+1))\",\n    \"      continue\",\n    \"    fi\",\n    '    if [[ \"$c\" == \"?\" ]]; then',\n    '      regex+=\"[^/]\"',\n    \"      i=$((i+1))\",\n    \"      continue\",\n    \"    fi\",\n    '    case \"$c\" in',\n    \"      .|+|\\\\(|\\\\)|\\\\[|\\\\]|\\\\{|\\\\}|\\\\||\\\\^|\\\\$|\\\\\\\\)\",\n    '        regex+=\"\\\\\\\\$c\"',\n    \"        ;;\",\n    \"      *)\",\n    '        regex+=\"$c\"',\n    \"        ;;\",\n    \"    esac\",\n    \"    i=$((i+1))\",\n    \"  done\",\n    '  printf \"^%s$\" \"$regex\"',\n    \"}\",\n    \"\",\n    \"# Check whether $file matches any of the configured path patterns.\",\n    \"# Returns 0 on match, 1 otherwise.\",\n    \"matches_any_pattern() {\",\n    '  local file=\"$1\"',\n    \"  local pattern regex\",\n    '  for pattern in \"${path_patterns[@]}\"; do',\n    '    regex=$(glob_to_regex \"$pattern\")',\n    '    if [[ \"$file\" =~ $regex ]]; then',\n    \"      return 0\",\n    \"    fi\",\n    \"  done\",\n    \"  return 1\",\n    \"}\",\n    \"\",\n    \"# Check whether $file contains any present-tense framing trigger\",\n    \"# without an `as of ` qualifier anywhere in the file. Returns 0\",\n    \"# when the file is OK (no triggers, or triggers + qualifier), 1\",\n    \"# when the file is malformed (triggers + no qualifier).\",\n    \"file_ok() {\",\n    '  local file=\"$1\"',\n    '  [[ ! -f \"$file\" ]] && return 0',\n    \"  local found_trigger=0\",\n    \"  local trigger\",\n    '  for trigger in \"${triggers[@]}\"; do',\n    '    if grep -qi -- \"$trigger\" \"$file\"; then',\n    \"      found_trigger=1\",\n    \"      break\",\n    \"    fi\",\n    \"  done\",\n    \"  if [[ $found_trigger -eq 0 ]]; then\",\n    \"    return 0\",\n    \"  fi\",\n    '  if grep -qi -- \"as of \" \"$file\"; then',\n    \"    return 0\",\n    \"  fi\",\n    \"  return 1\",\n    \"}\",\n    \"\",\n    \"# Read the file list from positional args or stdin.\",\n    \"files=()\",\n    \"if [[ $# -gt 0 ]]; then\",\n    '  files=(\"$@\")',\n    \"else\",\n    \"  while IFS= read -r line; do\",\n    '    [[ -n \"$line\" ]] && files+=(\"$line\")',\n    \"  done\",\n    \"fi\",\n    \"\",\n    \"if [[ ${#files[@]} -eq 0 ]]; then\",\n    \"  exit 0\",\n    \"fi\",\n    \"\",\n    \"violations=0\",\n    'for file in \"${files[@]}\"; do',\n    '  if ! matches_any_pattern \"$file\"; then',\n    \"    continue\",\n    \"  fi\",\n    '  if ! file_ok \"$file\"; then',\n    '    err \"$file: contains time-sensitive framing without an \\\\\"as of\\\\\" qualifier\"',\n    \"    violations=$((violations+1))\",\n    \"  fi\",\n    \"done\",\n    \"\",\n    \"if [[ $violations -gt 0 ]]; then\",\n    '  err \"found $violations file(s) violating the temporal-framing convention\"',\n    \"  exit 1\",\n    \"fi\",\n    \"exit 0\",\n  ].join(\"\\n\");\n}\n\n/*******************************************************************************\n *\n * Internal helpers\n *\n ******************************************************************************/\n\nfunction assertValidPaths(paths: ReadonlyArray<string>): void {\n  if (!Array.isArray(paths)) {\n    throw new Error(\n      `TemporalFramingConfig.paths must be an array; got ${typeof paths}`,\n    );\n  }\n  for (let i = 0; i < paths.length; i++) {\n    const entry = paths[i];\n    if (typeof entry !== \"string\" || entry.trim().length === 0) {\n      throw new Error(\n        `TemporalFramingConfig.paths[${i}] must be a non-empty string; got ${JSON.stringify(\n          entry,\n        )}`,\n      );\n    }\n  }\n}\n\nfunction resolveCadences(\n  supplied?: Partial<{ readonly [K in TemporalFramingCategory]: number }>,\n): { readonly [K in TemporalFramingCategory]: number } {\n  const merged: { [K in TemporalFramingCategory]: number } = {\n    ...DEFAULT_TEMPORAL_FRAMING_CADENCES,\n  };\n\n  if (supplied !== undefined) {\n    for (const category of TEMPORAL_FRAMING_CATEGORY_VALUES) {\n      const value = supplied[category];\n      if (value === undefined) {\n        continue;\n      }\n      assertValidCadence(value, category);\n      merged[category] = value;\n    }\n  }\n\n  return merged;\n}\n\nfunction assertValidCadence(value: number, field: string): void {\n  if (typeof value !== \"number\" || !Number.isInteger(value)) {\n    throw new Error(\n      `TemporalFramingConfig.cadences.${field} must be a positive integer; got ${value}`,\n    );\n  }\n  if (value <= 0) {\n    throw new Error(\n      `TemporalFramingConfig.cadences.${field} must be a positive integer; got ${value}`,\n    );\n  }\n}\n","import {\n  renderIssueTemplatesRuleContent,\n  ResolvedIssueTemplates,\n  resolveIssueTemplates,\n} from \"./issue-templates\";\nimport { renderGithubIssueTypeSectionLines } from \"./issue-type\";\nimport { DEFAULT_AGENT_PATHS, ResolvedAgentPaths } from \"./paths\";\nimport {\n  renderProgressFilesRuleContent,\n  ResolvedProgressFiles,\n  resolveProgressFiles,\n} from \"./progress-files\";\nimport {\n  DEFAULT_SHARED_INDEX_PATHS,\n  renderSharedEditingRuleContent,\n  ResolvedSharedEditing,\n  resolveSharedEditing,\n} from \"./shared-editing\";\nimport {\n  renderSkillEvalsRuleContent,\n  ResolvedSkillEvals,\n  resolveSkillEvals,\n} from \"./skill-evals\";\nimport {\n  renderTemporalFramingRuleContent,\n  ResolvedTemporalFraming,\n  resolveTemporalFraming,\n} from \"./temporal-framing\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE, AgentSkill } from \"../types\";\n\nconst createPackageSkill: AgentSkill = {\n  name: \"create-package\",\n  description:\n    \"Scaffold a new TypeScriptProject sub-project under packages/@scope/<name> by emitting the projen block to add to the monorepo config\",\n  disableModelInvocation: true,\n  instructions: [\n    \"# Create Package\",\n    \"\",\n    \"Scaffold a new shared-library sub-project at\",\n    \"`packages/@scope/<name>` by emitting the projen block to add to the\",\n    \"monorepo's projen configuration. This skill walks the user through\",\n    \"naming, metadata, and placement; it does **not** run projen, install\",\n    \"dependencies, or execute any build commands.\",\n    \"\",\n    \"## Usage\",\n    \"\",\n    \"```\",\n    \"/create-package @<scope>/<name>\",\n    \"```\",\n    \"\",\n    \"Example: `/create-package @codedrifters/my-lib` → scaffolds a new\",\n    \"`TypeScriptProject` at `packages/@codedrifters/my-lib`.\",\n    \"\",\n    \"## Steps\",\n    \"\",\n    \"1. **Parse and validate the package name.** The argument must be a\",\n    \"   **scoped** npm name in the form `@<scope>/<name>`:\",\n    \"   - Starts with `@`\",\n    \"   - Has exactly one `/` separator\",\n    \"   - `<scope>` and `<name>` are lowercase, kebab-case, non-empty\",\n    \"   - Unscoped names (e.g. `my-lib`) are **not** allowed — every\",\n    \"     package under `packages/` is scoped by owner.\",\n    \"   If the input is missing or invalid, ask the user to supply a\",\n    \"   scoped name. Do not guess the scope.\",\n    \"\",\n    \"2. **Collect metadata** — ask the user for each of the following,\",\n    \"   one question at a time:\",\n    \"   - **Description** — one-line summary of what the package does.\",\n    \"   - **Publish to npm?** — `true` or `false`. Workspace-internal\",\n    \"     libraries should answer `false`.\",\n    \"   Skip any question the user has already answered in the initial\",\n    \"   prompt.\",\n    \"\",\n    \"3. **Determine the target outdir.** The sub-project lives at:\",\n    \"\",\n    \"   ```\",\n    \"   packages/<scope>/<name>\",\n    \"   ```\",\n    \"\",\n    \"   `<scope>` is everything after `@` and before `/` in the package\",\n    \"   name; `<name>` is everything after the `/`. This matches the\",\n    \"   default `outdir` that `TypeScriptProject` computes from the\",\n    \"   package name, so the emitted block does **not** need to set\",\n    \"   `outdir` explicitly.\",\n    \"\",\n    \"4. **Locate the projen config file.** Prefer the monorepo's\",\n    \"   `projenrc/` directory — most monorepos declare sub-projects\",\n    \"   there (e.g. `projenrc/root-project.ts` or a dedicated\",\n    \"   `projenrc/packages.ts`). Fall back to `.projenrc.ts` only when\",\n    \"   no `projenrc/` directory exists.\",\n    \"\",\n    \"5. **Emit the projen block.** Show the TypeScript block to paste\",\n    \"   into the chosen projen config file. Example for\",\n    \"   `@codedrifters/my-lib`:\",\n    \"\",\n    \"   ```typescript\",\n    \"   import { TypeScriptProject } from '@codedrifters/configulator';\",\n    \"\",\n    \"   // Inside the monorepo's configuration function, alongside\",\n    \"   // sibling sub-projects:\",\n    \"   new TypeScriptProject({\",\n    \"     parent: monorepo,\",\n    \"     name: '@codedrifters/my-lib',\",\n    \"     description: '<one-line description>',\",\n    \"     defaultReleaseBranch: 'main',\",\n    \"     publishToNpm: false, // or true if this package publishes\",\n    \"   });\",\n    \"   ```\",\n    \"\",\n    \"   Substitute the user's scope, name, description, and\",\n    \"   `publishToNpm` value. Do not hard-code `outdir` — the default\",\n    \"   places the sub-project at `packages/<scope>/<name>`.\",\n    \"\",\n    \"6. **Tell the user how to synthesize.** Instruct them to run, from\",\n    \"   the repo root, the safe three-step regen sequence:\",\n    \"\",\n    \"   ```\",\n    \"   pnpm i\",\n    \"   pnpm exec projen\",\n    \"   pnpm i\",\n    \"   ```\",\n    \"\",\n    \"   The leading `pnpm i` syncs `node_modules` with `pnpm-lock.yaml`\",\n    \"   so synth runs against the right configulator/projen/plugin\",\n    \"   versions — without it, `pnpm exec projen` may synth against a\",\n    \"   stale resolved version of any pnpm-managed component and produce\",\n    \"   phantom drift in generated files. `pnpm exec projen` regenerates\",\n    \"   the sub-project tree; the trailing `pnpm i` updates the workspace\",\n    \"   lockfile to pick up any dependency changes projen wrote during\",\n    \"   synth. Do **not** run these commands yourself — the user runs them.\",\n    \"\",\n    \"## Guardrails\",\n    \"\",\n    \"- Never run `pnpm exec projen`, `pnpm install`, `pnpm i`, `pnpm build`,\",\n    \"  `pnpm test`, or any other package-manager, build, or test command.\",\n    \"  Emit the projen block and instructions only.\",\n    \"- Never scaffold outside `packages/`. Deployable apps belong under\",\n    \"  `apps/<scope>/<name>` (use `/create-app`); user-facing sites belong\",\n    \"  under `sites/<scope>/<name>` (use `/create-site`).\",\n    \"- Never scope by category (e.g. `@libs/foo`, `@packages/foo`). The\",\n    \"  scope identifies the **owning party**; the top-level folder\",\n    \"  identifies the kind.\",\n    \"- Do not invent an `outdir` — rely on the `TypeScriptProject`\",\n    \"  default that places the sub-project at `packages/<scope>/<name>`.\",\n    \"\",\n    \"## Related Skills\",\n    \"\",\n    \"- `/create-app` — scaffold a new `AwsCdkProject` under\",\n    \"  `apps/<scope>/<name>`.\",\n    \"- `/create-site` — scaffold a new `AstroProject` under\",\n    \"  `sites/<scope>/<name>`.\",\n  ].join(\"\\n\"),\n};\n\nconst createAppSkill: AgentSkill = {\n  name: \"create-app\",\n  description:\n    \"Scaffold a new AwsCdkProject sub-project under apps/@scope/<name> by emitting the projen block to add to the monorepo config\",\n  disableModelInvocation: true,\n  instructions: [\n    \"# Create App\",\n    \"\",\n    \"Scaffold a new deployable-application sub-project at\",\n    \"`apps/@scope/<name>` by emitting the projen block to add to the\",\n    \"monorepo's projen configuration. This skill walks the user through\",\n    \"naming, metadata, and placement; it does **not** run projen, install\",\n    \"dependencies, or execute any build commands.\",\n    \"\",\n    \"Today this skill scaffolds AWS CDK applications (`AwsCdkProject`).\",\n    \"The `apps/` folder is also the right home for other deployable\",\n    \"application types (mobile apps, backend services) as configulator\",\n    \"grows support for them — but at the moment, this skill emits an\",\n    \"`AwsCdkProject` block.\",\n    \"\",\n    \"## Usage\",\n    \"\",\n    \"```\",\n    \"/create-app @<scope>/<name>\",\n    \"```\",\n    \"\",\n    \"Example: `/create-app @codedrifters/my-stack` → scaffolds a new\",\n    \"`AwsCdkProject` at `apps/@codedrifters/my-stack`.\",\n    \"\",\n    \"## Steps\",\n    \"\",\n    \"1. **Parse and validate the app name.** The argument must be a\",\n    \"   **scoped** npm name in the form `@<scope>/<name>`:\",\n    \"   - Starts with `@`\",\n    \"   - Has exactly one `/` separator\",\n    \"   - `<scope>` and `<name>` are lowercase, kebab-case, non-empty\",\n    \"   - Unscoped names (e.g. `my-stack`) are **not** allowed — every\",\n    \"     app under `apps/` is scoped by owner.\",\n    \"   If the input is missing or invalid, ask the user to supply a\",\n    \"   scoped name. Do not guess the scope.\",\n    \"\",\n    \"2. **Collect metadata** — ask the user for each of the following,\",\n    \"   one question at a time:\",\n    \"   - **Description** — one-line summary of what the app does.\",\n    \"   Skip any question the user has already answered in the initial\",\n    \"   prompt.\",\n    \"\",\n    \"   Do **not** ask for a CDK version. `AwsCdkProject` renders\",\n    \"   `aws-cdk-lib` and `constructs` as `catalog:`, so the monorepo's\",\n    \"   pnpm catalog pins both for every app. Passing a `cdkVersion` or\",\n    \"   `constructsVersion` that disagrees with the catalog throws at\",\n    \"   synth time — a version bump is a catalog edit, not a per-app\",\n    \"   option.\",\n    \"\",\n    \"3. **Determine the target outdir.** The sub-project lives at:\",\n    \"\",\n    \"   ```\",\n    \"   apps/<scope>/<name>\",\n    \"   ```\",\n    \"\",\n    \"   `<scope>` is everything after `@` and before `/` in the app\",\n    \"   name; `<name>` is everything after the `/`. This matches the\",\n    \"   default `outdir` that `AwsCdkProject` computes from the package\",\n    \"   name, so the emitted block does **not** need to set `outdir`\",\n    \"   explicitly.\",\n    \"\",\n    \"4. **Locate the projen config file.** Prefer the monorepo's\",\n    \"   `projenrc/` directory — most monorepos declare sub-projects\",\n    \"   there (e.g. `projenrc/root-project.ts` or a dedicated\",\n    \"   `projenrc/apps.ts`). Fall back to `.projenrc.ts` only when\",\n    \"   no `projenrc/` directory exists.\",\n    \"\",\n    \"5. **Emit the projen block.** Show the TypeScript block to paste\",\n    \"   into the chosen projen config file. Example for\",\n    \"   `@codedrifters/my-stack`:\",\n    \"\",\n    \"   ```typescript\",\n    \"   import { AwsCdkProject } from '@codedrifters/configulator';\",\n    \"\",\n    \"   // Inside the monorepo's configuration function, alongside\",\n    \"   // sibling sub-projects:\",\n    \"   new AwsCdkProject({\",\n    \"     parent: monorepo,\",\n    \"     name: '@codedrifters/my-stack',\",\n    \"     description: '<one-line description>',\",\n    \"   });\",\n    \"   ```\",\n    \"\",\n    \"   Substitute the user's scope, name, and description. Do not\",\n    \"   hard-code `outdir` — the default places the sub-project at\",\n    \"   `apps/<scope>/<name>` — and do not add `cdkVersion`; the\",\n    \"   catalog supplies it.\",\n    \"\",\n    \"6. **Tell the user how to synthesize.** Instruct them to run, from\",\n    \"   the repo root, the safe three-step regen sequence:\",\n    \"\",\n    \"   ```\",\n    \"   pnpm i\",\n    \"   pnpm exec projen\",\n    \"   pnpm i\",\n    \"   ```\",\n    \"\",\n    \"   The leading `pnpm i` syncs `node_modules` with `pnpm-lock.yaml`\",\n    \"   so synth runs against the right configulator/projen/plugin\",\n    \"   versions — without it, `pnpm exec projen` may synth against a\",\n    \"   stale resolved version of any pnpm-managed component and produce\",\n    \"   phantom drift in generated files. `pnpm exec projen` regenerates\",\n    \"   the sub-project tree; the trailing `pnpm i` updates the workspace\",\n    \"   lockfile to pick up any dependency changes projen wrote during\",\n    \"   synth. Do **not** run these commands yourself — the user runs them.\",\n    \"\",\n    \"## Guardrails\",\n    \"\",\n    \"- Never run `pnpm exec projen`, `pnpm install`, `pnpm i`, `pnpm build`,\",\n    \"  `pnpm test`, or any other package-manager, build, or test command.\",\n    \"  Emit the projen block and instructions only.\",\n    \"- Never scaffold outside `apps/`. Shared libraries belong under\",\n    \"  `packages/<scope>/<name>` (use `/create-package`); user-facing\",\n    \"  sites belong under `sites/<scope>/<name>` (use `/create-site`).\",\n    \"- Never scope by category (e.g. `@apps/foo`, `@stacks/foo`). The\",\n    \"  scope identifies the **owning party**; the top-level folder\",\n    \"  identifies the kind.\",\n    \"- Do not invent an `outdir` — rely on the `AwsCdkProject` default\",\n    \"  that places the sub-project at `apps/<scope>/<name>`.\",\n    \"\",\n    \"## Related Skills\",\n    \"\",\n    \"- `/create-package` — scaffold a new `TypeScriptProject` under\",\n    \"  `packages/<scope>/<name>`.\",\n    \"- `/create-site` — scaffold a new `AstroProject` under\",\n    \"  `sites/<scope>/<name>`.\",\n  ].join(\"\\n\"),\n};\n\nconst createSiteSkill: AgentSkill = {\n  name: \"create-site\",\n  description:\n    \"Scaffold a new AstroProject sub-project under sites/@scope/<name> by emitting the projen block to add to the monorepo config\",\n  disableModelInvocation: true,\n  instructions: [\n    \"# Create Site\",\n    \"\",\n    \"Scaffold a new user-facing web front end at\",\n    \"`sites/@scope/<name>` by emitting the projen block to add to the\",\n    \"monorepo's projen configuration. This skill walks the user through\",\n    \"naming, metadata, and placement; it does **not** run projen, install\",\n    \"dependencies, or execute any build commands.\",\n    \"\",\n    \"The default project type is `AstroProject` — the common shape for\",\n    \"marketing sites, SPAs, and client-facing static sites. A\",\n    '`StarlightProject` with `role: \"site\"` is also a valid placement',\n    \"under `sites/<scope>/<name>` for consumers who specifically want a\",\n    \"Starlight-based front end; it is **not** the monorepo-wide docs site.\",\n    \"\",\n    \"## Usage\",\n    \"\",\n    \"```\",\n    \"/create-site @<scope>/<name>\",\n    \"```\",\n    \"\",\n    \"Example: `/create-site @codedrifters/marketing-site` → scaffolds a\",\n    \"new `AstroProject` at `sites/@codedrifters/marketing-site`.\",\n    \"\",\n    \"## Docs-vs-Site Guard\",\n    \"\",\n    \"There is **exactly one** Starlight docs site per monorepo, and it\",\n    \"lives at `/docs` — not under `sites/`. Before emitting any block,\",\n    \"check whether the user actually wants the monorepo-wide docs site:\",\n    \"\",\n    \"- If the user's intent is to create the single dev-docs site for the\",\n    \"  monorepo (names like `docs`, `documentation`, `dev-docs`, or any\",\n    '  explicit mention of \"the docs site\"), **refuse** to scaffold it',\n    \"  under `sites/`. Redirect them to the `StarlightProject` defaults\",\n    \"  that place the docs site at `/docs`, and explain that `sites/` is\",\n    \"  reserved for end-user-facing web front ends (marketing, SPAs,\",\n    \"  client-facing apps).\",\n    \"- If the user wants a user-facing site that happens to use Starlight\",\n    \"  (e.g. a public-facing documentation portal for a specific\",\n    \"  product), that is fine — they should use `StarlightProject` with\",\n    '  `role: \"site\"`, which routes under `sites/<scope>/<name>`.',\n    \"- Otherwise, proceed with `AstroProject` as the default.\",\n    \"\",\n    \"## Steps\",\n    \"\",\n    \"1. **Parse and validate the site name.** The argument must be a\",\n    \"   **scoped** npm name in the form `@<scope>/<name>`:\",\n    \"   - Starts with `@`\",\n    \"   - Has exactly one `/` separator\",\n    \"   - `<scope>` and `<name>` are lowercase, kebab-case, non-empty\",\n    \"   - Unscoped names (e.g. `marketing-site`) are **not** allowed —\",\n    \"     every site under `sites/` is scoped by owner.\",\n    \"   If the input is missing or invalid, ask the user to supply a\",\n    \"   scoped name. Do not guess the scope. Run the docs-vs-site guard\",\n    \"   above before continuing.\",\n    \"\",\n    \"2. **Collect metadata** — ask the user for each of the following,\",\n    \"   one question at a time:\",\n    \"   - **Description** — one-line summary of what the site is for.\",\n    \"   - **Project type** — `AstroProject` (default) or\",\n    \"     `StarlightProject` (role = site). If the user is unsure,\",\n    \"     recommend `AstroProject` — Starlight is only the right choice\",\n    \"     when the site's primary purpose is a documentation-style\",\n    '     layout. As an aside: a `StarlightProject` with `role: \"site\"`',\n    \"     lives at the same `sites/<scope>/<name>` path, so switching\",\n    \"     between the two later is a low-cost change.\",\n    \"   Skip any question the user has already answered in the initial\",\n    \"   prompt.\",\n    \"\",\n    \"3. **Determine the target outdir.** The sub-project lives at:\",\n    \"\",\n    \"   ```\",\n    \"   sites/<scope>/<name>\",\n    \"   ```\",\n    \"\",\n    \"   `<scope>` is everything after `@` and before `/` in the site\",\n    \"   name; `<name>` is everything after the `/`. This matches the\",\n    \"   default `outdir` that `AstroProject` (and `StarlightProject` with\",\n    '   `role: \"site\"`) computes from the package name, so the emitted',\n    \"   block does **not** need to set `outdir` explicitly.\",\n    \"\",\n    \"4. **Locate the projen config file.** Prefer the monorepo's\",\n    \"   `projenrc/` directory — most monorepos declare sub-projects\",\n    \"   there (e.g. `projenrc/root-project.ts` or a dedicated\",\n    \"   `projenrc/sites.ts`). Fall back to `.projenrc.ts` only when\",\n    \"   no `projenrc/` directory exists.\",\n    \"\",\n    \"5. **Emit the projen block.** Show the TypeScript block to paste\",\n    \"   into the chosen projen config file. Example for\",\n    \"   `@codedrifters/marketing-site` as an `AstroProject`:\",\n    \"\",\n    \"   ```typescript\",\n    \"   import { AstroProject } from '@codedrifters/configulator';\",\n    \"\",\n    \"   // Inside the monorepo's configuration function, alongside\",\n    \"   // sibling sub-projects:\",\n    \"   new AstroProject({\",\n    \"     parent: monorepo,\",\n    \"     name: '@codedrifters/marketing-site',\",\n    \"     description: '<one-line description>',\",\n    \"   });\",\n    \"   ```\",\n    \"\",\n    '   If the user chose `StarlightProject` with `role: \"site\"`, emit',\n    \"   that variant instead — same path, different project class:\",\n    \"\",\n    \"   ```typescript\",\n    \"   import { StarlightProject } from '@codedrifters/configulator';\",\n    \"\",\n    \"   new StarlightProject({\",\n    \"     parent: monorepo,\",\n    \"     name: '@codedrifters/marketing-site',\",\n    \"     description: '<one-line description>',\",\n    \"     role: 'site',\",\n    \"   });\",\n    \"   ```\",\n    \"\",\n    \"   Substitute the user's scope, name, and description. Do not\",\n    \"   hard-code `outdir` — the default places the sub-project at\",\n    \"   `sites/<scope>/<name>`.\",\n    \"\",\n    \"6. **Tell the user how to synthesize.** Instruct them to run, from\",\n    \"   the repo root, the safe three-step regen sequence:\",\n    \"\",\n    \"   ```\",\n    \"   pnpm i\",\n    \"   pnpm exec projen\",\n    \"   pnpm i\",\n    \"   ```\",\n    \"\",\n    \"   The leading `pnpm i` syncs `node_modules` with `pnpm-lock.yaml`\",\n    \"   so synth runs against the right configulator/projen/plugin\",\n    \"   versions — without it, `pnpm exec projen` may synth against a\",\n    \"   stale resolved version of any pnpm-managed component and produce\",\n    \"   phantom drift in generated files. `pnpm exec projen` regenerates\",\n    \"   the sub-project tree; the trailing `pnpm i` updates the workspace\",\n    \"   lockfile to pick up any dependency changes projen wrote during\",\n    \"   synth. Do **not** run these commands yourself — the user runs them.\",\n    \"\",\n    \"## Guardrails\",\n    \"\",\n    \"- Never run `pnpm exec projen`, `pnpm install`, `pnpm i`, `pnpm build`,\",\n    \"  `pnpm test`, or any other package-manager, build, or test command.\",\n    \"  Emit the projen block and instructions only.\",\n    \"- Never scaffold the monorepo-wide docs site under `sites/`. The\",\n    \"  dev-docs site is a singleton at `/docs` and is created once per\",\n    '  repo via `StarlightProject` with its default `role: \"docs\"` —',\n    \"  redirect the user there if they ask for it.\",\n    \"- Never scaffold outside `sites/`. Shared libraries belong under\",\n    \"  `packages/<scope>/<name>` (use `/create-package`); deployable apps\",\n    \"  belong under `apps/<scope>/<name>` (use `/create-app`).\",\n    \"- Never scope by category (e.g. `@sites/foo`, `@web/foo`). The\",\n    \"  scope identifies the **owning party**; the top-level folder\",\n    \"  identifies the kind.\",\n    \"- Do not invent an `outdir` — rely on the `AstroProject` default\",\n    '  (or the `StarlightProject` default when `role: \"site\"`) that',\n    \"  places the sub-project at `sites/<scope>/<name>`.\",\n    \"\",\n    \"## Related Skills\",\n    \"\",\n    \"- `/create-package` — scaffold a new `TypeScriptProject` under\",\n    \"  `packages/<scope>/<name>`.\",\n    \"- `/create-app` — scaffold a new `AwsCdkProject` under\",\n    \"  `apps/<scope>/<name>`.\",\n  ].join(\"\\n\"),\n};\n\nconst createRuleSkill: AgentSkill = {\n  name: \"create-rule\",\n  description:\n    \"Guide for creating new agent rules in this project using configulator\",\n  disableModelInvocation: true,\n  instructions: [\n    \"# Create Agent Rule\",\n    \"\",\n    \"Create a new agent rule for the **{{repository.owner}}/{{repository.name}}** project.\",\n    \"\",\n    \"## Steps\",\n    \"\",\n    \"1. **Identify the rule purpose** — ask what behavior the rule should enforce or guide\",\n    \"2. **Choose a scope:**\",\n    \"   - `AGENT_RULE_SCOPE.ALWAYS` — active in all contexts\",\n    \"   - `AGENT_RULE_SCOPE.FILE_PATTERN` — active only when working on matching files (requires `filePatterns`)\",\n    \"3. **Pick a name** — lowercase kebab-case (e.g., `react-conventions`, `api-error-handling`)\",\n    \"4. **Write the content** — clear, actionable markdown instructions\",\n    \"5. **Add to the project config** — add the rule to `AgentConfigOptions.rules` in the Projen config file\",\n    \"\",\n    \"## Rule Template\",\n    \"\",\n    \"```typescript\",\n    \"import { AGENT_RULE_SCOPE } from '@codedrifters/configulator';\",\n    \"\",\n    \"// In your AgentConfig options:\",\n    \"{\",\n    \"  rules: [\",\n    \"    {\",\n    \"      name: 'my-new-rule',\",\n    \"      description: 'What this rule does — used by AI for rule selection',\",\n    \"      scope: AGENT_RULE_SCOPE.ALWAYS, // or FILE_PATTERN\",\n    \"      // filePatterns: ['src/**/*.ts'],  // required for FILE_PATTERN scope\",\n    \"      content: [\",\n    \"        '# Rule Title',\",\n    \"        '',\",\n    \"        '## Guidelines',\",\n    \"        '',\",\n    \"        '- Guideline 1',\",\n    \"        '- Guideline 2',\",\n    \"      ].join('\\\\n'),\",\n    \"      tags: ['coding'], // optional: for ordering\",\n    \"    },\",\n    \"  ],\",\n    \"}\",\n    \"```\",\n    \"\",\n    \"## Best Practices\",\n    \"\",\n    \"- Keep rules **focused** — one concern per rule\",\n    '- Use **imperative tone** — \"Use X\" not \"You should use X\"',\n    \"- Include **examples** for complex patterns\",\n    \"- Use `ruleExtensions` to add project-specific content to existing bundle rules instead of replacing them\",\n  ].join(\"\\n\"),\n};\n\n/**\n * Fully-resolved settings for the five config-driven convention rules\n * the base bundle owns. Every field is already resolved, so\n * `buildBaseBundle` can seed each rule's final content up front rather\n * than shipping default content that a later pass has to rewrite.\n *\n * Seeding before the rule map exists is what lets `ruleExtensions`\n * appends and consumer-supplied same-name `rules` entries compose with\n * a consumer's convention overrides instead of being clobbered by\n * them. This mirrors the `pr-review-policy` rule, which has always\n * resolved its policy inside `buildPrReviewBundle`.\n */\nexport interface ResolvedBaseConventions {\n  readonly progressFiles: ResolvedProgressFiles;\n  readonly sharedEditing: ResolvedSharedEditing;\n  readonly temporalFraming: ResolvedTemporalFraming;\n  readonly skillEvals: ResolvedSkillEvals;\n  readonly issueTemplates: ResolvedIssueTemplates;\n\n  /**\n   * Whether any bundle contributing a downstream issue kind survived\n   * `excludeBundles`. When false the issue-templates rule renders its\n   * disabled stub — the convention has nothing left to enforce.\n   */\n  readonly hasDownstreamIssueKindBundles: boolean;\n}\n\n/**\n * The convention settings the base bundle ships when the consumer\n * supplies no override. Exported so callers can spread a partial\n * override over the documented defaults.\n */\nexport const DEFAULT_BASE_CONVENTIONS: ResolvedBaseConventions = {\n  progressFiles: resolveProgressFiles(),\n  sharedEditing: resolveSharedEditing(),\n  temporalFraming: resolveTemporalFraming(),\n  skillEvals: resolveSkillEvals(),\n  issueTemplates: resolveIssueTemplates(),\n  hasDownstreamIssueKindBundles: true,\n};\n\n/**\n * Base bundle — always included unless `includeBaseRules: false`.\n * Contains project-overview, interaction-style, and general-conventions rules.\n */\nexport function buildBaseBundle(\n  paths: ResolvedAgentPaths = DEFAULT_AGENT_PATHS,\n  conventions: ResolvedBaseConventions = DEFAULT_BASE_CONVENTIONS,\n): AgentRuleBundle {\n  return {\n    name: \"base\",\n    description:\n      \"Core rules: project overview, interaction style, and general coding conventions\",\n    appliesWhen: () => true,\n    skills: [\n      createPackageSkill,\n      createAppSkill,\n      createSiteSkill,\n      createRuleSkill,\n    ],\n    rules: [\n      {\n        name: \"project-overview\",\n        description: \"Project context and technology stack overview\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Project Overview\",\n          \"\",\n          \"**Repository:** {{repository.owner}}/{{repository.name}}\",\n          \"**Default branch:** {{repository.defaultBranch}}\",\n          \"\",\n          \"## Important Notes\",\n          \"\",\n          \"- **Never edit generated files** — they are marked with `// ~~ Generated by projen`\",\n          \"- **After modifying Projen configuration**, run the three-step regen sequence: `pnpm i`, then `pnpm exec projen`, then `pnpm i` again. The leading `pnpm i` syncs `node_modules` with the lockfile so synth runs against the right configulator/projen/plugin versions; the trailing `pnpm i` refreshes the lockfile to match anything projen rewrote in `package.json`.\",\n          \"- **Configure dependencies through Projen** — never use `npm install`, `pnpm add`, or `yarn add`. Add them to `deps` or `devDeps` in Projen config.\",\n          \"- **Export from index.ts** to maintain clean public APIs\",\n          '- **`defaultMode` is opt-in** for the rendered Claude Code `settings.json`. configulator does not set it by default, so the synthesised `settings.json` omits the key unless the consumer opts in. Consumers that run autonomous scheduled-task workers (issue-worker, orchestrator, pr-reviewer, and the analyst/writer family) — which would deadlock on confirmation prompts — opt in by setting `claudeSettings.defaultMode: \"dontAsk\"` on `AgentConfigOptions`.',\n          \"\",\n          \"## Repository Layout\",\n          \"\",\n          \"Every monorepo built with `@codedrifters/configulator` uses a fixed\",\n          \"top-level folder layout. Read a sub-project's role directly from its\",\n          \"outdir:\",\n          \"\",\n          \"| Folder | Purpose |\",\n          \"|--------|---------|\",\n          \"| `/docs` | **Single** monorepo-wide Starlight docs site (the one site that lives outside `/sites`). |\",\n          \"| `/apps/@scope/<name>` | Deployable applications (CDK stacks, mobile apps, backend services). |\",\n          \"| `/packages/@scope/<name>` | Shared libraries (published npm packages and workspace-internal libraries). |\",\n          \"| `/sites/@scope/<name>` | User-facing web front ends that are **not** the monorepo-wide docs site. |\",\n          \"\",\n          \"Every sub-project under `apps/`, `packages/`, or `sites/` is named\",\n          \"`@ownerscope/<name>`, where **scope is the owning party** (not a\",\n          \"category). Kind is captured by the top-level folder — never scope by\",\n          \"category (e.g. `@apps/foo`, `@libs/bar`).\",\n          \"\",\n          \"To place a **new** sub-project, always use a scaffolding skill — never\",\n          \"hand-roll the path:\",\n          \"\",\n          \"- `/create-package` — new shared library under `packages/<scope>/<name>`\",\n          \"- `/create-app` — new deployable app under `apps/<scope>/<name>`\",\n          \"- `/create-site` — new web front end under `sites/<scope>/<name>`\",\n          \"\",\n          \"The `monorepo-layout` rule documents the full contract (outdir\",\n          \"defaults per project type, the docs-singleton carve-out, synth-time\",\n          \"enforcement).\",\n        ].join(\"\\n\"),\n        tags: [\"project\"],\n      },\n      {\n        name: \"cursor-projen-restrictions\",\n        description:\n          \"Cursor must not run projen, build, test, or package-manager commands\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Projen & Development Command Restrictions\",\n          \"\",\n          \"**Never** run any of the following commands. Instead, tell the user which commands to run and why.\",\n          \"\",\n          \"## Prohibited Commands\",\n          \"\",\n          \"- `pnpm exec projen` — synthesize project files\",\n          \"- `pnpm install` / `pnpm i` — install dependencies\",\n          \"- `pnpm build` / `pnpm build:all` — build the project\",\n          \"- `pnpm test` / `pnpm --filter ... test` — run tests\",\n          \"- `pnpm eslint` / `pnpm --filter ... eslint` — run linting\",\n          \"- `pnpm compile` / `pnpm --filter ... compile` — compile packages\",\n          \"- `pnpm reset` / `pnpm reset:all` — reset build artifacts\",\n          \"- Any `vitest`, `tsup`, `rollup`, or `turbo` commands\",\n          \"\",\n          \"## What to Do Instead\",\n          \"\",\n          \"After making changes that need validation, tell the user the specific commands to run:\",\n          \"\",\n          \"1. **After projen config changes** — tell the user to run the three-step regen sequence: `pnpm i && pnpm exec projen && pnpm i`\",\n          \"2. **After source code changes** — tell the user to run `pnpm --filter @codedrifters/<package> test`\",\n          \"3. **After multi-package changes** — tell the user to run `pnpm build:all`\",\n        ].join(\"\\n\"),\n        platforms: {\n          claude: { exclude: true },\n        },\n        tags: [\"project\"],\n      },\n      {\n        name: \"reference-documentation\",\n        description:\n          \"Consult project rules, documentation, and existing code before answering or making changes\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Reference Documentation\",\n          \"\",\n          \"Before answering questions or making changes, always consult available project context.\",\n          \"\",\n          \"1. **Read project rules and guidelines** — check for agent rules, contribution guides, and coding standards defined in the project.\",\n          \"2. **Review existing code** — understand current patterns, conventions, and architecture before proposing changes. Look at similar files and modules for reference.\",\n          \"3. **Check documentation** — consult README files, inline documentation, and any design documents for relevant context.\",\n          \"4. **Respect established patterns** — follow the conventions already in use rather than introducing new ones without discussion.\",\n          \"5. **Verify before assuming** — if documentation or code conflicts with your assumptions, trust the project sources and ask for clarification when needed.\",\n        ].join(\"\\n\"),\n        tags: [\"project\"],\n      },\n      {\n        name: \"interaction-style\",\n        description:\n          \"Interaction style — ask questions one at a time and wait for feedback\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Interaction Style Guidelines\",\n          \"\",\n          \"When responding to requests, follow these interaction principles.\",\n          \"\",\n          \"1. **Ask when ambiguous**: When requirements are ambiguous or incomplete, always ask clarifying questions before proceeding. Do not make assumptions about the user's intent — it is better to ask than to guess wrong.\",\n          \"2. **Ask questions one at a time**: When clarification is needed, ask a single question and wait for the user's response before proceeding.\",\n          \"3. **Wait for feedback**: After asking a question, pause and wait for the user's answer before asking additional questions or making assumptions.\",\n          \"4. **Avoid question overload**: Do not ask multiple questions in a single response. If multiple clarifications are needed, prioritize the most important question first.\",\n          \"5. **Progressive clarification**: Once the user answers your first question, you may then ask the next most important question if needed.\",\n          \"6. **Confirm understanding**: After receiving feedback, acknowledge the user's response before proceeding with the next step or question.\",\n          \"7. **Be patient**: Do not rush ahead with assumptions. It is better to ask one clarifying question than to proceed with incorrect assumptions.\",\n        ].join(\"\\n\"),\n        tags: [\"project\"],\n      },\n      {\n        name: \"general-conventions\",\n        description:\n          \"Code formatting (Prettier/ESLint), import conventions (ES modules, import order), error handling (async/await, no floating promises)\",\n        scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n        filePatterns: [\"**/*.ts\", \"**/*.tsx\"],\n        content: [\n          \"# General Conventions\",\n          \"\",\n          \"## Code Formatting\",\n          \"\",\n          \"- Use **Prettier** for formatting (runs automatically on save in VS Code)\",\n          \"- Always use curly braces for control flow, even single-line statements; use multi-line format for complex conditionals\",\n          \"- Prefer `const` over `let`; avoid `var`\",\n          \"- Use trailing commas in multi-line objects/arrays\",\n          \"\",\n          \"### ESLint Rules to Follow\",\n          \"\",\n          \"- `curly`: Always use curly braces (multi-line, consistent)\",\n          \"- `dot-notation`: Use dot notation over bracket notation\",\n          \"- `no-bitwise`: No bitwise operators\",\n          \"- `@typescript-eslint/no-shadow`: No variable shadowing\",\n          \"- `@typescript-eslint/member-ordering`: Follow member order\",\n          \"\",\n          \"## Import Conventions\",\n          \"\",\n          \"- **Always use ES modules** (`import`/`export`), never `require()` (exception: `.projenrc.ts` files where `require` is allowed)\",\n          \"- Import order:\",\n          \"  1. Built-in Node.js modules (e.g., `node:path`, `node:fs`)\",\n          \"  2. External dependencies (alphabetically sorted)\",\n          \"  3. Internal imports (relative paths)\",\n          \"- Group imports with blank lines between groups\",\n          \"- Alphabetize imports within each group (case-insensitive)\",\n          \"- Use absolute imports from package root when possible\",\n          \"- Avoid duplicate imports (`import/no-duplicates`); all imports must be resolvable (`import/no-unresolved`)\",\n          \"\",\n          \"## Error Handling\",\n          \"\",\n          \"- Always handle promises properly with `await`\",\n          \"- Use `@typescript-eslint/return-await` rule (always return await)\",\n          \"- Never leave floating promises (`@typescript-eslint/no-floating-promises`)\",\n          \"- Use proper error types and meaningful error messages\",\n          \"- Do not swallow errors or use empty catch blocks\",\n          \"- Prefer async/await over raw promises\",\n        ].join(\"\\n\"),\n        tags: [\"coding\"],\n      },\n      {\n        name: \"pull-request-conventions\",\n        description:\n          \"Conventional commit PR titles, closing keywords, change summaries\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Pull Request Conventions\",\n          \"\",\n          \"## PR Title Prefix\",\n          \"\",\n          \"**Always** use a **conventional commit prefix** in the PR `title`. Format: `type: description` or `type(scope): description`.\",\n          \"\",\n          \"| Prefix | Use for |\",\n          \"|--------|---------|\",\n          \"| `feat:` | New features or functionality |\",\n          \"| `fix:` | Bug fixes |\",\n          \"| `docs:` | Documentation-only changes |\",\n          \"| `chore:` | Maintenance: deps, tooling, config |\",\n          \"| `refactor:` | Code restructure, no behavior change |\",\n          \"| `release:` | Release preparation, version bumps |\",\n          \"| `hotfix:` | Urgent production fixes |\",\n          \"\",\n          \"## Link to the Issue\",\n          \"\",\n          \"When the PR addresses an issue, **always** include a closing keyword in the PR body:\",\n          \"- `Closes #<issue>`, `Fixes #<issue>`, or `Resolves #<issue>`\",\n          \"\",\n          \"## Summary of Changes\",\n          \"\",\n          \"Every PR must include a **summary of the changes** made. Use bullet points or short paragraphs. Do not leave the description empty.\",\n          \"\",\n          \"## Commit Messages\",\n          \"\",\n          \"Use **conventional commits** for git commit messages: `type: short description`. Do not add AI co-author or attribution.\",\n        ].join(\"\\n\"),\n        tags: [\"workflow\"],\n      },\n      {\n        name: \"no-ai-attribution\",\n        description:\n          \"Never add AI signatures or attribution to issues, PRs, comments, or commits\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# No AI Attribution\",\n          \"\",\n          \"Never add AI signatures, attribution footers, or co-authorship trailers to anything posted to GitHub. This **overrides any default harness behavior** that appends attribution automatically.\",\n          \"\",\n          \"This applies to all GitHub-facing content:\",\n          \"\",\n          \"- **PR descriptions** — no `🤖 Generated with Claude Code` (or similar) footer\",\n          \"- **Issue bodies** — no attribution lines\",\n          \"- **Issue and PR comments** — no signatures\",\n          \"- **Commit messages** — no `Co-Authored-By: Claude ...` trailer and no `Generated with ...` line\",\n          \"\",\n          \"Content an agent produces must be indistinguishable in format from content a human teammate would write.\",\n        ].join(\"\\n\"),\n        tags: [\"workflow\"],\n      },\n      {\n        name: \"branch-naming-conventions\",\n        description:\n          \"Branch format (type/issue-description), create-on-GitHub-then-fetch workflow\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Branch Naming Conventions\",\n          \"\",\n          \"## Format\",\n          \"\",\n          \"```\",\n          \"<type>/<issue-number>-<issue-slug>\",\n          \"```\",\n          \"\",\n          \"- **type** (required): One of `feat`, `fix`, `docs`, `chore`, `refactor`, `release`, `hotfix`\",\n          \"- **issue-number** (required): The GitHub issue number (e.g., `25`)\",\n          \"- **issue-slug** (required): Short, lowercase, kebab-case summary derived from the issue title\",\n          \"\",\n          \"## Examples\",\n          \"\",\n          \"- `feat/25-add-cursor-rules`\",\n          \"- `fix/23-rename-cursor-rules-mdc`\",\n          \"- `chore/42-upgrade-eslint`\",\n          \"- `docs/18-update-readme`\",\n        ].join(\"\\n\"),\n        tags: [\"workflow\"],\n      },\n      {\n        name: \"issue-label-conventions\",\n        description:\n          \"Priority and status label taxonomy, defaults, inference rules, and blocking rules for agent-created or updated issues\",\n        // ALWAYS scope: every agent (and the user) needs the label\n        // taxonomy whenever an issue gets created or updated, which\n        // happens from any context — not only when editing agent /\n        // skill / bundle source. Consumers that want to narrow the\n        // load can override via `agentConfig.additionalRulePaths`\n        // or `excludeRules`.\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Issue Label Conventions\",\n          \"\",\n          \"Every issue created or updated by an agent in **{{repository.owner}}/{{repository.name}}**\",\n          \"must carry exactly one `priority:*` label and exactly one `status:*` label.\",\n          \"These conventions apply to **all** agent bundles — do not redefine them\",\n          \"locally. The orchestrator and issue worker depend on this taxonomy.\",\n          \"\",\n          \"## Priority Labels\",\n          \"\",\n          \"Pick exactly one of the following:\",\n          \"\",\n          \"| Label | Criteria |\",\n          \"|-------|----------|\",\n          \"| `priority:critical` | Production is broken, blocked, or data at risk. Must start immediately. Use for outages, security incidents, regressions that block a release. |\",\n          \"| `priority:high` | Important work that should be next in the queue. Blocks other planned work, an epic's children, or a near-term deliverable. |\",\n          \"| `priority:medium` | Default for normal planned work. No immediate blocker but belongs in the current roadmap. |\",\n          \"| `priority:low` | Nice-to-have. Can be deferred without impact. Cleanups, minor polish, non-urgent refactors. |\",\n          \"| `priority:trivial` | Cosmetic or optional. Typos, formatting, stray comments. Safe to never pick up. |\",\n          \"\",\n          \"### Default Priority\",\n          \"\",\n          \"When the user has not indicated a priority and context provides no signal,\",\n          \"assign `priority:medium`.\",\n          \"\",\n          \"### Inference Heuristics\",\n          \"\",\n          \"Before defaulting to medium, scan the user's request and the issue context\",\n          \"for these signals:\",\n          \"\",\n          \"- **Urgency language** — words like *urgent*, *ASAP*, *immediately*, *now*,\",\n          \"  *blocker*, *on fire* → `priority:critical`\",\n          \"- **Importance language** — words like *important*, *soon*, *need this*,\",\n          \"  *next up*, *before launch* → `priority:high`\",\n          \"- **Deadlines** — an explicit due date within 7 days → `priority:high`;\",\n          \"  within 24 hours or labeled as a release blocker → `priority:critical`\",\n          \"- **Blocker status** — the issue blocks another open issue, an epic child,\",\n          \"  or a release → `priority:high` (or `priority:critical` if the blocked\",\n          \"  work is itself critical)\",\n          \"- **Business impact** — revenue loss, customer-facing outage, security\",\n          \"  exposure → `priority:critical`\",\n          \"- **Polish language** — *nice to have*, *minor*, *cleanup*, *whenever*,\",\n          \"  *low priority* → `priority:low`\",\n          \"- **Cosmetic scope** — typo fixes, comment tweaks, formatting-only → `priority:trivial`\",\n          \"- **Meeting-note origin** — any issue created from reviewing meeting notes or\",\n          \"  a meeting transcript → `priority:high` (meeting follow-ups are time-sensitive\",\n          \"  and presumed important unless the note explicitly says otherwise)\",\n          \"\",\n          \"### Ask vs. Infer\",\n          \"\",\n          \"- **Infer** when the user's request contains at least one clear signal from\",\n          \"  the heuristics above, or when the default (`priority:medium`) is clearly\",\n          \"  appropriate (routine feature, refactor, or chore with no urgency cues).\",\n          \"- **Ask** before creating the issue when:\",\n          '  - The request mixes signals (e.g., \"minor but blocks the release\")',\n          \"  - The work would reasonably map to `priority:critical` — always confirm\",\n          \"    before using the top tier\",\n          \"  - The scope is ambiguous enough that medium vs. high is unclear **and**\",\n          \"    the outcome would change how the orchestrator sequences work\",\n          \"- When asking, pose a single question with the candidate levels, e.g.\",\n          '  \"Is this `priority:high` (next in queue) or `priority:medium` (normal)?\"',\n          \"\",\n          \"## Status Labels\",\n          \"\",\n          \"Pick exactly one of the following. Status reflects where the issue sits in\",\n          \"the workflow, not the nature of the work.\",\n          \"\",\n          \"| Label | Criteria |\",\n          \"|-------|----------|\",\n          \"| `status:ready` | The issue is fully specified, has no open blockers, and is available for a worker to pick up. |\",\n          \"| `status:blocked` | The issue cannot be started yet — either it declares `Depends on: #N` on an open issue, or it is an epic with one or more open children. |\",\n          \"| `status:in-progress` | A worker has claimed the issue and a branch exists. Set when the worker starts; cleared only when the worker opens a PR or the issue fails. |\",\n          \"| `status:ready-for-review` | A PR has been opened for this issue and is awaiting review and merge. Replaces `status:in-progress` at the moment the PR opens. |\",\n          \"| `status:needs-attention` | Automated triage has flagged the issue for human review (stale, failed worker, or ambiguous state). Humans reset this label manually. |\",\n          \"| `status:deferred` | Captured for provenance only; should not be auto-dispatched. Used by consumers that want a low-priority backlog (e.g. people-profile follow-ups in research-heavy planning repos) to stay out of the orchestrator's queue until a human or a consumer-configured scheduled task promotes it. |\",\n          \"| `status:done` | The change has shipped. Set when the PR merges and the issue closes. |\",\n          \"\",\n          \"### Configurable filing-site defaults\",\n          \"\",\n          \"The bundle-shipped `gh issue create` recipes default to\",\n          \"`status:ready` + `priority:medium`. Consumers can override the\",\n          \"defaults per-phase-label via\",\n          \"`AgentConfigOptions.issueDefaults` — e.g. flip every\",\n          \"`people:research` filing to `status:deferred` + `priority:low`\",\n          \"without touching the bundle source. See the **`issueDefaults`**\",\n          \"section in the configulator agent-config docs for the full\",\n          \"schema and consumer example. `status:deferred` is a valid\",\n          \"override value reserved for this exact use case.\",\n          \"\",\n          \"### The `status:deferred` invariant\",\n          \"\",\n          \"**No agent, procedure, or sweep ever removes `status:deferred`.\",\n          \"Only a human promotes a deferred issue.**\",\n          \"\",\n          \"`status:deferred` records a deliberate human decision to park\",\n          \"work. Automation may read it, count it, and log it — but the\",\n          \"label is cleared exclusively by a human (or by a scheduled task\",\n          \"a human configured for that purpose). Concretely:\",\n          \"\",\n          \"- **Unblock sweeps skip it.** Both `check-blocked.sh unblock`\",\n          \"  and `unblock-dependents.sh` leave a `status:deferred` +\",\n          \"  `status:blocked` issue blocked when its dependencies close,\",\n          \"  emitting a `SKIP_DEFERRED #<n>` line instead of flipping to\",\n          \"  `status:ready`. Dependency resolution is not a promotion\",\n          \"  signal for parked work.\",\n          \"- **Dispatch scans exclude it.** `check-blocked.sh eligible`\",\n          \"  drops any issue carrying `status:deferred`, so a stray\",\n          \"  `status:ready` + `status:deferred` pairing never reaches a\",\n          \"  worker.\",\n          \"- **No sweep writes it either.** Automation adds\",\n          \"  `status:deferred` only at filing time via the configured\",\n          \"  `issueDefaults` — never as a runtime triage decision.\",\n          \"\",\n          \"An issue that legitimately needs to leave the parked backlog is\",\n          \"promoted by a human removing `status:deferred` and setting the\",\n          \"appropriate base status. Any automation that removes the label\",\n          \"is a bug.\",\n          \"\",\n          \"### Blocking Rules\",\n          \"\",\n          \"Two rules force `status:blocked` — both are non-negotiable:\",\n          \"\",\n          \"1. **Epic-blocking rule.** Any issue of GitHub type *Epic* that has one or\",\n          \"   more open child issues must carry `status:blocked`. Only flip it to\",\n          \"   `status:ready` (or close it) once every child is resolved.\",\n          \"2. **Dependency-blocking rule.** Any issue whose body contains a\",\n          \"   `Depends on: #N` line referencing an open issue must carry\",\n          \"   `status:blocked` for as long as that dependency remains open.\",\n          \"   When all referenced dependencies close, transition to `status:ready`.\",\n          \"\",\n          \"### Status Transitions\",\n          \"\",\n          \"Agents transition status labels at these well-defined points:\",\n          \"\",\n          \"- **Issue creation** → `status:ready` by default, or `status:blocked` if\",\n          \"  either blocking rule applies.\",\n          \"- **Worker claims the issue** → remove `status:ready`, add\",\n          \"  `status:in-progress`. A branch must exist before this transition.\",\n          \"- **Worker opens a PR** → remove `status:in-progress`, add\",\n          \"  `status:ready-for-review`. The PR URL should be posted on the issue.\",\n          \"- **PR merges / issue closes** → remove `status:ready-for-review`, add\",\n          \"  `status:done`.\",\n          \"- **Dependency resolves** → if the issue was `status:blocked` solely because\",\n          \"  of the dependency-blocking rule, remove `status:blocked` and add\",\n          \"  `status:ready`.\",\n          \"- **Automated flag** → add `status:needs-attention` (do not remove existing\",\n          \"  status). Never auto-reset a `status:needs-attention` issue back to ready;\",\n          \"  a human must decide. The flag is **additive**: apply it with `--add-label`\",\n          \"  alone — never pair it with a `--remove-label` that strips the base\",\n          \"  `status:*` label. A flag that swaps out the base status (e.g. scope-gate\",\n          \"  or worker-failure paths removing `status:ready` / `status:in-progress`)\",\n          \"  leaves the issue with no base status — invisible to every status-driven\",\n          \"  query and to the queue, and unrecoverable once the flag is cleared.\",\n          \"- **Automated-flag clear** → when `status:needs-attention` is cleared, if the\",\n          \"  issue carries no base `status:*` label (a legacy issue flagged before the\",\n          \"  additive-flag rule, whose base status was stripped at flag time), restore\",\n          \"  `status:ready` — or `status:blocked` if the body still declares an open\",\n          \"  `Depends on:` dependency — in the same edit so it re-enters the workflow.\",\n          \"- **PR CI failure** → add `status:needs-attention` to the associated PR (and\",\n          \"  its linked issue) when CI fails in a **permanent** state — i.e. the failure\",\n          \"  persists after a rerun, or the failure is clearly not a flake (compile\",\n          \"  errors, failing assertions, type errors, broken builds). Do **not** flag\",\n          \"  when CI self-mutates the PR and the follow-up run passes — for example,\",\n          \"  lint auto-fixes, formatter commits, or snapshot/lockfile updates pushed\",\n          \"  by CI. Those are expected self-healing behaviors, not failures.\",\n          \"\",\n          \"An issue must always carry exactly one of `status:ready`, `status:blocked`,\",\n          \"`status:in-progress`, `status:ready-for-review`, or `status:done`. The\",\n          \"`status:needs-attention` label is additive — it coexists with whichever of\",\n          \"those five applies.\",\n        ].join(\"\\n\"),\n        tags: [\"workflow\"],\n      },\n      {\n        name: \"monorepo-layout\",\n        description:\n          \"Canonical monorepo top-level folders (docs, apps, packages, sites), the @ownerscope/<name> scoping rule, the docs-singleton carve-out, and the scaffolding skills that place new sub-projects\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Monorepo Layout\",\n          \"\",\n          \"Every monorepo built with `@codedrifters/configulator` uses a single,\",\n          \"fixed top-level folder layout. Agents, scaffolding skills, pnpm-workspace\",\n          \"globs, Turbo filters, and CI cache keys all assume these roots.\",\n          \"\",\n          \"## Four Canonical Top-Level Folders\",\n          \"\",\n          \"| Folder | Purpose | Examples |\",\n          \"|--------|---------|----------|\",\n          \"| `/docs` | **Single** Starlight site covering the entire monorepo. The one site that lives outside `/sites`. | Monorepo-wide developer docs, ADRs, how-to guides. |\",\n          \"| `/apps/@scope/<name>` | Deployable applications — anything that runs or ships as a running process. | AWS CDK stacks, mobile apps (iOS/Android), backend services. |\",\n          \"| `/packages/@scope/<name>` | Shared libraries — published npm packages and workspace-internal libraries. | `@codedrifters/configulator`, `@codedrifters/constructs`, `@codedrifters/utils`. |\",\n          \"| `/sites/@scope/<name>` | User-facing web front ends that are **not** the monorepo-wide docs site. | Marketing sites, SPAs, per-client static sites. |\",\n          \"\",\n          \"No other top-level folder is part of this contract. Generated roots\",\n          \"(`.projen/`, `.github/`, `node_modules/`, `.turbo/`, etc.) are orthogonal\",\n          \"and unchanged.\",\n          \"\",\n          \"## Scoping Rule\",\n          \"\",\n          \"Every sub-project under `apps/`, `packages/`, or `sites/` is named\",\n          \"`@ownerscope/<name>`, where **scope is the owning party** (not a category).\",\n          \"\",\n          \"- `@codedrifters/configulator` — a shared library owned by CodeDrifters → `packages/@codedrifters/configulator`\",\n          \"- `@codedrifters/infrastructure-stack` — an AWS CDK app owned by CodeDrifters → `apps/@codedrifters/infrastructure-stack`\",\n          \"- `@clientA/iphone-app` — a mobile app owned by Client A → `apps/@clientA/iphone-app`\",\n          \"- `@clientB/marketing-site` — a marketing site owned by Client B → `sites/@clientB/marketing-site`\",\n          \"\",\n          \"The scope identifies **who owns the sub-project**, not what kind of\",\n          \"sub-project it is. Kind is captured by the top-level folder (`apps/`,\",\n          \"`packages/`, `sites/`). Never scope by category (e.g. `@apps/foo`,\",\n          \"`@libs/bar`) — the top-level folder already carries that information.\",\n          \"\",\n          \"## Docs-Singleton Carve-Out\",\n          \"\",\n          \"There is **exactly one** Starlight docs site per monorepo, and it lives\",\n          \"at `/docs`. It is **not** `sites/@scope/docs`.\",\n          \"\",\n          \"- The docs site is monorepo-wide. Sub-project documentation belongs\",\n          `  inside that single site (under \\`${paths.docsRoot}/\\`), not in a`,\n          \"  per-package `docs/` folder.\",\n          \"- Configulator's `StarlightProject` defaults its `outdir` to `/docs` and\",\n          '  its `role` to `\"docs\"`. A second `StarlightProject` with `role: \"docs\"`',\n          \"  fails synth — the singleton rule is enforced at validate time.\",\n          \"- Additional Starlight sites (client-facing, marketing, etc.) must set\",\n          '  `role: \"site\"`, which routes them under `sites/<scope>/<name>` just',\n          \"  like a plain `AstroProject`.\",\n          \"- `/sites` is reserved for end-user-facing web front ends (marketing\",\n          \"  sites, SPAs, client-facing apps). It deliberately does not host the\",\n          \"  dev-docs site.\",\n          \"\",\n          \"## Project-Type → `outdir` Mapping\",\n          \"\",\n          \"Configulator project types default their `outdir` according to the\",\n          \"following table. Override `outdir` explicitly only when you have a\",\n          \"genuine reason — the defaults cover the common path.\",\n          \"\",\n          \"| Configulator project type | Default `outdir` |\",\n          \"|---------------------------|------------------|\",\n          \"| `TypeScriptProject` | `packages/<scope>/<name>` |\",\n          \"| `AwsCdkProject` | `apps/<scope>/<name>` |\",\n          \"| `AstroProject` | `sites/<scope>/<name>` |\",\n          \"| `StarlightProject` (role = docs, default) | `docs/` |\",\n          \"| `StarlightProject` (role = site) | `sites/<scope>/<name>` |\",\n          \"\",\n          \"`<scope>` is parsed from the sub-project's package name (everything\",\n          \"after `@` and before `/`). `<name>` is the unscoped part of the\",\n          \"package name.\",\n          \"\",\n          \"## Placing New Sub-Projects\",\n          \"\",\n          \"Never hand-roll a sub-project path. Use one of the scaffolding skills,\",\n          \"which take `@scope/<name>` as input, validate it, and place the new\",\n          \"project in the correct folder:\",\n          \"\",\n          \"- `/create-package` — scaffolds a new `TypeScriptProject` under `packages/<scope>/<name>`\",\n          \"- `/create-app` — scaffolds a new `AwsCdkProject` under `apps/<scope>/<name>`\",\n          \"- `/create-site` — scaffolds a new `AstroProject` under `sites/<scope>/<name>`\",\n          \"\",\n          \"The monorepo-wide docs site at `/docs` is a singleton and is created\",\n          \"once per repo via `StarlightProject` — it is not scaffolded per\",\n          \"sub-project.\",\n        ].join(\"\\n\"),\n        tags: [\"project\"],\n      },\n      {\n        name: \"source-quality-verification\",\n        description:\n          \"Source tier hierarchy (T1–T4), conflict resolution, temporal validity, and source-annotation format for research-producing agents\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Source Quality & Verification\",\n          \"\",\n          \"All research-producing agents must follow this source hierarchy when\",\n          \"writing profiles and reference documents. The tiers govern which\",\n          \"source to prefer when claims conflict and when time-sensitive claims\",\n          \"need re-verification.\",\n          \"\",\n          \"## Source Tier Hierarchy\",\n          \"\",\n          \"### T1 — Primary Living\",\n          \"\",\n          \"Authoritative sources that update when reality changes.\",\n          \"Use these for current-state claims. Examples:\",\n          \"\",\n          \"- Official product docs and API references\",\n          \"- Company about / leadership / team pages\",\n          \"- Live government registries (SEC EDGAR, Companies House)\",\n          \"- Current-role LinkedIn profiles\",\n          \"- Investor relations pages\",\n          \"\",\n          \"### T2 — Primary Snapshot\",\n          \"\",\n          \"Authoritative but time-stamped sources straight from the subject.\",\n          \"Trust for current state only when fresh (< 6 months) and no T1\",\n          \"source contradicts them. Examples:\",\n          \"\",\n          \"- Press releases from the entity\",\n          \"- Earnings transcripts and investor calls\",\n          \"- Regulatory filings (10-K, 10-Q, 8-K)\",\n          \"- Official announcements and conference presentations\",\n          \"\",\n          \"### T3 — Secondary\",\n          \"\",\n          \"Third-party sources that interpret or re-report primary material.\",\n          \"Good for context and triangulation; T1 wins on conflict. Examples:\",\n          \"\",\n          \"- News articles and trade press\",\n          \"- Industry reports and analyst research\",\n          \"- Database aggregators (Crunchbase, PitchBook, Owler)\",\n          \"\",\n          \"### T4 — Self-Reported / Marketing\",\n          \"\",\n          \"Promotional or unverified sources. Use for discovery and leads only\",\n          \"— never as the sole source for a factual claim, and always note the\",\n          \"self-reported nature in the annotation. Examples:\",\n          \"\",\n          \"- Vendor comparison pages and customer testimonials on vendor sites\",\n          \"- Social-media posts\",\n          \"- Job postings\",\n          \"- Wikipedia\",\n          \"\",\n          \"## Conflict Resolution\",\n          \"\",\n          \"Higher tier wins. Within the same tier, more recent wins. If a newer\",\n          \"T2 source contradicts an older T1 source on a time-sensitive claim,\",\n          \"flag for re-verification — the T1 source may simply not have been\",\n          \"updated yet.\",\n          \"\",\n          \"## Temporal Validity\",\n          \"\",\n          \"Some claims decay faster than others. When a fast-decay claim comes\",\n          \"from a source older than 6 months, agents **must** attempt to\",\n          \"corroborate it with a T1 living source. If no T1 source is available,\",\n          \"add an inline note: `_(source: YYYY-MM, may need re-verification)_`.\",\n          \"\",\n          \"| Decay | Re-verify if source older than | Typical claims |\",\n          \"|-------|-------------------------------|----------------|\",\n          \"| **Fast** | 6 months | Leadership roles, employee count, pricing, product features, funding status, office locations |\",\n          \"| **Slow** | 18 months | Founding year, ownership structure, core business description, industry classification, HQ location |\",\n          \"| **Stable** | Verify once, note source date | Historical facts (acquisition dates, founding story), published financials for a specific period |\",\n          \"\",\n          \"## Source Annotation Format\",\n          \"\",\n          \"In the `## Sources` section of profiles and reference documents,\",\n          \"annotate each source with its tier and date:\",\n          \"\",\n          \"```\",\n          \"1. [Company Leadership Page](https://...) — T1, accessed 2026-04\",\n          \"2. [Company press release](https://...) — T2, published 2026-02\",\n          \"3. [TechCrunch coverage](https://...) — T3, published 2025-11\",\n          \"```\",\n          \"\",\n          \"Use `accessed YYYY-MM` for living sources (T1) and `published YYYY-MM`\",\n          \"for snapshot sources (T2, T3, T4).\",\n        ].join(\"\\n\"),\n        tags: [\"workflow\"],\n      },\n      {\n        name: \"issue-conventions\",\n        description:\n          \"Issue title prefixes, GitHub issue type mapping, prerequisite issues\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Issue Title Conventions\",\n          \"\",\n          \"## Format\",\n          \"\",\n          \"```\",\n          \"<type>: <description>\",\n          \"```\",\n          \"\",\n          \"## Types\",\n          \"\",\n          \"| Prefix | Use for |\",\n          \"|--------|---------|\",\n          \"| `epic:` | Large initiatives spanning multiple child issues |\",\n          \"| `feat:` | New features or functionality |\",\n          \"| `fix:` | Bug fixes |\",\n          \"| `chore:` | Maintenance: deps, tooling, config |\",\n          \"| `docs:` | Documentation-only work |\",\n          \"| `refactor:` | Code restructure, no behavior change |\",\n          \"| `release:` | Release preparation, version bumps |\",\n          \"| `hotfix:` | Urgent production fixes |\",\n          \"\",\n          ...renderGithubIssueTypeSectionLines(),\n          \"\",\n          \"## Prerequisite Issues\",\n          \"\",\n          \"Include any prerequisite (blocking) issues in the issue body when they exist.\",\n          \"Use a **Dependencies** section or `**Depends on:** #123`.\",\n        ].join(\"\\n\"),\n        tags: [\"workflow\"],\n      },\n      {\n        name: \"progress-file-convention\",\n        description:\n          \"Progress-file schema and write rules, partial-resume protocol, stale-branch decision tree, and [BLOCKED] comment format that let phased agents survive crashes without losing work.\",\n        scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n        // Bundle defaults exclude paths into configulator's own source\n        // (only meaningful when configulator is a workspace package,\n        // i.e. in codedrifters/packages itself). That repo restores\n        // them via `agentConfig.additionalRulePaths`; other consumers\n        // get a clean default.\n        filePatterns: [\".claude/agents/*.md\", \".claude/procedures/**\"],\n        content: renderProgressFilesRuleContent(conventions.progressFiles),\n        platforms: {\n          cursor: { exclude: true },\n        },\n        tags: [\"workflow\"],\n      },\n      {\n        name: \"shared-editing-safety\",\n        description:\n          \"Shared-editing safety: single-entry deterministic-sort inserts on index files, commit-path verification, and the merge-conflict resolution recipe that keeps concurrent agent sessions from dropping each other's rows on shared registries and feature matrices.\",\n        scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n        filePatterns: DEFAULT_SHARED_INDEX_PATHS,\n        content: renderSharedEditingRuleContent(conventions.sharedEditing),\n        platforms: {\n          cursor: { exclude: true },\n        },\n        tags: [\"workflow\"],\n      },\n      {\n        name: \"temporal-framing-convention\",\n        description:\n          \"Temporal-framing convention: every agent-authored time-sensitive factual claim (ownership, leadership tenure, regulatory status, litigation, dated metrics) carries an inline `as of [YYYY-MM-DD]` or `as of [Month YYYY]` qualifier on first occurrence so refresh agents have a mechanical signal for which claims to re-verify.\",\n        scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n        filePatterns: [\n          \"docs/src/content/docs/profiles/**/*.md\",\n          \"docs/src/content/docs/industry-research/**/*.md\",\n          \"docs/src/content/docs/software-research/**/*.md\",\n          \"docs/src/content/docs/regulatory-research/**/*.md\",\n          \"docs/src/content/docs/standards-research/**/*.md\",\n          \"docs/src/content/docs/customer-research/**/*.md\",\n        ],\n        content: renderTemporalFramingRuleContent(conventions.temporalFraming),\n        platforms: {\n          cursor: { exclude: true },\n        },\n        tags: [\"workflow\"],\n      },\n      {\n        name: \"skill-evals\",\n        description:\n          \"Skill eval harness contract: declarative prompt/expected-output regression suites per skill at `<skillsRoot>/<skill-name>/evals/evals.json`, parameterised by a shared product-context fixture so the same eval shape works across every configulator-consuming project without forking fixtures.\",\n        scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n        // Bundle defaults exclude paths into configulator's own\n        // source — see comment on progress-file-convention above.\n        filePatterns: [\".claude/skills/**\"],\n        content: renderSkillEvalsRuleContent(conventions.skillEvals),\n        platforms: {\n          cursor: { exclude: true },\n        },\n        tags: [\"workflow\"],\n      },\n      {\n        name: \"issue-templates-convention\",\n        description: `Issue-templates convention: a single hand-authored reference page under \\`${paths.docsRoot}/agents/issue-templates.md\\` that carries one canonical \\`gh issue create\\` recipe per downstream phase label, and the reference-don't-inline rule that keeps bundle rules and agent prompts citing that page instead of duplicating full template invocations.`,\n        scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n        // Bundle defaults exclude paths into configulator's own\n        // source — see comment on progress-file-convention above.\n        filePatterns: [\n          \".claude/skills/**/SKILL.md\",\n          \".claude/agents/*.md\",\n          `${paths.docsRoot}/agents/issue-templates.md`,\n        ],\n        content: renderIssueTemplatesRuleContent(\n          conventions.issueTemplates,\n          conventions.hasDownstreamIssueKindBundles,\n        ),\n        platforms: {\n          cursor: { exclude: true },\n        },\n        tags: [\"workflow\"],\n      },\n    ],\n  };\n}\n\n/**\n * Default-paths instance of the base bundle, preserved for backward\n * compatibility with consumers that import the const directly. The\n * factory above is the canonical entry point when a consumer supplies\n * `AgentConfigOptions.paths`.\n */\nexport const baseBundle: AgentRuleBundle = buildBaseBundle();\n","/**\n * Shared \"Issue closing\" section for every phased worker/analyst\n * bundle (codedrifters/packages#921).\n *\n * Every phased bundle's agent loop already defers the close to the\n * consumer — *\"Commit, push, open a PR (if applicable), and close the\n * issue per your project's PR workflow.\"* The per-phase steps used to\n * drop that qualifier and say \"Close the research issue.\" flat, which\n * contradicts the loop: in any consumer whose PR body carries a closing\n * keyword (`Closes #<n>`), the phase-end close fires **before** the PR\n * merges, so the keyword no-ops and the issue leaves the `status:*`\n * state machine early.\n *\n * The rule is rendered identically into every phased prompt via\n * {@link renderIssueClosePolicySection}, and each per-phase step defers\n * to it with {@link ISSUE_CLOSE_RULE_REFERENCE}, so the guidance cannot\n * drift per-bundle again — the same pattern the claim-verification,\n * project-context, and progress-file sections use.\n */\n\n/**\n * Heading of the shared section, without the markdown `##` prefix.\n * Exported so the per-step reference and any test assert against one\n * string.\n */\nexport const ISSUE_CLOSE_SECTION_TITLE = \"Issue closing\";\n\n/**\n * Clause a per-phase step appends when it tells the agent to close its\n * own issue. Points at the shared section instead of restating it.\n *\n * @example\n * `7. **Commit and push** the notes file. Close the research issue ${ISSUE_CLOSE_RULE_REFERENCE}.`\n */\nexport const ISSUE_CLOSE_RULE_REFERENCE = `per the **${ISSUE_CLOSE_SECTION_TITLE}** rule`;\n\n/**\n * Render the shared `## Issue closing` section as prompt lines. Spread\n * into a sub-agent `prompt` array with\n * `...renderIssueClosePolicySection()`.\n */\nexport function renderIssueClosePolicySection(): ReadonlyArray<string> {\n  return [\n    `## ${ISSUE_CLOSE_SECTION_TITLE}`,\n    \"\",\n    \"**Never close a phase issue that your PR is going to close for**\",\n    \"**you.** Most projects put a closing keyword (`Closes #<n>`) in the\",\n    \"PR body, so the issue closes when the PR merges — and that merge is\",\n    \"what drives the documented `status:ready-for-review` →\",\n    \"`status:done` transition.\",\n    \"\",\n    \"Closing the issue yourself at the end of a phase pre-empts all of\",\n    \"that:\",\n    \"\",\n    \"- the PR's `Closes #<n>` line becomes a no-op — nothing happens at\",\n    \"  merge time;\",\n    \"- the issue closes while still carrying `status:in-progress` or\",\n    \"  `status:ready-for-review`, so its labels describe a state it has\",\n    \"  already left;\",\n    \"- any caller that applies a status label afterwards is labelling a\",\n    \"  closed issue, and a caller that verifies workflow state has to\",\n    \"  reopen the issue to put it back in the pipeline.\",\n    \"\",\n    \"So whenever a phase step tells you to close its issue, resolve it\",\n    \"against your project's PR workflow first:\",\n    \"\",\n    \"1. **The PR closes it.** Your PR body carries `Closes #<n>` for this\",\n    \"   issue — commit, push, open the PR, and leave the issue **open**.\",\n    \"   Post the phase outcome the step asks for as an ordinary comment\",\n    \"   on the issue, not as a closing comment, and let the merge perform\",\n    \"   the close.\",\n    \"2. **The PR does not close it.** There is no closing keyword for\",\n    \"   this issue, or the phase lands no PR at all — close the issue\",\n    \"   yourself, with the outcome comment the step describes.\",\n    \"\",\n    \"### Always close directly\",\n    \"\",\n    \"Two cases never wait on a merge:\",\n    \"\",\n    \"- **Aborts.** A phase that stops without a deliverable — nothing\",\n    \"  relevant found, a duplicate, an ambiguity handed off with\",\n    \"  `status:needs-attention` — closes its issue directly. No PR will\",\n    \"  ever reference it.\",\n    \"- **Someone else's issue.** Closing an issue other than the one you\",\n    \"  are working (a parent issue your phase resolves, a superseded\",\n    \"  sibling) is bookkeeping, not the workflow close. A closing keyword\",\n    \"  only ever covers the issues your PR body names.\",\n  ];\n}\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { renderClaimVerificationSection } from \"./claim-verification\";\nimport {\n  ISSUE_CLOSE_RULE_REFERENCE,\n  ISSUE_CLOSE_SECTION_TITLE,\n  renderIssueClosePolicySection,\n} from \"./issue-close\";\nimport {\n  DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n  ResolvedIssueDefaults,\n  labelsForPhase,\n} from \"./issue-defaults\";\nimport { renderIssueTypeAssignmentStep } from \"./issue-type\";\nimport { renderOriginStampSection } from \"./origin-label\";\nimport { DEFAULT_AGENT_PATHS, ResolvedAgentPaths } from \"./paths\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n  AGENT_MODEL,\n  AGENT_RULE_SCOPE,\n  AgentSkill,\n  AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that authors BCM (Business Capability Model) capability-model\n * documents through a 4-phase state machine (outline → scaffold →\n * context → connect). Each phase runs in its own session with narrow\n * file/section ownership so every session stays well under context\n * limits.\n *\n * This agent writes **capability-model documents** — structured\n * descriptions of a business capability with BIZBOK-aligned attributes\n * (Capability Definitions, Sub-Capabilities, Roles Involved, Company\n * Size Applicability, Enabling Software Systems, Value Stream Mapping,\n * Project Relevance, Traceability, Revision History, Heat Map Rating).\n * It is **not** a requirements-document writer — requirements are the\n * responsibility of the downstream requirements-writer agent.\n */\nfunction buildBcmWriterSubAgent(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSubAgent {\n  return {\n    name: \"bcm-writer\",\n    description:\n      \"Writes BCM (Business Capability Model) capability-model documents through a 4-phase pipeline (outline → scaffold → context → connect), one phase per session, tracked by bcm:* GitHub issue labels with filesystem-based durability between phases. Produces BIZBOK-aligned capability documents — not requirement documents.\",\n    model: AGENT_MODEL.POWERFUL,\n    maxTurns: 80,\n    platforms: { cursor: { exclude: true } },\n    prompt: [\n      \"# BCM Writer Agent\",\n      \"\",\n      \"You author BCM (Business Capability Model) capability-model documents\",\n      \"through a structured 4-phase state machine. Each phase runs as its\",\n      \"**own agent session**, triggered by a GitHub issue with a `bcm:*`\",\n      \"phase label. You handle exactly **one phase per session** — read the\",\n      \"issue to determine which phase to execute.\",\n      \"\",\n      \"This agent produces **BCM capability-model documents** — structured\",\n      \"descriptions of a business capability with BIZBOK-aligned attributes\",\n      \"(Capability Definitions, Sub-Capabilities, Roles Involved, Company\",\n      \"Size Applicability, Enabling Software Systems, Value Stream Mapping,\",\n      \"Project Relevance, Traceability, Revision History, Heat Map Rating).\",\n      \"It is **not** a requirements-document writer — requirements are\",\n      \"handled by the downstream requirements-writer agent.\",\n      \"\",\n      \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n      \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...PROJECT_CONTEXT_READER_SECTION,\n      \"## Design Principles\",\n      \"\",\n      \"1. **One phase per session.** Each phase has narrow file/section\",\n      \"   ownership so every session stays well under context limits. Never\",\n      \"   run two phases back-to-back in a single session.\",\n      \"2. **Filesystem durability.** Every phase persists its output to a\",\n      \"   file on disk before closing its issue. Downstream phases read\",\n      \"   those files — never rely on session memory.\",\n      \"3. **Issue graph = state machine.** Phase ordering is encoded with\",\n      \"   `Depends on: #N` links between phase issues. A phase runs only\",\n      \"   after its predecessor is closed.\",\n      \"4. **BIZBOK vocabulary is authoritative.** Capability attributes\",\n      \"   (name-as-noun, business object, definition, outcome, tier, heat\",\n      \"   map rating), L1/L2/L3 decomposition with business-object focus,\",\n      \"   and value stream cross-mapping are preserved verbatim. Only\",\n      \"   *paths* are parameterized; vocabulary is not.\",\n      `5. **Project Relevance comes from \\`${paths.docsRoot}/project-context.md\\`.** The`,\n      \"   Project Relevance section of every BCM document is framed against\",\n      \"   the mission, target users, and in/out-of-scope capabilities\",\n      \"   captured in that file. Never invent project framing.\",\n      \"6. **Write capability models, not requirements.** Discovered\",\n      \"   requirements, research gaps, or unfamiliar people/companies are\",\n      \"   spun off to downstream pipelines via issues (`people:research`,\",\n      \"   `company:research`, `research:scope`) — never inlined as\",\n      \"   requirement documents.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## State Machine Overview\",\n      \"\",\n      \"BCM document authoring flows through **4 phases**:\",\n      \"\",\n      \"```\",\n      \"┌──────────────┐     ┌──────────────┐     ┌──────────────┐     ┌──────────────┐\",\n      \"│ 1. OUTLINE   │────▶│ 2. SCAFFOLD  │────▶│ 3. CONTEXT   │────▶│ 4. CONNECT   │\",\n      \"│ Identify the │     │ Create the   │     │ Fill Project │     │ Cross-link   │\",\n      \"│ capability,  │     │ BCM doc with │     │ Relevance,   │     │ with parent/ │\",\n      \"│ its L1/L2/L3 │     │ BIZBOK       │     │ Value Stream │     │ sibling      │\",\n      \"│ tier, and    │     │ attributes   │     │ Mapping, and │     │ capabilities,│\",\n      \"│ business     │     │ as headings  │     │ Enabling     │     │ registry, &  │\",\n      \"│ object       │     │ + placeholder│     │ Software     │     │ downstream   │\",\n      \"│              │     │ content      │     │ Systems      │     │ pipelines    │\",\n      \"└──────────────┘     └──────────────┘     └──────────────┘     └──────────────┘\",\n      \"```\",\n      \"\",\n      \"**Issue labels encode the phase:**\",\n      \"\",\n      \"| Label | Phase | Session work |\",\n      \"|-------|-------|-------------|\",\n      \"| `bcm:outline` | 1. Outline | Identify the capability (name-as-noun, business object, L1/L2/L3 tier). Write a short outline file in the outline working directory. Create the scaffold issue. |\",\n      \"| `bcm:scaffold` | 2. Scaffold | Create the BCM document with BIZBOK section headings and placeholder content for each attribute. Create the context issue. |\",\n      `| \\`bcm:context\\` | 3. Context | Fill Project Relevance (framed against \\`${paths.docsRoot}/project-context.md\\`), Value Stream Mapping, Enabling Software Systems, Roles Involved, and Company Size Applicability. Create the connect issue. |`,\n      \"| `bcm:connect` | 4. Connect | Cross-link with parent/sibling capabilities, update the capability registry `_index.md` and capability-map file, and open downstream research issues for surfaced people/companies/requirement gaps. |\",\n      \"\",\n      \"All issues also carry `type:bcm-document` and a `status:*` label.\",\n      \"\",\n      \"**Issue count per BCM document:** 1 outline + 1 scaffold + 1 context\",\n      \"+ 1 connect = **4 sessions**, plus `M` downstream issues created by\",\n      \"Phase 4 (`people:research`, `company:research`, `research:scope`),\",\n      \"where `M` is the number of distinct items surfaced during authoring.\",\n      \"\",\n      \"**Shortened paths:**\",\n      \"- **Outline determines the capability is out of scope** (duplicate of\",\n      \"  an existing capability, not a business capability, or clearly not\",\n      `  relevant per \\`${paths.docsRoot}/project-context.md\\`) → outline issue closes with`,\n      \"  a justification and no downstream issues are created → **1\",\n      \"  session**.\",\n      \"- **Scaffold reuses an existing BCM document** (the capability turned\",\n      \"  out to already have a document under `<BCM_DOC_ROOT>`) → scaffold\",\n      \"  issue closes with a pointer to the existing doc and no context or\",\n      \"  connect issues are created → **2 sessions**.\",\n      \"- **Context reveals no project relevance** (the capability exists in\",\n      \"  the taxonomy but is explicitly out of scope per the project context)\",\n      \"  → context fills the BCM with a minimal `## Project Relevance`\",\n      \"  section noting the out-of-scope decision and the connect issue still\",\n      \"  runs (registry update only, no downstream research) → **4 sessions,\",\n      \"  0 downstream issues**.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Configurable Paths\",\n      \"\",\n      \"The pipeline uses these placeholders. Consuming projects override the\",\n      \"defaults by passing paths in the `/write-bcm` skill invocation or by\",\n      \"extending this rule in their own `agentConfig.rules`.\",\n      \"\",\n      \"| Placeholder | Meaning | Default |\",\n      \"|-------------|---------|---------|\",\n      `| \\`<BCM_DOC_ROOT>\\` | Root folder for all BCM capability-model documents | \\`${paths.bcmRoot}/\\` |`,\n      `| \\`<OUTLINE_ROOT>\\` | Working-directory root for outline files produced in Phase 1 | \\`${paths.bcmRoot}/.outlines/\\` |`,\n      \"| `<REGISTRY_INDEX>` | Capability registry `_index.md` file that lists every BCM doc | `<BCM_DOC_ROOT>/_index.md` |\",\n      \"| `<CAPABILITY_MAP>` | Capability-map file that shows the L1/L2/L3 hierarchy | `<BCM_DOC_ROOT>/capability-map.md` |\",\n      \"| `<ENTITY_TAXONOMY>` | Entity-taxonomy / product-context file used for business-object alignment | `docs/product/entity-taxonomy.md` |\",\n      \"| `<BCM_SLUG>` | Short kebab-case slug identifying one BCM capability | derived from the capability name |\",\n      `| \\`<PREFIX>\\` | Optional project-specific BCM ID prefix | derived from \\`${paths.docsRoot}/project-context.md\\` if specified |`,\n      \"\",\n      `If \\`${paths.docsRoot}/project-context.md\\` specifies a different BCM tree, prefer`,\n      \"that. Otherwise fall back to the defaults above.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## BIZBOK Methodology\",\n      \"\",\n      \"This agent uses BIZBOK (Business Architecture Body of Knowledge)\",\n      \"conventions. BIZBOK vocabulary is preserved verbatim — do not rename,\",\n      \"paraphrase, or localize these terms.\",\n      \"\",\n      \"### Capability Attributes\",\n      \"\",\n      \"Every BCM capability-model document captures these BIZBOK attributes:\",\n      \"\",\n      \"| Attribute | Shape | Notes |\",\n      \"|-----------|-------|-------|\",\n      \"| **Name** | Noun or noun phrase | Capabilities are *what the business does*, expressed as nouns — never verbs. Example: `Customer Onboarding`, not `Onboard Customers`. |\",\n      \"| **Business Object** | The thing the capability acts on | Align to the entity taxonomy. Each L3 capability acts on exactly one primary business object. |\",\n      \"| **Definition** | 1–2 sentences | Describes what the capability is and its boundary — not how it is implemented. |\",\n      \"| **Outcome** | 1 sentence | The measurable result the capability produces for the business. |\",\n      \"| **Tier** | `L1` / `L2` / `L3` | L1 = top-level domain, L2 = mid-level grouping, L3 = granular capability that maps to one business object. |\",\n      `| **Heat Map Rating** | \\`critical\\` / \\`high\\` / \\`medium\\` / \\`low\\` | Strategic importance to the business. Sourced from \\`${paths.docsRoot}/project-context.md\\` or the invoking issue — never invented. |`,\n      \"\",\n      \"### L1 / L2 / L3 Decomposition\",\n      \"\",\n      \"- **L1** — top-level business domain (e.g. `Customer Management`).\",\n      \"  Acts on a broad business-object family.\",\n      \"- **L2** — mid-level grouping (e.g. `Customer Onboarding`). Acts on a\",\n      \"  narrower business-object slice.\",\n      \"- **L3** — granular capability (e.g. `Identity Verification`). Acts on\",\n      \"  exactly one primary business object and is the unit that maps to\",\n      \"  requirements, value streams, and enabling software systems.\",\n      \"\",\n      \"Every BCM document declares its tier in the scaffold phase. L3\",\n      \"documents are the most common — L1/L2 documents are summary pages\",\n      \"whose body is a short definition plus links to their child L3\",\n      \"capabilities.\",\n      \"\",\n      \"### Value Stream Mapping\",\n      \"\",\n      \"Each L3 capability maps to one or more **value streams** — end-to-end\",\n      \"sequences of stages that deliver value to a stakeholder. The Value\",\n      \"Stream Mapping section of a BCM document lists:\",\n      \"\",\n      \"- Which value streams invoke this capability\",\n      \"- Which stage(s) of each value stream the capability participates in\",\n      \"- The input/output business objects at each stage\",\n      \"\",\n      \"Value streams are authoritative inputs — they come from\",\n      `\\`${paths.docsRoot}/project-context.md\\`, a dedicated value-stream doc under`,\n      \"`<BCM_DOC_ROOT>`, or the invoking issue. If no value stream is\",\n      \"defined, write a `TODO: value stream not yet defined` placeholder and\",\n      \"flag the context issue with `status:needs-attention`. Never invent\",\n      \"value streams.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Agent Loop\",\n      \"\",\n      \"Run this loop exactly once per session. Never start a second issue.\",\n      \"\",\n      \"1. Claim one open `type:bcm-document` issue using phase priority:\",\n      \"   `bcm:outline` > `bcm:scaffold` > `bcm:context` > `bcm:connect`.\",\n      \"2. Transition `status:ready` → `status:in-progress` and create the\",\n      \"   branch per your project's branch-naming convention.\",\n      \"3. Execute the phase handler that matches the issue's `bcm:*` label.\",\n      \"4. Commit, push, open a PR (if applicable), and close the issue per\",\n      `   your project's PR workflow — see the **${ISSUE_CLOSE_SECTION_TITLE}**`,\n      \"   section below before you close anything yourself.\",\n      \"   Stamp every PR you open with the `origin:agent` label — see the\",\n      \"   **Origin label** section below.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...renderClaimVerificationSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderOriginStampSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderIssueClosePolicySection(),\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 1: Outline (`bcm:outline`)\",\n      \"\",\n      \"**Goal:** Identify the capability (name-as-noun, business object, tier)\",\n      \"and write a short outline file that the scaffold phase will use as its\",\n      \"spec.\",\n      \"\",\n      `**Budget:** Reading the invoking issue, \\`${paths.docsRoot}/project-context.md\\`, the`,\n      \"capability map, the entity taxonomy, and the registry `_index.md`.\",\n      \"Write one outline file. No BCM document is created in this phase.\",\n      \"\",\n      \"**Section ownership:** Only writes under `<OUTLINE_ROOT>/`.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the invoking issue body** for the candidate capability name,\",\n      \"   any proposed tier, and any authoritative references (value streams,\",\n      \"   existing parents/siblings, source meeting, source requirement).\",\n      \"\",\n      `2. **Read \\`${paths.docsRoot}/project-context.md\\`** for mission, in/out-of-scope`,\n      \"   capabilities, domain vocabulary, and any BCM-specific overrides\",\n      \"   (paths, prefix, heat-map inputs).\",\n      \"\",\n      \"3. **Read the registry.** Open `<REGISTRY_INDEX>` and\",\n      \"   `<CAPABILITY_MAP>` to confirm the capability is not already\",\n      \"   documented and to locate its correct parent in the L1/L2/L3\",\n      \"   hierarchy.\",\n      \"\",\n      \"4. **Read the entity taxonomy.** Open `<ENTITY_TAXONOMY>` (if it\",\n      \"   exists) to pick the primary business object the capability acts on.\",\n      \"   If the taxonomy does not name the required entity, flag the outline\",\n      \"   issue with `status:needs-attention` — do not invent entities.\",\n      \"\",\n      \"5. **Derive `<BCM_SLUG>`** — a 3–5 word kebab-case summary of the\",\n      \"   capability name. Ensure the slug is not already in use under\",\n      \"   `<BCM_DOC_ROOT>` or `<OUTLINE_ROOT>`.\",\n      \"\",\n      \"6. **Decide the tier.** L3 by default. L1/L2 only when the invoking\",\n      \"   issue explicitly asks for a summary page.\",\n      \"\",\n      \"7. **Write the outline file** to\",\n      \"   `<OUTLINE_ROOT>/<BCM_SLUG>.outline.md`:\",\n      \"\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"BCM Outline: <Capability Name>\"',\n      \"   slug: <BCM_SLUG>\",\n      \"   date: YYYY-MM-DD\",\n      \"   parent_issue: <N>\",\n      \"   tier: L1 | L2 | L3\",\n      \"   ---\",\n      \"\",\n      \"   ## Capability Name\",\n      \"   <noun or noun phrase — never a verb>\",\n      \"\",\n      \"   ## Business Object\",\n      \"   <entity from <ENTITY_TAXONOMY> this capability acts on>\",\n      \"\",\n      \"   ## Tier\",\n      \"   L1 | L2 | L3\",\n      \"\",\n      \"   ## Parent Capability\",\n      \"   <slug of the L(n-1) parent, or `none` for L1>\",\n      \"\",\n      \"   ## Sibling Capabilities\",\n      \"   <list of sibling slugs, if any>\",\n      \"\",\n      \"   ## Proposed Definition\",\n      \"   <1–2 sentences describing what the capability is>\",\n      \"\",\n      \"   ## Proposed Outcome\",\n      \"   <1 sentence on the measurable result>\",\n      \"\",\n      \"   ## Heat Map Rating\",\n      \"   critical | high | medium | low (source: <where rating came from>)\",\n      \"\",\n      \"   ## Open Questions\",\n      \"   <anything the scaffold phase needs a human to resolve first>\",\n      \"   ```\",\n      \"\",\n      \"8. **Decide the shortened path.** If the capability is out of scope,\",\n      \"   a duplicate, or not actually a business capability, close the\",\n      \"   outline issue with a justification comment and do **not** create a\",\n      \"   scaffold issue.\",\n      \"\",\n      \"9. **Otherwise, create one `bcm:scaffold` issue** with\",\n      \"   `Depends on: #<outline-issue>`. Its body references the outline\",\n      \"   file path.\",\n      \"\",\n      \"10. **Commit and push** the outline file. Close the outline issue\",\n      `    ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 2: Scaffold (`bcm:scaffold`)\",\n      \"\",\n      \"**Goal:** Create the BCM capability-model document with BIZBOK section\",\n      \"headings and placeholder content for each attribute.\",\n      \"\",\n      \"**Budget:** Reading the outline file and the scaffold template. Write\",\n      \"one BCM document. No research or cross-linking yet.\",\n      \"\",\n      \"**Section ownership:** Writes the complete BCM document under\",\n      \"`<BCM_DOC_ROOT>/` but fills only the structural attributes (Capability\",\n      \"Definitions, Sub-Capabilities, Heat Map Rating from the outline, Tier,\",\n      \"Business Object, Revision History). Leaves Project Relevance, Value\",\n      \"Stream Mapping, Enabling Software Systems, Roles Involved, and Company\",\n      \"Size Applicability as placeholder sections for the context phase.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the outline file** referenced in the issue body.\",\n      \"\",\n      \"2. **Shortened path: existing document.** Before writing, confirm\",\n      \"   `<BCM_DOC_ROOT>/<BCM_SLUG>.md` does not already exist. If it does,\",\n      \"   comment on the scaffold issue with a link to the existing doc and\",\n      \"   close both the scaffold issue and any pending context/connect\",\n      \"   issues — do not create downstream issues.\",\n      \"\",\n      \"3. **Write the BCM document** to `<BCM_DOC_ROOT>/<BCM_SLUG>.md`:\",\n      \"\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"<Capability Name>\"',\n      \"   slug: <BCM_SLUG>\",\n      \"   tier: L1 | L2 | L3\",\n      \"   business_object: <entity>\",\n      \"   parent: <parent-slug or `none`>\",\n      \"   heat_map: critical | high | medium | low\",\n      \"   date: YYYY-MM-DD\",\n      \"   ---\",\n      \"\",\n      \"   ## Capability Definitions\",\n      \"   <1–2 sentences from the outline's Proposed Definition, refined>\",\n      \"\",\n      \"   **Outcome:** <1 sentence from the outline's Proposed Outcome>\",\n      \"\",\n      \"   **Tier:** L1 | L2 | L3\",\n      \"\",\n      \"   **Business Object:** <entity>\",\n      \"\",\n      \"   **Heat Map Rating:** critical | high | medium | low\",\n      \"\",\n      \"   ## Sub-Capabilities\",\n      \"   <For L1/L2: list of child slugs with 1-line definitions.\",\n      '    For L3: write \"None — this is an L3 leaf capability.\">',\n      \"\",\n      \"   ## Roles Involved\",\n      \"   TODO: filled in Phase 3 (Context).\",\n      \"\",\n      \"   ## Company Size Applicability\",\n      \"   TODO: filled in Phase 3 (Context).\",\n      \"\",\n      \"   ## Enabling Software Systems\",\n      \"   TODO: filled in Phase 3 (Context).\",\n      \"\",\n      \"   ## Value Stream Mapping\",\n      \"   TODO: filled in Phase 3 (Context).\",\n      \"\",\n      \"   ## Project Relevance\",\n      `   TODO: filled in Phase 3 (Context) from ${paths.docsRoot}/project-context.md.`,\n      \"\",\n      \"   ## Traceability\",\n      \"   - **Parent capability:** <parent-slug or `none`>\",\n      \"   - **Sibling capabilities:** <sibling slugs>\",\n      \"   - **Source outline:** <OUTLINE_ROOT>/<BCM_SLUG>.outline.md\",\n      \"\",\n      \"   ## Revision History\",\n      \"   | Date | Phase | Change |\",\n      \"   |------|-------|--------|\",\n      \"   | YYYY-MM-DD | scaffold | Initial scaffold from outline |\",\n      \"   ```\",\n      \"\",\n      \"4. **Create one `bcm:context` issue** with\",\n      \"   `Depends on: #<scaffold-issue>`. Its body references the BCM\",\n      \"   document path and the outline file path.\",\n      \"\",\n      \"5. **Commit and push** the BCM document. Close the scaffold issue\",\n      `   ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 3: Context (`bcm:context`)\",\n      \"\",\n      \"**Goal:** Fill the context-specific sections of the BCM document —\",\n      \"Project Relevance, Value Stream Mapping, Enabling Software Systems,\",\n      \"Roles Involved, and Company Size Applicability — and append a\",\n      \"revision-history entry.\",\n      \"\",\n      `**Budget:** Read the scaffold, \\`${paths.docsRoot}/project-context.md\\`, the value`,\n      \"stream source, and the entity taxonomy. Targeted research only —\",\n      \"enough to fill each section with cited facts. Do not open downstream\",\n      \"issues in this phase; that is Phase 4's job.\",\n      \"\",\n      \"**Section ownership:** Replaces the `TODO:` placeholder contents of\",\n      \"these BCM sections:\",\n      \"- `## Roles Involved`\",\n      \"- `## Company Size Applicability`\",\n      \"- `## Enabling Software Systems`\",\n      \"- `## Value Stream Mapping`\",\n      \"- `## Project Relevance`\",\n      \"\",\n      \"Appends one row to `## Revision History`. Touches no other sections.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the scaffolded BCM document** referenced in the issue body.\",\n      \"\",\n      `2. **Read \\`${paths.docsRoot}/project-context.md\\`** for mission, target users,`,\n      \"   in/out-of-scope capabilities, and key stakeholders — this is the\",\n      \"   authoritative source for the Project Relevance section.\",\n      \"\",\n      \"3. **Resolve the value stream.** Find the value-stream source named in\",\n      \"   the outline or the issue body. If none is provided, check\",\n      `   \\`${paths.docsRoot}/project-context.md\\` and \\`<BCM_DOC_ROOT>\\` for a value-stream`,\n      \"   doc. If still unresolved, write a `TODO: value stream not yet\",\n      \"   defined` placeholder and flag the context issue with\",\n      \"   `status:needs-attention`.\",\n      \"\",\n      \"4. **Fill `## Roles Involved`.** List the business roles that invoke,\",\n      \"   own, or are accountable for this capability. Cite the source (an\",\n      \"   org chart, a stakeholders section, or a meeting note). Unknown\",\n      \"   roles get a `TODO:` placeholder and a note.\",\n      \"\",\n      \"5. **Fill `## Company Size Applicability`.** Indicate whether this\",\n      \"   capability applies to `small`, `medium`, `large`, or `enterprise`\",\n      \"   organizations, with a one-line rationale each. Source from\",\n      `   \\`${paths.docsRoot}/project-context.md\\` target users when possible.`,\n      \"\",\n      \"6. **Fill `## Enabling Software Systems`.** List the software systems\",\n      \"   (internal or external) that enable this capability. Reference\",\n      \"   existing software profiles under `<BCM_DOC_ROOT>/../software/` or\",\n      \"   equivalent. Unknown systems get a `TODO:` marker — do not invent.\",\n      \"\",\n      \"7. **Fill `## Value Stream Mapping`.** For each value stream that\",\n      \"   invokes this capability, list the stage(s), input business object,\",\n      \"   and output business object. Example row:\",\n      \"\",\n      \"   ```markdown\",\n      \"   | Value Stream | Stage | Input | Output |\",\n      \"   |--------------|-------|-------|--------|\",\n      \"   | <name> | <stage> | <input entity> | <output entity> |\",\n      \"   ```\",\n      \"\",\n      \"8. **Fill `## Project Relevance`.** Frame the capability against\",\n      `   \\`${paths.docsRoot}/project-context.md\\`:`,\n      \"   - Which in-scope capability does this match (or overlap with)?\",\n      \"   - Which mission pillar does it support?\",\n      \"   - Which target-user role benefits from it?\",\n      \"   - Is it explicitly in scope, out of scope, or ambiguous? If\",\n      \"     out-of-scope, record the justification and keep the section\",\n      \"     minimal — the BCM document still exists as a taxonomy reference,\",\n      \"     but Phase 4 will not create downstream research issues.\",\n      \"\",\n      \"9. **Append a `## Revision History` row:**\",\n      \"\",\n      \"   ```markdown\",\n      \"   | YYYY-MM-DD | context | Filled Project Relevance, Value Stream Mapping, Enabling Software Systems, Roles Involved, Company Size Applicability |\",\n      \"   ```\",\n      \"\",\n      \"10. **Create one `bcm:connect` issue** with\",\n      \"    `Depends on: #<context-issue>`. Its body references the BCM\",\n      \"    document path and lists any people, companies, or software\",\n      \"    systems that surfaced during context work — Phase 4 will convert\",\n      \"    those into downstream issues.\",\n      \"\",\n      \"11. **Commit and push** the updated BCM document. Close the context\",\n      `    issue ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 4: Connect (`bcm:connect`)\",\n      \"\",\n      \"**Goal:** Cross-link the new BCM document with its parent and sibling\",\n      \"capabilities, update the capability registry and capability-map, and\",\n      \"open downstream research issues for items surfaced during authoring.\",\n      \"\",\n      \"**Budget:** No new research. Reading the completed BCM doc, the\",\n      \"registry, and the capability-map. Writing cross-links and creating\",\n      \"downstream issues.\",\n      \"\",\n      \"**Section ownership:** Writes to `<REGISTRY_INDEX>`,\",\n      \"`<CAPABILITY_MAP>`, and appends one row to the BCM document's\",\n      \"`## Revision History`. Updates parent/sibling BCM docs only to add\",\n      \"reciprocal cross-links in their `## Traceability` sections.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the completed BCM document** referenced in the issue body.\",\n      \"\",\n      \"2. **Update `<REGISTRY_INDEX>`.** Add a row for the new capability\",\n      \"   (slug, title, tier, heat map rating, business object, link).\",\n      \"\",\n      \"3. **Update `<CAPABILITY_MAP>`.** Insert the new capability under its\",\n      \"   parent at the correct L1/L2/L3 position.\",\n      \"\",\n      \"4. **Add reciprocal cross-links.** For the parent and each sibling\",\n      \"   referenced in the BCM document's `## Traceability` section, open\",\n      \"   their BCM files and append this document's slug to their relevant\",\n      \"   cross-link list. Keep edits surgical — only modify the traceability\",\n      \"   section of sibling/parent docs.\",\n      \"\",\n      \"5. **Create downstream research issues.** For each distinct item\",\n      \"   surfaced during authoring, file one issue against the appropriate\",\n      \"   downstream bundle. Every handoff issue includes a brief scope\",\n      \"   statement, a link back to this BCM document for traceability, and\",\n      \"   a reference to the context-phase output that revealed the item.\",\n      \"\",\n      \"   **Unfamiliar person (role holder, stakeholder).** Hand off to the\",\n      \"   `people-profile` bundle by creating a `people:research` issue.\",\n      \"   The issue must carry:\",\n      \"\",\n      \"   - `type:people-profile`\",\n      \"   - `people:research`\",\n      `   - \\`priority:${labelsForPhase(issueDefaults, \"people:research\").priority}\\``,\n      `   - \\`status:${labelsForPhase(issueDefaults, \"people:research\").status}\\``,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"   **Unfamiliar company (enabling vendor, partner, competitor).**\",\n      \"   Hand off to the `company-profile` bundle by creating a\",\n      \"   `company:research` issue. The issue must carry:\",\n      \"\",\n      \"   - `type:company-profile`\",\n      \"   - `company:research`\",\n      `   - \\`priority:${labelsForPhase(issueDefaults, \"company:research\").priority}\\``,\n      `   - \\`status:${labelsForPhase(issueDefaults, \"company:research\").status}\\``,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"   **Missing research topic (value stream, market sizing, etc.).**\",\n      \"   Hand off to the `research-pipeline` bundle by creating a\",\n      \"   `research:scope` issue. The issue must carry:\",\n      \"\",\n      \"   - `type:research`\",\n      \"   - `research:scope`\",\n      `   - \\`priority:${labelsForPhase(issueDefaults, \"research:scope\").priority}\\``,\n      `   - \\`status:${labelsForPhase(issueDefaults, \"research:scope\").status}\\``,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"   This phase assumes the `people-profile`, `company-profile`, and\",\n      \"   `research-pipeline` bundles are enabled in the consuming project.\",\n      \"   If a bundle is not enabled, flag the connect issue with\",\n      \"   `status:needs-attention` and list the items that could not be\",\n      \"   routed — never invent an alternative label taxonomy.\",\n      \"\",\n      \"6. **Do NOT create requirement issues.** Requirement gaps surfaced\",\n      \"   during BCM authoring are the responsibility of the\",\n      \"   `requirements-analyst` bundle, which scans BCM documents for gaps\",\n      \"   on its own schedule. Never inline requirement documents or open\",\n      \"   `req:*` issues from this pipeline.\",\n      \"\",\n      \"7. **Append a final `## Revision History` row:**\",\n      \"\",\n      \"   ```markdown\",\n      \"   | YYYY-MM-DD | connect | Added to registry and capability map; cross-linked with parent/siblings; opened <N> downstream research issues |\",\n      \"   ```\",\n      \"\",\n      \"8. **Commit and push** the registry update, capability-map update,\",\n      \"   cross-link edits, and BCM-document revision-history row. Close the\",\n      `   connect issue ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Output Boundaries\",\n      \"\",\n      \"This agent writes **only** to:\",\n      \"\",\n      \"- `<OUTLINE_ROOT>/` — outline working files (Phase 1)\",\n      \"- `<BCM_DOC_ROOT>/` — BCM capability-model documents (Phases 2–4)\",\n      \"- `<REGISTRY_INDEX>` — capability registry (Phase 4)\",\n      \"- `<CAPABILITY_MAP>` — capability map (Phase 4)\",\n      \"- Reciprocal cross-links in sibling/parent BCM docs under\",\n      \"  `<BCM_DOC_ROOT>/` (Phase 4, `## Traceability` section only)\",\n      \"\",\n      \"The pipeline produces **BCM capability-model documents**. It does not\",\n      \"write requirement documents, people profiles, company profiles, or\",\n      \"software profiles — those are the responsibility of specialized\",\n      \"downstream agents (`requirements-analyst`, `people-profile-analyst`,\",\n      \"`company-profile-analyst`, `software-profile-analyst`) that pick up\",\n      \"the issues this pipeline creates. Keep this boundary clean so the BCM\",\n      \"writer stays focused on capability modeling.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Rules\",\n      \"\",\n      \"- **One phase per session.** Never run two phases back-to-back.\",\n      \"- **Persist before closing.** Every phase must write its output file\",\n      \"  (or registry/map updates for Phase 4) before closing its issue.\",\n      \"- **BIZBOK vocabulary is verbatim.** Do not rename Capability\",\n      \"  Definitions, Sub-Capabilities, Roles Involved, Company Size\",\n      \"  Applicability, Enabling Software Systems, Value Stream Mapping,\",\n      \"  Project Relevance, Traceability, Revision History, or Heat Map\",\n      \"  Rating. Paths are parameterized; vocabulary is not.\",\n      \"- **Name capabilities as nouns.** Never as verbs. Reject outlines that\",\n      \"  use a verb phrase.\",\n      \"- **Do not invent business objects, value streams, heat-map ratings,\",\n      \"  or roles.** If the source material (entity taxonomy, project\",\n      \"  context, invoking issue) does not supply them, write a `TODO:`\",\n      \"  placeholder and flag `status:needs-attention`.\",\n      \"- **Write capability models, not requirements.** Requirement gaps are\",\n      \"  handed off to the `requirements-analyst` bundle. Never create\",\n      \"  `req:*` issues from this pipeline.\",\n      \"- **Delegate, don't duplicate.** People, companies, and research\",\n      \"  topics surfaced during authoring are sent to downstream pipelines\",\n      \"  via `people:research`, `company:research`, and `research:scope`\",\n      \"  issues — never inlined in the BCM document body.\",\n      \"- **Cite everything.** Every Project Relevance statement, value\",\n      \"  stream row, and role assignment must carry at least one source\",\n      \"  citation.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off a BCM-document authoring cycle. */\nfunction buildWriteBcmSkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"write-bcm\",\n    description:\n      \"Kick off a BCM capability-model document authoring cycle. Creates a bcm:outline issue carrying the capability name and dispatches Phase 1 (Outline) in the bcm-writer agent.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"bcm-writer\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Write BCM\",\n      \"\",\n      \"Kick off a BCM (Business Capability Model) capability-model document\",\n      \"authoring cycle. Creates a `bcm:outline` issue carrying the candidate\",\n      \"capability name and dispatches Phase 1 (Outline) in the bcm-writer\",\n      \"agent.\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/write-bcm <capability-name>\",\n      \"\",\n      \"Optional extensions in the issue body:\",\n      \"- `tier: L1 | L2 | L3` — override the default (L3)\",\n      \"- `parent: <slug>` — pre-specify the parent capability\",\n      \"- `business_object: <entity>` — pre-specify the primary business\",\n      \"  object\",\n      \"- `heat_map: critical | high | medium | low` — pre-specify the heat\",\n      \"  map rating\",\n      \"- `value_stream: <path or slug>` — pre-specify the value stream\",\n      \"  source\",\n      \"- `slug: <kebab-case>` — override the derived BCM slug\",\n      \"\",\n      \"## Default Paths\",\n      \"\",\n      `If the project has no override in \\`${paths.docsRoot}/project-context.md\\` or`,\n      \"`agentConfig.rules`, outputs land under:\",\n      \"\",\n      `- \\`${paths.bcmRoot}/.outlines/<slug>.outline.md\\` (Phase 1)`,\n      `- \\`${paths.bcmRoot}/<slug>.md\\` (Phases 2–4)`,\n      `- \\`${paths.bcmRoot}/_index.md\\` (Phase 4, registry update)`,\n      `- \\`${paths.bcmRoot}/capability-map.md\\` (Phase 4, capability-map update)`,\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `bcm:outline` issue with `type:bcm-document`,\",\n      `   \\`priority:${labelsForPhase(issueDefaults, \"bcm:outline\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"bcm:outline\").status}\\`. Body must include the`,\n      \"   verbatim capability name and any overrides.\",\n      \"\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 1 (Outline) of the bcm-writer agent.\",\n      \"\",\n      \"3. Phase 1 creates a `bcm:scaffold` issue, which Phase 2 follows with\",\n      \"   `bcm:context`, then Phase 4 (`bcm:connect`). Each downstream issue\",\n      \"   declares its `Depends on:` predecessor. Phase 4 creates downstream\",\n      \"   `people:research`, `company:research`, and `research:scope` issues\",\n      \"   for items surfaced during authoring.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- An outline file under the project's outline working directory\",\n      \"- A BCM capability-model document with BIZBOK attributes populated\",\n      \"- Registry and capability-map entries cross-linked with parent and\",\n      \"  sibling capabilities\",\n      \"- Downstream `people:research`, `company:research`, and\",\n      \"  `research:scope` issues — picked up by the `people-profile`,\",\n      \"  `company-profile`, and `research-pipeline` bundles respectively\",\n    ].join(\"\\n\"),\n  };\n}\n\n/**\n * Build the bcm-writer bundle with the supplied resolved paths.\n *\n * Every reference to a canonical agent path (bcm root, docs root, etc.)\n * inside the rule / skill / sub-agent content strings is an interpolation\n * of the supplied `paths` struct, so a consumer override of\n * `AgentConfigOptions.paths` propagates to the rendered output.\n *\n * Consuming projects can disable it with `excludeBundles: [\"bcm-writer\"]`.\n * `appliesWhen` always returns `true` per this batch's directive that\n * bundles assume peers are present.\n *\n * Ships a single consolidated sub-agent (`bcm-writer`) with all 4 phase\n * handlers in one prompt (outline, scaffold, context, connect), a\n * user-invocable skill (`/write-bcm`), and `type:bcm-document` plus\n * `bcm:*` phase labels.\n *\n * The bundle assumes the `people-profile`, `company-profile`, and\n * `research-pipeline` bundles are also enabled so Phase 4 can hand off\n * surfaced items via `people:research`, `company:research`, and\n * `research:scope` issues.\n */\nexport function buildBcmWriterBundle(\n  paths: ResolvedAgentPaths = DEFAULT_AGENT_PATHS,\n  issueDefaults: ResolvedIssueDefaults = DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n): AgentRuleBundle {\n  return {\n    name: \"bcm-writer\",\n    description:\n      \"BCM (Business Capability Model) capability-model document authoring pipeline: outline, scaffold, context, connect. Enabled by default; BIZBOK-aligned; filesystem-durable between phases.\",\n    appliesWhen: () => true,\n    rules: [\n      {\n        name: \"bcm-writer-workflow\",\n        description:\n          \"Describes the 4-phase BCM-document authoring pipeline, the bcm:* label taxonomy, BIZBOK methodology, and the handoffs to people-profile, company-profile, and research-pipeline bundles.\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# BCM Writer Workflow\",\n          \"\",\n          \"Use `/write-bcm <capability-name>` to kick off a BCM\",\n          \"capability-model document authoring cycle. The pipeline runs in\",\n          \"4 phases — outline, scaffold, context, connect — each tracked by\",\n          \"its own GitHub issue labeled `bcm:outline`, `bcm:scaffold`,\",\n          \"`bcm:context`, or `bcm:connect`. All issues carry\",\n          \"`type:bcm-document`.\",\n          \"\",\n          \"The pipeline produces **BCM capability-model documents** —\",\n          \"structured descriptions of a business capability with\",\n          \"BIZBOK-aligned attributes (Capability Definitions, Sub-Capabilities,\",\n          \"Roles Involved, Company Size Applicability, Enabling Software\",\n          \"Systems, Value Stream Mapping, Project Relevance, Traceability,\",\n          \"Revision History, Heat Map Rating). It is **not** a\",\n          \"requirements-document writer — requirements are handled by the\",\n          \"downstream `requirements-analyst` bundle.\",\n          \"\",\n          \"Items surfaced during authoring (unfamiliar people, companies, or\",\n          \"research topics) are handed off to the `people-profile`,\",\n          \"`company-profile`, and `research-pipeline` bundles via\",\n          \"`people:research`, `company:research`, and `research:scope`\",\n          \"issues.\",\n          \"\",\n          \"See the `bcm-writer` agent definition for full workflow details,\",\n          \"default paths, BIZBOK methodology, and phase-by-phase\",\n          \"instructions.\",\n        ].join(\"\\n\"),\n        platforms: {\n          cursor: { exclude: true },\n        },\n        tags: [\"workflow\"],\n      },\n    ],\n    skills: [buildWriteBcmSkill(paths, issueDefaults)],\n    subAgents: [buildBcmWriterSubAgent(paths, issueDefaults)],\n    labels: [\n      {\n        name: \"type:bcm-document\",\n        color: \"1D76DB\",\n        description:\n          \"Work that produces or maintains a BCM (Business Capability Model) capability-model document\",\n      },\n      {\n        name: \"bcm:outline\",\n        color: \"C5DEF5\",\n        description:\n          \"Phase 1: identify the capability (name-as-noun, business object, tier) and write the outline file\",\n      },\n      {\n        name: \"bcm:scaffold\",\n        color: \"BFDADC\",\n        description:\n          \"Phase 2: create the BCM document with BIZBOK section headings and placeholder content\",\n      },\n      {\n        name: \"bcm:context\",\n        color: \"D4C5F9\",\n        description:\n          \"Phase 3: fill Project Relevance, Value Stream Mapping, Software Systems, Roles, and Company Size\",\n      },\n      {\n        name: \"bcm:connect\",\n        color: \"FEF2C0\",\n        description:\n          \"Phase 4: cross-link parent/siblings, update registry and capability-map, open downstream issues\",\n      },\n    ],\n  };\n}\n\n/**\n * Default-paths instance of the bcm-writer bundle, preserved for\n * backward compatibility with consumers that import the const directly.\n * The factory above is the canonical entry point when a consumer\n * supplies `AgentConfigOptions.paths`.\n */\nexport const bcmWriterBundle: AgentRuleBundle = buildBcmWriterBundle();\n","import {\n  Component,\n  FileBase,\n  JsonFile,\n  Project,\n  SampleDir,\n  SampleFile,\n  Task,\n} from \"projen/lib\";\nimport { BuildWorkflowOptions } from \"projen/lib/build\";\nimport { JobPermission } from \"projen/lib/github/workflows-model\";\nimport { NodeProject } from \"projen/lib/javascript\";\nimport { TurboRepoTask } from \"./turbo-repo-task\";\nimport {\n  TurboRunContinue,\n  TurboRunDryRun,\n  TurboRunLogOrder,\n  TurboRunLogPrefix,\n  TurboRunOutputLogs,\n} from \"./turbo-run-enums\";\nimport { GIT_BRANCH_NAME_ENV, GIT_BRANCH_NAME_ENV_VALUE } from \"../git\";\n\n/*******************************************************************************\n *\n * Turbo Repo Config\n *\n ******************************************************************************/\n\nexport const ROOT_TURBO_TASK_NAME = \"turbo:build\";\nexport const ROOT_CI_TASK_NAME = \"build:all\";\n\nexport interface RemoteCacheOptions {\n  /**\n   * Local profile name to use when fetching the cache endpoint and token.\n   */\n  readonly profileName: string;\n\n  /**\n   * OIDC role to assume when fetching the cache endpoint and token.\n   */\n  readonly oidcRole: string;\n\n  /**\n   * Name for the params used to store the cache endpoint.\n   */\n  readonly endpointParamName: string;\n\n  /**\n   * Name for the params used to store the cache's API token.\n   */\n  readonly tokenParamName: string;\n\n  /**\n   * team name used in remote cache commands\n   */\n  readonly teamName: string;\n}\n\n/**\n * Options for {@link TurboRepo.activateBranchNameEnvVar}.\n *\n * The `tasks` field is required so callers explicitly name every task whose\n * cache hash should include `GIT_BRANCH_NAME`. Scoping the env to a small\n * set of consuming tasks (typically CDK `synth` / `package`) preserves\n * cross-branch cache hits for every other task in the monorepo — library\n * `compile` / `test` / `lint` / `package` runs no longer miss cache just\n * because the branch name changed.\n *\n * The call also populates `GIT_BRANCH_NAME` on the root `build:all` task env\n * so the named tasks hash a real value locally, matching CI.\n */\nexport interface ActivateBranchNameEnvVarOptions {\n  /**\n   * Tasks whose cache hash should include GIT_BRANCH_NAME. Each named task\n   * gets the env added to its `env: []` array. Unknown task names throw at\n   * synth time so typos surface immediately.\n   *\n   * Adding a task to this list is a deliberate cache-hit-rate tradeoff:\n   * the task will miss cache on every branch switch. Only name tasks that\n   * actually read `GIT_BRANCH_NAME` at runtime (e.g. CDK stack-name\n   * generators that bake the branch into resource names).\n   */\n  readonly tasks: Array<string>;\n}\n\n/**\n * CLI flags appended to the `turbo run` invocation in the root `build:all`\n * task and the sibling `reset:all` task. These are command-line *run* flags —\n * distinct from the `turbo.json` config keys on {@link TurboRepoOptions}\n * (`ui`, `cacheDir`, `envMode`, `globalDependencies`,\n * `dangerouslyDisablePackageManagerCheck`), which are written to the config\n * file rather than passed on the command line.\n *\n * Every field defaults to the value currently hard-coded by the component, so\n * omitting `runOptions` reproduces the historical command strings exactly.\n *\n * Targets the `turbo run` surface for Turbo 2.9.18. Flags not modeled here\n * (profiling, experimental OpenTelemetry, operational) stay reachable via\n * {@link TurboRunOptions.additionalArgs}.\n */\nexport interface TurboRunOptions {\n  /**\n   * `--concurrency` — limit concurrent task execution (number or percentage).\n   *\n   * @default 10\n   */\n  readonly concurrency?: string | number;\n\n  /**\n   * `--summarize` — write a run summary under `.turbo/runs`.\n   *\n   * @default true\n   */\n  readonly summarize?: boolean;\n\n  /**\n   * `--cache` — cache behavior, e.g. `\"local:rw\"` or `\"remote:rw\"`. Defaults to\n   * `\"remote:rw\"` when a {@link RemoteCacheOptions} is configured; otherwise no\n   * `--cache` flag is emitted.\n   */\n  readonly cache?: string;\n\n  /**\n   * `--force` — ignore the existing cache and force execution.\n   */\n  readonly force?: boolean;\n\n  /**\n   * `--no-cache` — do not write task results to the cache.\n   */\n  readonly noCache?: boolean;\n\n  /**\n   * `--cache-workers` — number of concurrent cache operations.\n   */\n  readonly cacheWorkers?: number;\n\n  /**\n   * `--continue` — how execution proceeds when a task fails.\n   */\n  readonly continueOn?: TurboRunContinue;\n\n  /**\n   * `--only` — run only the specified tasks, not their dependencies.\n   */\n  readonly only?: boolean;\n\n  /**\n   * `--framework-inference` — toggle framework inference for tasks.\n   */\n  readonly frameworkInference?: boolean;\n\n  /**\n   * `--filter` — package selectors; one `--filter` flag is emitted per entry.\n   */\n  readonly filter?: Array<string>;\n\n  /**\n   * `--affected` — restrict to packages affected vs. the base branch.\n   */\n  readonly affected?: boolean;\n\n  /**\n   * `--output-logs` — task output logging mode.\n   */\n  readonly outputLogs?: TurboRunOutputLogs;\n\n  /**\n   * `--log-order` — ordering of task output.\n   */\n  readonly logOrder?: TurboRunLogOrder;\n\n  /**\n   * `--log-prefix` — task log prefixing mode.\n   */\n  readonly logPrefix?: TurboRunLogPrefix;\n\n  /**\n   * `--dry-run` — print what would run without executing.\n   */\n  readonly dryRun?: TurboRunDryRun;\n\n  /**\n   * Escape hatch: extra raw flags appended verbatim after all modeled flags,\n   * e.g. `[\"--anon-profile=prof.json\", \"--experimental-otel-enabled\"]`. Lets\n   * any current or future `turbo run` flag be passed even when not modeled\n   * above.\n   */\n  readonly additionalArgs?: Array<string>;\n}\n\nexport interface TurboRepoOptions {\n  /**\n   * Version of turborepo to use.\n   *\n   * @default specified in versions file\n   */\n  readonly turboVersion?: string;\n\n  /**\n   * Extend from the root turbo.json to create specific configuration for a package using Package Configurations.\n   *\n   * The only valid value for extends is [\"//\"] to inherit configuration from the root turbo.json.\n   * If extends is used in the root turbo.json, it will be ignored.\n   *\n   * https://turbo.build/repo/docs/reference/configuration#extends\n   */\n  readonly extends?: Array<string>;\n\n  /**\n   * A list of globs that you want to include in all task hashes. If any file matching these globs changes, all tasks will miss cache. Globs are relative to the location of turbo.json.\n   *\n   * By default, all files in source control in the Workspace root are included in the global hash.\n   *\n   * Globs must be in the repository's source control root. Globs outside of the repository aren't supported.\n   *\n   * https://turbo.build/repo/docs/reference/configuration#globaldependencies\n   */\n  readonly globalDependencies?: Array<string>;\n\n  /**\n   * A list of environment variables that you want to impact the hash of all tasks. Any change to these environment variables will cause all tasks to miss cache.\n   *\n   * For more on wildcard and negation syntax, see the env section.\n   *\n   * https://turbo.build/repo/docs/reference/configuration#globalenv\n   */\n  readonly globalEnv?: Array<string>;\n\n  /**\n   * A list of environment variables that you want to make available to tasks.\n   * Using this key opts all tasks into Strict\n   * Environment Variable Mode.\n   *\n   * Additionally, Turborepo has a built-in set of global passthrough variables\n   * for common cases, like operating system environment variables. This\n   * includes variables like HOME, PATH, APPDATA, SHELL, PWD, and more. The full\n   * list can be found in the source code.\n   *\n   * Passthrough values do not contribute to hashes for caching\n   *\n   * If you want changes in these variables to cause cache misses, you will need\n   * to include them in env or globalEnv.\n   *\n   * https://turbo.build/repo/docs/reference/configuration#globalpassthroughenv\n   */\n  readonly globalPassThroughEnv?: Array<string>;\n\n  /**\n   * @default \"stream\"\n   *\n   * Select a terminal UI for the repository.\n   *\n   * \"tui\" allows for viewing each log at once and interacting with the task.\n   * \"stream\" outputs logs as they come in and is not interactive.\n   *\n   * https://turbo.build/repo/docs/reference/configuration#ui\n   */\n  readonly ui?: \"tui\" | \"stream\";\n\n  /**\n   * @default false\n   *\n   * Turborepo uses your repository's lockfile to determine caching behavior,\n   * Package Graphs, and more. Because of this, we use the packageManager field\n   * to help you stabilize your Turborepo.\n   *\n   * To help with incremental migration or in situations where you can't use\n   * the packageManager field, you may use\n   * --dangerously-disable-package-manager-check to opt out of this check and\n   * assume the risks of unstable lockfiles producing unpredictable behavior.\n   * When disabled, Turborepo will attempt a best-effort discovery of the\n   * intended package manager meant for the repository.\n   *\n   * https://turbo.build/repo/docs/reference/configuration#dangerouslydisablepackagemanagercheck\n   */\n  readonly dangerouslyDisablePackageManagerCheck?: boolean;\n\n  /**\n   * @default \".turbo/cache\"\n   *\n   * Specify the filesystem cache directory.\n   *\n   * https://turbo.build/repo/docs/reference/configuration#cachedir\n   */\n  readonly cacheDir?: string;\n\n  /**\n   * @deprecated The `daemon` configuration option is deprecated in Turbo 2.x\n   * and will be removed in Turbo 3.0 — the daemon is no longer used for\n   * `turbo run`. Setting this value has no effect; the key is not emitted\n   * to `turbo.json`. Remove the option from your configulator config.\n   *\n   * https://turbo.build/repo/docs/reference/configuration#daemon\n   */\n  readonly daemon?: boolean;\n\n  /**\n   * @default \"strict\"\n   *\n   * Turborepo's Environment Modes allow you to control which environment\n   * variables are available to a task at runtime:\n   *\n   *\"strict\": Filter environment variables to only those that are specified\n   * in the env and globalEnv keys in turbo.json.\n   *\n   * \"loose\": Allow all environment variables for the process to be available.\n   *\n   * https://turbo.build/repo/docs/reference/configuration#envmode\n   */\n  readonly envMode?: string;\n\n  /**\n   * CLI flags for the `turbo run` invocation in the root `build:all` /\n   * `reset:all` tasks. Defaults preserve the historically hard-coded flags\n   * (`--summarize`, `--concurrency=10`, and the remote-cache flags), so\n   * existing consumers are unaffected.\n   *\n   * @default - `--summarize --concurrency=10` (plus remote-cache flags when `remoteCacheOptions` is set)\n   */\n  readonly runOptions?: TurboRunOptions;\n\n  /*****************************************************************************\n   *\n   * Cache Settings\n   *\n   ****************************************************************************/\n\n  /**\n   * Cache settings, if using remote cache.\n   */\n  readonly remoteCacheOptions?: RemoteCacheOptions;\n\n  /**\n   * Env Args that will bre added to turbo's build:all task\n   *\n   * @default `{}`\n   */\n  readonly buildAllTaskEnvVars?: Record<string, string>;\n\n  /*****************************************************************************\n   *\n   * Tasks - Optionally define a different projen task for one of the lifecycle\n   * steps.\n   *\n   ****************************************************************************/\n\n  /**\n   * Pre compile task\n   *\n   * @default \"pre-compile\"\n   */\n  readonly preCompileTask?: Task;\n\n  /**\n   * Compile task\n   *\n   * @default \"compile\"\n   */\n  readonly compileTask?: Task;\n\n  /**\n   * Post compile task\n   *\n   * @default \"post-compile\"\n   */\n  readonly postCompileTask?: Task;\n\n  /**\n   * Test task\n   *\n   * @default \"test\"\n   */\n  readonly testTask?: Task;\n\n  /**\n   * Package task\n   *\n   * @default \"package\"\n   */\n  readonly packageTask?: Task;\n}\n\nexport class TurboRepo extends Component {\n  /**\n   * Static method to discovert turbo in a project.\n   */\n  public static of(project: Project): TurboRepo | undefined {\n    const isDefined = (c: Component): c is TurboRepo => c instanceof TurboRepo;\n    return project.components.find(isDefined);\n  }\n\n  public static buildWorkflowOptions = (\n    remoteCacheOptions: RemoteCacheOptions,\n  ): Partial<BuildWorkflowOptions> => {\n    return {\n      env: {\n        GIT_BRANCH_NAME: \"${{ github.head_ref || github.ref_name }}\",\n      },\n      permissions: {\n        contents: JobPermission.WRITE,\n        idToken: JobPermission.WRITE,\n      },\n      preBuildSteps: [\n        {\n          name: \"AWS Creds for SSM\",\n          uses: \"aws-actions/configure-aws-credentials@v6\",\n          with: {\n            [\"role-to-assume\"]: remoteCacheOptions.oidcRole,\n            [\"aws-region\"]: \"us-east-1\",\n            [\"role-duration-seconds\"]: \"900\",\n          },\n        },\n      ],\n    };\n  };\n\n  /**\n   * Version of turborepo to use.\n   */\n  public readonly turboVersion: string;\n\n  /**\n   * Extend from the root turbo.json to create specific configuration for a package using Package Configurations.\n   *\n   * The only valid value for extends is [\"//\"] to inherit configuration from the root turbo.json.\n   * If extends is used in the root turbo.json, it will be ignored.\n   *\n   * https://turbo.build/repo/docs/reference/configuration#extends\n   */\n  public readonly extends: Array<string>;\n\n  /**\n   * A list of globs that you want to include in all task hashes. If any file matching these globs changes, all tasks will miss cache. Globs are relative to the location of turbo.json.\n   *\n   * By default, all files in source control in the Workspace root are included in the global hash.\n   *\n   * Globs must be in the repository's source control root. Globs outside of the repository aren't supported.\n   *\n   * https://turbo.build/repo/docs/reference/configuration#globaldependencies\n   */\n  public readonly globalDependencies: Array<string>;\n\n  /**\n   * A list of environment variables that you want to impact the hash of all tasks. Any change to these environment variables will cause all tasks to miss cache.\n   *\n   * For more on wildcard and negation syntax, see the env section.\n   *\n   * https://turbo.build/repo/docs/reference/configuration#globalenv\n   */\n  public readonly globalEnv: Array<string>;\n\n  /**\n   * A list of environment variables that you want to make available to tasks.\n   * Using this key opts all tasks into Strict\n   * Environment Variable Mode.\n   *\n   * Additionally, Turborepo has a built-in set of global passthrough variables\n   * for common cases, like operating system environment variables. This\n   * includes variables like HOME, PATH, APPDATA, SHELL, PWD, and more. The full\n   * list can be found in the source code.\n   *\n   * Passthrough values do not contribute to hashes for caching\n   *\n   * If you want changes in these variables to cause cache misses, you will need\n   * to include them in env or globalEnv.\n   *\n   * https://turbo.build/repo/docs/reference/configuration#globalpassthroughenv\n   */\n  public readonly globalPassThroughEnv: Array<string>;\n\n  /**\n   * @default \"stream\"\n   *\n   * Select a terminal UI for the repository.\n   *\n   * \"tui\" allows for viewing each log at once and interacting with the task.\n   * \"stream\" outputs logs as they come in and is not interactive.\n   *\n   * https://turbo.build/repo/docs/reference/configuration#ui\n   */\n  public readonly ui: \"tui\" | \"stream\";\n\n  /**\n   * @default false\n   *\n   * Turborepo uses your repository's lockfile to determine caching behavior,\n   * Package Graphs, and more. Because of this, we use the packageManager field\n   * to help you stabilize your Turborepo.\n   *\n   * To help with incremental migration or in situations where you can't use\n   * the packageManager field, you may use\n   * --dangerously-disable-package-manager-check to opt out of this check and\n   * assume the risks of unstable lockfiles producing unpredictable behavior.\n   * When disabled, Turborepo will attempt a best-effort discovery of the\n   * intended package manager meant for the repository.\n   *\n   * https://turbo.build/repo/docs/reference/configuration#dangerouslydisablepackagemanagercheck\n   */\n  public readonly dangerouslyDisablePackageManagerCheck: boolean;\n\n  /**\n   * @default \".turbo/cache\"\n   *\n   * Specify the filesystem cache directory.\n   *\n   * https://turbo.build/repo/docs/reference/configuration#cachedir\n   */\n  public readonly cacheDir: string;\n\n  /**\n   * @deprecated The `daemon` configuration option is deprecated in Turbo 2.x\n   * and will be removed in Turbo 3.0 — the daemon is no longer used for\n   * `turbo run`. Reading this property returns whatever was passed to the\n   * constructor (default `true`), but the value is never written to\n   * `turbo.json`. New code should not consult this property.\n   */\n  public readonly daemon: boolean;\n\n  /**\n   * @default \"strict\"\n   *\n   * Turborepo's Environment Modes allow you to control which environment\n   * variables are available to a task at runtime:\n   *\n   *\"strict\": Filter environment variables to only those that are specified\n   * in the env and globalEnv keys in turbo.json.\n   *\n   * \"loose\": Allow all environment variables for the process to be available.\n   *\n   * https://turbo.build/repo/docs/reference/configuration#envmode\n   */\n  public readonly envMode: string;\n\n  /**\n   * Resolved `turbo run` CLI flags, with historical defaults applied. Rendered\n   * into the `build:all` / `reset:all` task commands via {@link renderRunArgs}.\n   */\n  public readonly runOptions: TurboRunOptions;\n\n  /*****************************************************************************\n   *\n   * Cache Settings\n   *\n   ****************************************************************************/\n\n  /**\n   * Cache settings, if using remote cache.\n   */\n  public readonly remoteCacheOptions?: RemoteCacheOptions;\n\n  /**\n   * is this the root project?\n   */\n  public readonly isRootProject: boolean;\n\n  /**\n   * Turbo's build:all task at the root of the monorepo.\n   *\n   * This is a normal projen task that runs the root turbo task.\n   */\n  public readonly buildAllTask?: Task;\n\n  /**\n   * Main turbo:build task\n   *\n   * This is a special Turbo task\n   */\n  public readonly buildTask: TurboRepoTask;\n\n  /**\n   * pre compile task\n   */\n  public readonly preCompileTask?: TurboRepoTask;\n\n  /**\n   * compile task\n   */\n  public readonly compileTask?: TurboRepoTask;\n\n  /**\n   * post compile task\n   */\n  public readonly postCompileTask?: TurboRepoTask;\n\n  /**\n   * Test task\n   */\n  public readonly testTask?: TurboRepoTask;\n\n  /**\n   * Package task\n   */\n  public readonly packageTask?: TurboRepoTask;\n\n  /**\n   * Sub-Tasks to run\n   */\n  public readonly tasks: Array<TurboRepoTask> = [];\n\n  /**\n   * Env Args that will bre added to turbo's build:all task\n   */\n  public readonly buildAllTaskEnvVars: Record<string, string>;\n\n  constructor(\n    public readonly project: NodeProject,\n    options: TurboRepoOptions = {},\n  ) {\n    super(project);\n\n    this.turboVersion = options.turboVersion ?? \"catalog:\";\n    this.isRootProject = project === project.root;\n\n    /**\n     * Add turborepo package to root project.\n     */\n    if (this.isRootProject) {\n      project.addDevDeps(`turbo@${this.turboVersion}`);\n    }\n\n    /**\n     * Ignore the working cache for turbo.\n     */\n    project.gitignore.addPatterns(\"/.turbo\");\n    project.npmignore?.addPatterns(\"/.turbo/\");\n\n    /***************************************************************************\n     *\n     * Set some default options\n     *\n     **************************************************************************/\n\n    this.extends = options.extends ?? (this.isRootProject ? [] : [\"//\"]);\n    this.globalDependencies = options.globalDependencies ?? [];\n    this.globalEnv = options.globalEnv ?? [];\n    this.globalPassThroughEnv = options.globalPassThroughEnv ?? [];\n    this.ui = options.ui ?? \"stream\";\n    this.dangerouslyDisablePackageManagerCheck =\n      options.dangerouslyDisablePackageManagerCheck ?? false;\n    this.cacheDir = options.cacheDir ?? \".turbo/cache\";\n    this.daemon = options.daemon ?? true;\n    this.envMode = options.envMode ?? \"strict\";\n    this.runOptions = {\n      ...options.runOptions,\n      summarize: options.runOptions?.summarize ?? true,\n      concurrency: options.runOptions?.concurrency ?? 10,\n    };\n    this.remoteCacheOptions = options.remoteCacheOptions;\n    this.buildAllTaskEnvVars = options.buildAllTaskEnvVars ?? {};\n\n    /***************************************************************************\n     *\n     * Turbo Build Task\n     *\n     * All turbo configs contain a turbo build task.\n     *\n     **************************************************************************/\n\n    /**\n     * The turbo entry point definition for the turbo:build task. This exists\n     * in each project and is written tot he turbo.json file. This task is not\n     * a projen task or a Node task.\n     *\n     * For the root project, generated file paths are added as inputs at synth\n     * time (see {@link generatedFileInputs}, applied in {@link preSynthesize})\n     * so that when projen regenerates files (e.g. turbo.json, workflows), the\n     * root task cache is invalidated.\n     */\n    this.buildTask = new TurboRepoTask(this.project, {\n      name: ROOT_TURBO_TASK_NAME,\n      dependsOn: this.isRootProject ? [`^${ROOT_TURBO_TASK_NAME}`] : [],\n    });\n\n    /***************************************************************************\n     *\n     * Turbo Build All Task\n     *\n     * The Projen entry point. This only exists in the root and is a projen\n     * task that can be run using pnpm.\n     *\n     * - Turns off telemetry\n     * - Runs root turbo task to build all sub-projects.\n     *\n     **************************************************************************/\n\n    if (this.isRootProject) {\n      /**\n       * Create and configure the build all task.\n       */\n      this.buildAllTask = this.project.tasks.addTask(ROOT_CI_TASK_NAME, {\n        description:\n          \"Root build followed by sub-project builds. Mimics the CI build process in one step.\",\n      });\n      this.buildAllTask.exec(\"turbo telemetry disable\");\n\n      /**\n       * Any env vars that may need to be added to the build all task.\n       */\n      if (this.buildAllTaskEnvVars) {\n        Object.entries(this.buildAllTaskEnvVars).forEach(([name, value]) => {\n          this.addGlobalEnvVar(name, value);\n        });\n      }\n\n      /**\n       * No remote cache in use, so run the root turbo task to build all\n       * sub-projects locally.\n       */\n      if (!this.remoteCacheOptions) {\n        this.buildAllTask.exec(\n          `turbo ${ROOT_TURBO_TASK_NAME} ${this.renderRunArgs(false)}`,\n        );\n      } else {\n        /**\n         * Remote cache in use, so run the root turbo task to build all\n         * sub-projects using the remote cache.\n         */\n        this.buildAllTask.exec(\n          `turbo ${ROOT_TURBO_TASK_NAME} ${this.renderRunArgs(true)}`,\n          {\n            condition: '[ ! -n \"$CI\" ]',\n            env: {\n              TURBO_ENDPOINT: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.endpointParamName} --query Parameter.Value --output text --profile ${this.remoteCacheOptions.profileName})`,\n              TURBO_TOKEN: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.tokenParamName} --query Parameter.Value --output text --profile ${this.remoteCacheOptions.profileName})`,\n            },\n          },\n        );\n        // running in CI, We'll depend on OIDC auth.\n        this.buildAllTask.exec(\n          `turbo ${ROOT_TURBO_TASK_NAME} ${this.renderRunArgs(true)}`,\n          {\n            condition: '[ -n \"$CI\" ]',\n            env: {\n              TURBO_ENDPOINT: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.endpointParamName} --query Parameter.Value --output text)`,\n              TURBO_TOKEN: `$(aws ssm get-parameter --name ${this.remoteCacheOptions.tokenParamName} --query Parameter.Value --output text)`,\n            },\n          },\n        );\n      }\n    }\n\n    /**\n     * SUB-PROJECT\n     *\n     * Creates tasks for the typical lifecycle for all project projects.\n     */\n    if (!this.isRootProject) {\n      /**\n       * Generated file paths (managed `FileBase` files plus generated-once\n       * `SampleFile` / `SampleDir`) are appended to these compile-phase task\n       * inputs at synth time — see {@link generatedFileInputs}, applied in\n       * {@link preSynthesize} — so they are captured even when added after this\n       * component is constructed (e.g. a subclass's SampleFiles).\n       */\n      this.preCompileTask = new TurboRepoTask(project, {\n        name: options.preCompileTask?.name ?? \"pre-compile\",\n        inputs: [\"src/**\"],\n      });\n      this.compileTask = new TurboRepoTask(project, {\n        name: options.compileTask?.name ?? \"compile\",\n        inputs: [\"src/**\"],\n      });\n      this.postCompileTask = new TurboRepoTask(project, {\n        name: options.postCompileTask?.name ?? \"post-compile\",\n        inputs: [\"src/**\"],\n      });\n      this.testTask = new TurboRepoTask(project, {\n        name: options.testTask?.name ?? \"test\",\n      });\n      this.packageTask = new TurboRepoTask(project, {\n        name: options.packageTask?.name ?? \"package\",\n        inputs: [\".npmignore\"],\n      });\n      this.tasks.push(\n        this.preCompileTask,\n        this.compileTask,\n        this.postCompileTask,\n        this.testTask,\n        this.packageTask,\n      );\n    }\n  }\n\n  /**\n   * Render the `turbo run` CLI flag string for the `build:all` / `reset:all`\n   * task commands from {@link runOptions}. With no `runOptions` configured the\n   * output matches the historically hard-coded flags exactly.\n   *\n   * @param remote - when `true`, also emit the remote-cache flags\n   * (`--cache=remote:rw` plus `--api` / `--token` / `--team` derived from\n   * {@link remoteCacheOptions}). The remote-cache `build:all` variant passes\n   * `true`; `reset:all` and the local `build:all` variant pass `false`.\n   */\n  public renderRunArgs(remote: boolean): string {\n    const run = this.runOptions;\n    const args: Array<string> = [];\n\n    // --summarize / --concurrency carry the historical defaults applied in the\n    // constructor, so the empty-runOptions case renders byte-identically.\n    if (run.summarize) {\n      args.push(\"--summarize\");\n    }\n    args.push(`--concurrency=${run.concurrency}`);\n\n    // Presence-only boolean flags.\n    if (run.force) {\n      args.push(\"--force\");\n    }\n    if (run.noCache) {\n      args.push(\"--no-cache\");\n    }\n    if (run.only) {\n      args.push(\"--only\");\n    }\n    if (run.affected) {\n      args.push(\"--affected\");\n    }\n\n    // Value flags — emitted only when explicitly set.\n    if (run.cacheWorkers !== undefined) {\n      args.push(`--cache-workers=${run.cacheWorkers}`);\n    }\n    if (run.continueOn !== undefined) {\n      args.push(`--continue=${run.continueOn}`);\n    }\n    if (run.frameworkInference !== undefined) {\n      args.push(`--framework-inference=${run.frameworkInference}`);\n    }\n    for (const filter of run.filter ?? []) {\n      args.push(`--filter=${filter}`);\n    }\n    if (run.outputLogs !== undefined) {\n      args.push(`--output-logs=${run.outputLogs}`);\n    }\n    if (run.logOrder !== undefined) {\n      args.push(`--log-order=${run.logOrder}`);\n    }\n    if (run.logPrefix !== undefined) {\n      args.push(`--log-prefix=${run.logPrefix}`);\n    }\n    if (run.dryRun !== undefined) {\n      args.push(`--dry-run=${run.dryRun}`);\n    }\n\n    /**\n     * `--cache`: an explicit value always wins; otherwise default to\n     * `remote:rw` only in the remote-cache branch (matching the historical\n     * hard-coded command). The local branch emits no `--cache` by default.\n     */\n    const cache = run.cache ?? (remote ? \"remote:rw\" : undefined);\n    if (cache !== undefined) {\n      args.push(`--cache=${cache}`);\n    }\n\n    /**\n     * Remote-cache auth flags are derived from `remoteCacheOptions`, never from\n     * `runOptions`. The `$TURBO_ENDPOINT` / `$TURBO_TOKEN` references resolve\n     * from the task's `env` at run time.\n     */\n    if (remote && this.remoteCacheOptions) {\n      args.push(\n        \"--api=$TURBO_ENDPOINT\",\n        \"--token=$TURBO_TOKEN\",\n        `--team=${this.remoteCacheOptions.teamName}`,\n      );\n    }\n\n    // Escape hatch — appended verbatim, last, so it can extend or override.\n    if (run.additionalArgs) {\n      args.push(...run.additionalArgs);\n    }\n\n    return args.join(\" \");\n  }\n\n  /**\n   * Add an env var to the global env vars for all tasks.\n   * This will also become an input for the build:all task cache at the root.\n   */\n  public addGlobalEnvVar(name: string, value: string) {\n    /**\n     * Add env var to global task env\n     */\n    this.buildAllTask?.env(name, value);\n\n    /**\n     * Add to global env vars for all tasks.\n     */\n    if (this.isRootProject) {\n      this.globalEnv.push(name);\n    }\n  }\n\n  /**\n   * @deprecated Pass `{ tasks: [...] }` and name only the tasks whose cache\n   * hash must include `GIT_BRANCH_NAME`. The no-args form writes the env to\n   * the root `globalEnv` array, which forces every task in the monorepo to\n   * miss cache on every branch switch — destroying cross-branch cache hits\n   * for library `compile` / `test` / `lint` / `package` work that does not\n   * read the branch name at runtime.\n   */\n  public activateBranchNameEnvVar(): void;\n  /**\n   * Scopes `GIT_BRANCH_NAME` to the named tasks on this TurboRepo.\n   *\n   * Two layers are wired, and both are required:\n   *\n   * 1. Each named task's `env: []` array gets `GIT_BRANCH_NAME`, telling turbo\n   *    *to hash* the variable for that task. Only those tasks miss cache on a\n   *    branch switch — other tasks and the root `globalEnv` are left untouched.\n   * 2. The root `build:all` projen task env gets the value, so the variable is\n   *    actually *populated* in the process turbo runs in. Without this, turbo\n   *    hashes the declared variable as unset locally while CI hashes the job\n   *    env's value, and the two can never share a cache entry.\n   *\n   * Layer 2 is deliberately written to the `build:all` task env rather than to\n   * `globalEnv`: an unset-vs-set value in turbo's process env only changes the\n   * hash of tasks that declare it, so cross-branch cache hits survive for\n   * every task that does not.\n   *\n   * Throws at synth time when `options.tasks` contains a name that does\n   * not match a task on this TurboRepo, so typos surface immediately.\n   */\n  public activateBranchNameEnvVar(\n    options: ActivateBranchNameEnvVarOptions,\n  ): void;\n  public activateBranchNameEnvVar(\n    options?: ActivateBranchNameEnvVarOptions,\n  ): void {\n    /**\n     * Legacy no-args form. Preserved so existing consumers keep building\n     * without code edits; emits a deprecation warning so the regression\n     * risk surfaces in synth logs.\n     */\n    if (options === undefined) {\n      this.project.logger.warn(\n        \"TurboRepo.activateBranchNameEnvVar() with no arguments is deprecated. \" +\n          \"It writes GIT_BRANCH_NAME to the root `globalEnv`, which forces every \" +\n          \"task in the monorepo to miss cache on every branch switch. Pass \" +\n          \"`{ tasks: [...] }` and name only the tasks that actually consume the \" +\n          \"branch (e.g. CDK synth/package) to preserve cross-branch cache hits \" +\n          \"for everything else.\",\n      );\n      this.addGlobalEnvVar(GIT_BRANCH_NAME_ENV, GIT_BRANCH_NAME_ENV_VALUE);\n      return;\n    }\n\n    /**\n     * Per-task scope. Validate every requested task name against this\n     * TurboRepo's known tasks before mutating anything so a typo in one\n     * entry cannot leave a partial state behind.\n     */\n    const knownTaskNames = this.tasks.map((task) => task.name);\n    const unknown = options.tasks.filter(\n      (name) => !knownTaskNames.includes(name),\n    );\n    if (unknown.length > 0) {\n      throw new Error(\n        `TurboRepo.activateBranchNameEnvVar: unknown task name(s) ${JSON.stringify(\n          unknown,\n        )}. Known tasks on this TurboRepo: ${JSON.stringify(knownTaskNames)}.`,\n      );\n    }\n\n    for (const name of options.tasks) {\n      const task = this.tasks.find((t) => t.name === name);\n      // Guaranteed non-undefined by the validation pass above, but narrow for TS.\n      if (task && !task.env.includes(GIT_BRANCH_NAME_ENV)) {\n        task.env.push(GIT_BRANCH_NAME_ENV);\n      }\n    }\n\n    /**\n     * Declaring the env on a task only tells turbo to hash it — something has\n     * to populate it in turbo's own process for the hash to carry a value.\n     * Runs only after the validation pass above, so a typo leaves no partial\n     * state behind at either layer.\n     */\n    this.injectBranchNameOnBuildAll();\n  }\n\n  /**\n   * Populate `GIT_BRANCH_NAME` on the root `build:all` task env — the process\n   * env turbo runs in — so locally computed hashes match CI, where the\n   * workflow job env supplies the same variable.\n   *\n   * Written straight to the task rather than through\n   * {@link addGlobalEnvVar}, which would also push the name onto the root\n   * `globalEnv` and bust the cache for every task in the monorepo.\n   *\n   * No-ops when the root project has no TurboRepo (`turbo: false`) and\n   * therefore no `build:all` task to inject into.\n   */\n  private injectBranchNameOnBuildAll(): void {\n    const rootTurbo = TurboRepo.of(this.project.root);\n    rootTurbo?.buildAllTask?.env(\n      GIT_BRANCH_NAME_ENV,\n      GIT_BRANCH_NAME_ENV_VALUE,\n    );\n  }\n\n  /**\n   * Paths of all generated files in the project, deduped, for use as task\n   * inputs so the compile cache invalidates when they change. Includes\n   * projen-managed `FileBase` files plus generated-once `SampleFile` /\n   * `SampleDir` — whose paths projen keeps private, so they are read defensively\n   * and skipped if that internal shape ever changes. Computed at synth time so\n   * files added after this component (e.g. a subclass's SampleFiles) are seen.\n   */\n  private generatedFileInputs(): Array<string> {\n    const inputs = new Set<string>();\n\n    for (const component of this.project.components) {\n      if (component instanceof FileBase) {\n        inputs.add(component.path);\n      } else if (component instanceof SampleFile) {\n        const filePath = (component as unknown as { filePath?: unknown })\n          .filePath;\n        if (typeof filePath === \"string\") {\n          inputs.add(filePath);\n        }\n      } else if (component instanceof SampleDir) {\n        const dir = (component as unknown as { dir?: unknown }).dir;\n        if (typeof dir === \"string\") {\n          inputs.add(`${dir}/**`);\n        }\n      }\n    }\n\n    return Array.from(inputs);\n  }\n\n  preSynthesize(): void {\n    /**\n     * Add any local workspace specific deps to dependsOn so that we know\n     * compile has finished before attempting to use any distribution artifacts.\n     *\n     * Do this in presynth so that we can be sure all project dependencies have\n     * been defined first.\n     */\n    let nextDependsOn = this.project.deps.all\n      .filter((d) => d.version === \"workspace:*\")\n      .map((d) => [d.name, ROOT_TURBO_TASK_NAME].join(\"#\"));\n\n    /**\n     * Loop over all projen tasks and their corresponding turbo task\n     * definitions. Chain them together using dependsOn, along with any outside\n     * package dependencies.\n     */\n    if (!this.isRootProject) {\n      (\n        [\n          [this.project.preCompileTask, this.preCompileTask],\n          [this.project.compileTask, this.compileTask],\n          [this.project.postCompileTask, this.postCompileTask],\n          [this.project.testTask, this.testTask],\n          [this.project.packageTask, this.packageTask],\n        ] as Array<[Task, TurboRepoTask]>\n      ).forEach(([pjTask, turboTask]) => {\n        /**\n         * If steps exist chain using dependsOn\n         */\n        if (pjTask && turboTask && pjTask.steps.length > 0) {\n          if (nextDependsOn.length > 0) {\n            turboTask.dependsOn.push(...nextDependsOn);\n          }\n          nextDependsOn = [turboTask.name];\n\n          /**\n           * Otherwise, if a task doesn't do anything, deactivate it.\n           */\n        } else {\n          turboTask.isActive = false;\n        }\n      });\n\n      /**\n       * Main build entry point depends on whatever was last.\n       */\n      this.buildTask.dependsOn.push(...nextDependsOn);\n    }\n\n    /**\n     * Append generated-file paths to the compile-phase task inputs (or the root\n     * build task) now that all files — including generated-once SampleFiles\n     * added after this component — are registered. Done here, not in the\n     * constructor, so those late-added inputs become part of the turbo cache\n     * key. Deduped against existing inputs so any inputs a project type declared\n     * explicitly are not duplicated.\n     */\n    const generatedInputs = this.generatedFileInputs();\n    const appendGeneratedInputs = (task?: TurboRepoTask): void => {\n      if (!task) {\n        return;\n      }\n      for (const input of generatedInputs) {\n        if (!task.inputs.includes(input)) {\n          task.inputs.push(input);\n        }\n      }\n    };\n\n    if (this.isRootProject) {\n      appendGeneratedInputs(this.buildTask);\n    } else {\n      appendGeneratedInputs(this.preCompileTask);\n      appendGeneratedInputs(this.compileTask);\n      appendGeneratedInputs(this.postCompileTask);\n    }\n\n    /**\n     * The name for the turbo config file.\n     */\n    const fileName: string = \"turbo.json\";\n\n    /**\n     * Ensure that turbo config doesn't end up in any package distributions.\n     */\n    this.project.addPackageIgnore(fileName);\n\n    /**\n     * The content of this YAML file will be resolved at synth time. By then,\n     * any sub-projects will be defined and this will be a complete list.\n     */\n    new JsonFile(this.project, fileName, {\n      obj: {\n        extends: this.extends.length ? this.extends : undefined,\n        globalDependencies:\n          this.isRootProject && this.globalDependencies.length\n            ? this.globalDependencies\n            : undefined,\n        globalEnv:\n          this.isRootProject && this.globalEnv.length\n            ? this.globalEnv\n            : undefined,\n        globalPassThroughEnv:\n          this.isRootProject && this.globalPassThroughEnv.length\n            ? this.globalPassThroughEnv\n            : undefined,\n        ui: this.isRootProject ? this.ui : undefined,\n        dangerouslyDisablePackageManagerCheck: this.isRootProject\n          ? this.dangerouslyDisablePackageManagerCheck\n          : undefined,\n        cacheDir: this.isRootProject ? this.cacheDir : undefined,\n        envMode: this.isRootProject ? this.envMode : undefined,\n        /**\n         * All tasks\n         */\n        tasks: this.tasks\n          .filter((task) => task.isActive)\n          .reduce(\n            (acc, task) => {\n              acc[task.name] = {\n                ...task.taskConfig(),\n              };\n              return acc;\n            },\n            {\n              [this.buildTask.name]: { ...this.buildTask.taskConfig() },\n            } as Record<string, any>,\n          ),\n      },\n    });\n\n    super.preSynthesize();\n  }\n}\n","import { Component, Project } from \"projen/lib\";\n\n/**\n * Each of the below options corresponds to a task property found here:\n *  * https://turborepo.com/docs/reference/configuration#defining-tasks\n */\nexport interface TurboRepoTaskOptions {\n  readonly name: string;\n  readonly dependsOn?: Array<string>;\n  readonly env?: Array<string>;\n  readonly passThroughEnv?: Array<string>;\n  readonly outputs?: Array<string>;\n  readonly cache?: boolean;\n  readonly inputs?: Array<string>;\n  readonly outputLogs?:\n    \"full\" | \"hash-only\" | \"new-only\" | \"errors-only\" | \"none\";\n  readonly persistent?: boolean;\n  readonly interactive?: boolean;\n}\n\nexport class TurboRepoTask extends Component {\n  public readonly name: string;\n  public dependsOn: Array<string>;\n  public readonly env: Array<string>;\n  public readonly passThroughEnv: Array<string>;\n  public outputs: Array<string>;\n  public cache: boolean;\n  public inputs: Array<string>;\n  public readonly outputLogs:\n    \"full\" | \"hash-only\" | \"new-only\" | \"errors-only\" | \"none\";\n  public readonly persistent: boolean;\n  public readonly interactive: boolean;\n\n  /**\n   * Include this task in turbo.json output?\n   */\n  public isActive: boolean;\n\n  constructor(\n    public readonly project: Project,\n    options: TurboRepoTaskOptions,\n  ) {\n    super(project);\n\n    this.name = options.name;\n    this.dependsOn = options.dependsOn ?? [];\n    this.env = options.env ?? [];\n    this.passThroughEnv = options.passThroughEnv ?? [];\n    this.outputs = options.outputs ?? [];\n    this.cache = options.cache ?? true;\n    this.inputs = [\n      ...(options.inputs ?? []),\n      // rerun if projen config changes\n      \".projen/**\",\n      // ignore mac files\n      \"!.DS_Store\",\n      \"!**/.DS_Store\",\n    ];\n    this.outputLogs = options.outputLogs ?? \"new-only\";\n    this.persistent = options.persistent ?? false;\n    this.interactive = options.interactive ?? false;\n    this.isActive = true;\n  }\n\n  public taskConfig(): Record<string, any> {\n    return {\n      dependsOn: this.dependsOn,\n      env: this.env,\n      passThroughEnv: this.passThroughEnv,\n      outputs: this.outputs,\n      cache: this.cache,\n      inputs: this.inputs,\n      outputLogs: this.outputLogs,\n      persistent: this.persistent,\n      interactive: this.interactive,\n    };\n  }\n}\n","/*******************************************************************************\n *\n * Shared branch-name environment variable contract.\n *\n * `GIT_BRANCH_NAME` is injected at two layers that must agree:\n *\n * 1. ABOVE turbo — the root `build:all` projen task env. This is the process\n *    env turbo itself runs in, so it is the only layer turbo's hasher can read\n *    when a task declares `GIT_BRANCH_NAME` in its `env: []` array.\n * 2. BELOW turbo — the `cdk synth` step env inside a CDK app's `synth` /\n *    `synth:silent` tasks, which is what actually resolves the branch used in\n *    generated stack/resource names.\n *\n * Layer 1 sets the value that layer 2's `[ -n \"$GIT_BRANCH_NAME\" ]` guard then\n * consumes, so the two fallbacks must be identical — otherwise the value turbo\n * hashes and the value synth bakes into the assembly can diverge. Both layers\n * import the constants below so they agree by construction.\n *\n ******************************************************************************/\n\n/**\n * Environment variable carrying the current git branch name.\n */\nexport const GIT_BRANCH_NAME_ENV = \"GIT_BRANCH_NAME\";\n\n/**\n * Projen task env value that resolves {@link GIT_BRANCH_NAME_ENV}.\n *\n * The value must be exactly `$(...)` so projen's `evalEnvironment` expands it\n * (substitution only fires when the full value matches `$(...)`), and the body\n * must NOT contain a nested `$(...)` — projen's built-in cross-platform shell\n * (0.101+) cannot evaluate command substitution and throws\n * `Not implemented: command`.\n *\n * The `[ -n \"$GIT_BRANCH_NAME\" ]` guard honors a pre-set (CI-exported)\n * value for remote-cache parity, otherwise falls back to\n * `git branch --show-current`. That fallback returns empty on a detached HEAD,\n * where CI's job-level env takes precedence anyway.\n */\nexport const GIT_BRANCH_NAME_ENV_VALUE =\n  '$([ -n \"$GIT_BRANCH_NAME\" ] && echo \"$GIT_BRANCH_NAME\" || git branch --show-current)';\n","import { Project } from \"projen/lib\";\nimport { TurboRepo } from \"../../turbo/turbo-repo\";\n\n/**\n * Fully-resolved build policy for the consuming project.\n *\n * The generated agent guidance around `pnpm build:all` used to assert\n * unconditionally that the command \"requires the user to be\n * authenticated to AWS on the prod account used for Turborepo remote\n * caching (`readonlyaccess-prod-525259625215-us-east-1` profile)\".\n * Both halves of that sentence were wrong for most consumers:\n *\n *   1. The AWS-auth requirement only exists when a Turborepo **remote\n *      cache** is configured. Consumers running a local cache only\n *      (`turbo.json` with just a `cacheDir`) need no credentials at\n *      all, and agents that believed otherwise aborted mid-flow —\n *      three lost-work incidents in `codedrifters/openhi-planning`.\n *   2. The profile name was this repository's own profile, baked\n *      verbatim into every consumer's generated text.\n *\n * This struct carries the two facts the rule renderers need, derived\n * from the project's actual {@link TurboRepo} configuration, so the\n * guidance is true for whichever consumer it renders into.\n *\n * @see resolveBuildPolicy\n */\nexport interface ResolvedBuildPolicy {\n  /**\n   * Whether a Turborepo **remote** cache is configured on the project.\n   *\n   * `false` means either there is no {@link TurboRepo} component at\n   * all, or it was constructed without `remoteCacheOptions` — in both\n   * cases `pnpm build:all` needs no AWS credentials and the generated\n   * guidance must not claim otherwise.\n   */\n  readonly remoteCacheEnabled: boolean;\n\n  /**\n   * Local AWS profile name used to fetch the remote-cache endpoint and\n   * token, taken from `remoteCacheOptions.profileName`.\n   *\n   * `undefined` whenever {@link remoteCacheEnabled} is `false`. Never\n   * hard-code a profile name in rule content — read it from here so\n   * each consumer's generated text names its own profile.\n   */\n  readonly awsProfileName?: string;\n}\n\n/**\n * Build policy for a project with no Turborepo remote cache — the\n * zero-config default. Rule renderers that receive this omit the\n * AWS-authentication guidance entirely rather than asserting a\n * credential requirement that does not exist.\n */\nexport const DEFAULT_BUILD_POLICY: ResolvedBuildPolicy = {\n  remoteCacheEnabled: false,\n};\n\n/**\n * Derives the {@link ResolvedBuildPolicy} for a project by inspecting\n * its {@link TurboRepo} component.\n *\n * Auto-detection, not opt-in: `remoteCacheOptions` being `undefined`\n * *is* the \"remote cache disabled\" signal — `TurboRepo.renderRunArgs`\n * already branches on exactly the same condition when it decides\n * whether to emit `--api` / `--token` / `--team` flags. Consumers get\n * accurate guidance with no extra configuration.\n *\n * Call this lazily (at synthesis time), not from a constructor: the\n * `TurboRepo` component must already be attached to the project for\n * detection to succeed.\n */\nexport function resolveBuildPolicy(project: Project): ResolvedBuildPolicy {\n  const remoteCacheOptions = TurboRepo.of(project)?.remoteCacheOptions;\n\n  if (!remoteCacheOptions) {\n    return DEFAULT_BUILD_POLICY;\n  }\n\n  return {\n    remoteCacheEnabled: true,\n    awsProfileName: remoteCacheOptions.profileName,\n  };\n}\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { renderClaimVerificationSection } from \"./claim-verification\";\nimport {\n  ISSUE_CLOSE_RULE_REFERENCE,\n  ISSUE_CLOSE_SECTION_TITLE,\n  renderIssueClosePolicySection,\n} from \"./issue-close\";\nimport {\n  DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n  ResolvedIssueDefaults,\n  labelsForPhase,\n} from \"./issue-defaults\";\nimport { renderIssueTypeAssignmentStep } from \"./issue-type\";\nimport { renderOriginStampSection } from \"./origin-label\";\nimport { DEFAULT_AGENT_PATHS, ResolvedAgentPaths } from \"./paths\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n  AGENT_MODEL,\n  AGENT_RULE_SCOPE,\n  AgentSkill,\n  AgentSubAgent,\n} from \"../types\";\n\n/**\n * Verbatim Business Model Canvas template shipped to the consuming\n * project alongside the `/canvas-business-model` skill. Emitted as\n * `_references/templates/_template-canvas.md` under the skill\n * directory so the canvas-phase handler resolves it locally without\n * reaching back into configulator.\n *\n * The template is domain-neutral: it captures the Osterwalder nine-\n * block structure, BIZBOK value-stream placeholders, and size-based\n * variation scaffolding, but does not hardcode industry names,\n * company names, or product categories. Those are filled in by the\n * canvas phase based on the invoking issue.\n */\nconst TEMPLATE_CANVAS = `---\ntitle: \"Business Model: <Segment Name>\"\ndescription: \"Business Model Canvas analysis for the <segment name> segment of the <industry> industry.\"\n---\n\n| Field | Value |\n|-------|-------|\n| **Industry** | <industry name> |\n| **Segment** | <segment name> |\n| **Status** | Draft |\n| **Created** | YYYY-MM-DD |\n| **Last Updated** | YYYY-MM-DD |\n\n## Overview\n\n<2–3 paragraph summary of this segment: what it is, who the key\nplayers are, how large the market is, and what makes this segment's\nbusiness model distinctive.>\n\n## Business Model Canvas\n\n### Customer Segments\n\nWho are the customers in this segment? Include segment definitions,\nbuyer personas, and how customer needs vary.\n\n| Customer Segment | Description | Size Estimate | Key Needs |\n|------------------|-------------|---------------|-----------|\n| <segment> | <who they are> | <market size or count> | <primary needs> |\n\n### Value Propositions\n\nWhat value does this segment deliver to its customers? What problems\ndoes it solve?\n\n| Value Proposition | Target Customer Segment | Differentiation |\n|-------------------|-------------------------|-----------------|\n| <proposition> | <which customer segment> | <what makes it unique> |\n\n### Channels\n\nHow does this segment reach its customers? Include marketing, sales,\ndistribution, and service delivery channels.\n\n| Channel | Type | Purpose | Digital/Physical |\n|---------|------|---------|------------------|\n| <channel> | <marketing / sales / distribution / service> | <what it does> | <digital / physical / hybrid> |\n\n### Customer Relationships\n\nHow are customer relationships established, maintained, and grown?\n\n| Relationship Type | Customer Segment | Description |\n|-------------------|------------------|-------------|\n| <type> | <which segment> | <how the relationship works> |\n\n### Revenue Streams\n\nHow does this segment generate revenue? Include pricing models,\npayment mechanisms, and revenue mix.\n\n| Revenue Stream | Pricing Model | % of Revenue | Trend |\n|----------------|---------------|--------------|-------|\n| <stream> | <subscription / transaction / licensing / etc.> | <estimate> | <growing / stable / declining> |\n\n### Key Resources\n\nWhat assets are required to operate in this segment?\n\n| Resource | Type | Critical? | Notes |\n|----------|------|-----------|-------|\n| <resource> | <physical / intellectual / human / financial> | <yes / no> | <context> |\n\n### Key Activities\n\nWhat must businesses in this segment do to deliver their value\nproposition? These activities directly feed value stream definitions.\n\n| Activity | Category | Description | Value Proposition Served |\n|----------|----------|-------------|--------------------------|\n| <activity> | <production / problem-solving / platform / network> | <what it involves> | <which VP it supports> |\n\n### Key Partners\n\nWho are the critical external partners and suppliers?\n\n| Partner Type | Examples | What They Provide | Dependency Level |\n|--------------|----------|-------------------|------------------|\n| <type> | <example companies or categories> | <what value they add> | <critical / important / optional> |\n\n### Cost Structure\n\nWhat are the major cost drivers?\n\n| Cost Category | Type | Relative Scale | Notes |\n|---------------|------|----------------|-------|\n| <category> | <fixed / variable> | <high / medium / low> | <context> |\n\n## Value Streams\n\n<!-- Populated in the complete phase. Each value stream traces to a\nValue Proposition above; each stage maps to at least one Key Activity. -->\n\n## Variations\n\n<!-- Populated in the complete phase. Size variations are required;\ngeographic and regulatory variations are included when applicable. -->\n\n## Sources\n\n1. [<Title>](<URL>) — <brief description>\n2. ...\n\n## Traceability\n\n- **Industry source:** [<industry scope or plan>](<relative path>)\n- **Related research:** [<research page>](<relative path>)\n\n## Revision History\n\n| Date | Author | Changes |\n|------|--------|---------|\n| YYYY-MM-DD | <author> | Initial canvas |\n`;\n\n/**\n * Reference files emitted alongside the `/canvas-business-model` SKILL.md.\n * Currently just the canvas template; the list is kept as a\n * `ReadonlyArray` so future reference material (e.g. a BIZBOK value-\n * stream cheatsheet) can be added without changing the bundle shape.\n */\nconst BUSINESS_MODELS_CANVAS_REFERENCE_FILES: ReadonlyArray<{\n  readonly path: string;\n  readonly content: string;\n}> = [\n  {\n    path: \"_references/templates/_template-canvas.md\",\n    content: TEMPLATE_CANVAS,\n  },\n];\n\n/**\n * Sub-agent that authors Business Model Canvas (Osterwalder) documents\n * plus BIZBOK value streams per industry segment. Sits between\n * `industry-discovery` (which picks verticals and segments) and\n * `bcm-writer` (which models capabilities needed to execute).\n *\n * The prompt is deliberately domain-neutral. Concrete industry names,\n * segment taxonomies, company-size tiers, and regulatory frameworks\n * come from the invoking issue body, `docs/src/content/docs/project-context.md`,\n * or the consuming project's `agentConfig.rules`.\n */\nfunction buildBusinessModelsAnalystSubAgent(\n  paths: ResolvedAgentPaths,\n): AgentSubAgent {\n  return {\n    name: \"business-models-analyst\",\n    description:\n      \"Authors Business Model Canvas (Osterwalder) documents plus per-segment BIZBOK value streams through a 3-phase pipeline (scan → canvas → complete). One phase per session, tracked by business-models:* GitHub issue labels with filesystem-based durability between phases. Produces canvas documents that downstream bcm-writer capability models consume.\",\n    model: AGENT_MODEL.POWERFUL,\n    maxTurns: 80,\n    platforms: { cursor: { exclude: true } },\n    prompt: [\n      \"# Business Models Analyst Agent\",\n      \"\",\n      \"You author Business Model Canvas (Osterwalder) documents plus\",\n      \"per-segment BIZBOK value streams through a structured 3-phase state\",\n      \"machine. Each phase runs as its **own agent session**, triggered by a\",\n      \"GitHub issue with a `business-models:*` phase label. You handle\",\n      \"exactly **one phase per session** — read the issue to determine\",\n      \"which phase to execute.\",\n      \"\",\n      \"This agent sits between `industry-discovery` (which identifies\",\n      \"verticals and segments) and `bcm-writer` (which models the\",\n      \"capabilities needed to execute). Your canvases describe *how the\",\n      \"business operates in a segment*; the downstream BCM writer then\",\n      \"derives capability models from the Key Activities and value streams\",\n      \"you capture.\",\n      \"\",\n      \"This agent is **domain-neutral**. It makes no assumptions about the\",\n      \"consuming project's industry, product, or segment taxonomy. All\",\n      \"concrete vocabulary — industry names, segment slugs, company-size\",\n      \"tiers, regulatory frameworks — comes from the invoking issue body,\",\n      `\\`${paths.docsRoot}/project-context.md\\`, or the consuming project's`,\n      \"configuration.\",\n      \"\",\n      \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n      \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...PROJECT_CONTEXT_READER_SECTION,\n      \"## Design Principles\",\n      \"\",\n      \"1. **Canvas first, value streams second.** The Business Model Canvas\",\n      \"   captures *how the business works*. Value streams capture *how\",\n      \"   value flows*. Canvas informs value streams, not the other way\",\n      \"   around — Key Activities and Value Propositions on the canvas\",\n      \"   directly feed value-stream definitions.\",\n      \"2. **Variations are first-class.** A business model for a broad\",\n      \"   industry is too coarse — the same segment operates differently at\",\n      \"   different company sizes and in different regulatory environments.\",\n      \"   Variations are not footnotes; they are structured sections that\",\n      \"   downstream agents depend on.\",\n      \"3. **One segment per document.** Each business model document covers\",\n      \"   exactly one industry segment. Sub-segments share the parent\",\n      \"   document with a variation section unless the sub-segment's\",\n      \"   business model is fundamentally different.\",\n      \"4. **Research-driven, not invented.** Every canvas block must trace\",\n      \"   to research output, the invoking issue, or cited web sources. Do\",\n      \"   not populate canvas blocks from general knowledge alone.\",\n      \"5. **Filesystem durability.** Every phase persists its output to a\",\n      \"   file on disk before closing its issue. Downstream phases read\",\n      \"   those files — never rely on session memory.\",\n      \"6. **Issue graph = state machine.** Phase ordering is encoded with\",\n      \"   `Depends on: #N` links between phase issues. A phase runs only\",\n      \"   after its predecessor is closed.\",\n      \"7. **Generic over specific.** No hardcoded industry names,\",\n      \"   regulations, or product categories. Use placeholders and templates\",\n      \"   that the invoking issue or consuming project fills in.\",\n      \"8. **Canvas, not capabilities.** Capability modelling is the job of\",\n      \"   the downstream `bcm-writer` bundle. Canvas documents describe\",\n      \"   activities and value streams; they do not decompose capabilities\",\n      \"   into L1/L2/L3 trees or write capability definitions.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Methodology\",\n      \"\",\n      \"Business model analysis combines two established frameworks:\",\n      \"\",\n      \"### Business Model Canvas (Osterwalder & Pigneur)\",\n      \"\",\n      \"The nine-block strategic view of how a business creates, delivers,\",\n      \"and captures value:\",\n      \"\",\n      \"| Block | Question It Answers |\",\n      \"|-------|---------------------|\",\n      \"| Customer Segments | **Who** do we create value for? |\",\n      \"| Value Propositions | **What** value do we deliver? |\",\n      \"| Channels | **How** do we reach customers? |\",\n      \"| Customer Relationships | **How** do we maintain relationships? |\",\n      \"| Revenue Streams | **How** does the business earn money? |\",\n      \"| Key Resources | **What** assets are required? |\",\n      \"| Key Activities | **What** must the business do? |\",\n      \"| Key Partners | **Who** are the critical external partners? |\",\n      \"| Cost Structure | **What** are the major cost drivers? |\",\n      \"\",\n      \"### BIZBOK Value Streams (Business Architecture Guild)\",\n      \"\",\n      \"The operational view of how value flows from a triggering stakeholder\",\n      \"through stages to an outcome. Derived from the canvas's Key\",\n      \"Activities and Value Propositions. Each value stream has:\",\n      \"\",\n      \"- **Name** — noun phrase (e.g. `Customer Onboarding`, not\",\n      \"  `Onboard Customers`)\",\n      \"- **Triggering stakeholder** — who initiates the stream\",\n      \"- **Value proposition** — what value is delivered (pulled verbatim\",\n      \"  from the canvas)\",\n      \"- **Stages** — sequential steps from trigger to outcome\",\n      \"- **Stage outcomes** — what each stage produces\",\n      \"- **Key Activities mapping** — which canvas activities enable each\",\n      \"  stage\",\n      \"\",\n      \"### Combined Flow\",\n      \"\",\n      \"Canvas → Value Streams → Capability Models.\",\n      \"\",\n      \"The canvas tells us *what the business does*; value streams tell us\",\n      \"*how value flows*; capability models (authored by the downstream\",\n      \"`bcm-writer`) tell us *what capabilities are needed to execute*. Each\",\n      \"L3 capability in the BCM ultimately maps back to one or more value\",\n      \"stream stages authored here.\",\n      \"\",\n      \"**References:** Business Model Generation (Osterwalder & Pigneur,\",\n      \"2010); BIZBOK Guide (Business Architecture Guild).\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## State Machine Overview\",\n      \"\",\n      \"Business model authoring flows through **3 phases**:\",\n      \"\",\n      \"```\",\n      \"┌──────────────┐     ┌──────────────┐     ┌──────────────────┐\",\n      \"│  1. SCAN     │────▶│  2. CANVAS   │────▶│  3. COMPLETE     │\",\n      \"│  Identify    │     │  Research +  │     │  Value streams + │\",\n      \"│  segments    │     │  write the   │     │  variations +    │\",\n      \"│  needing     │     │  nine-block  │     │  downstream      │\",\n      \"│  analysis    │     │  canvas for  │     │  handoffs        │\",\n      \"│              │     │  one segment │     │                  │\",\n      \"└──────────────┘     └──────────────┘     └──────────────────┘\",\n      \"```\",\n      \"\",\n      \"**Issue labels encode the phase:**\",\n      \"\",\n      \"| Label | Phase | Session work |\",\n      \"|-------|-------|-------------|\",\n      \"| `business-models:scan` | 1. Scan | Read industry-discovery output and existing profiles. Identify segments needing analysis. Write a scan report. Create one `business-models:canvas` issue per in-scope segment. |\",\n      \"| `business-models:canvas` | 2. Canvas | Research and write the Business Model Canvas for one segment — all nine blocks. Create the downstream `business-models:complete` issue. |\",\n      \"| `business-models:complete` | 3. Complete | Derive BIZBOK value streams from the canvas, document variations (size, geography, regulatory), and hand off to `bcm-writer` via `bcm:outline` issues for each capability surfaced in Key Activities. |\",\n      \"\",\n      \"All issues also carry `type:business-model` and a `status:*` label.\",\n      \"\",\n      \"**Issue count per segment:** 1 scan (shared across segments in an\",\n      \"industry) + 1 canvas + 1 complete = **2–3 sessions per segment**\",\n      \"(scan is shared; one scan spawns N canvas issues).\",\n      \"\",\n      \"**Shortened paths:**\",\n      \"- Scan determines no segments need analysis (all already covered, or\",\n      \"  the industry input is absent) → scan issue closes with a\",\n      \"  justification and no downstream issues are created → **1 session**.\",\n      \"- Segment closely resembles a parent → complete phase appends a\",\n      \"  variation section to the parent's canvas rather than a full new\",\n      \"  document → the canvas phase closes with a pointer to the parent and\",\n      \"  only `business-models:complete` on the parent runs → **2 sessions**.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Configurable Paths\",\n      \"\",\n      \"The pipeline uses these placeholders. Consuming projects override the\",\n      \"defaults by passing paths in the skill invocations or by extending\",\n      \"this rule in their own `agentConfig.rules`.\",\n      \"\",\n      \"| Placeholder | Meaning | Default |\",\n      \"|-------------|---------|---------|\",\n      `| \\`<BUSINESS_MODELS_ROOT>\\` | Root folder for all business-model documents. The same path \\`company-profile\\` reads as \\`<BUSINESS_MODELS_ROOT>\\` and \\`bcm-writer\\` links from its Value Stream Mapping sections. | \\`${paths.docsRoot}/industry-research/\\` |`,\n      \"| `<SCAN_DIR>` | Scan-report working directory (Phase 1 output) | `<RESEARCH_ROOT>/business-models/` |\",\n      \"| `<CANVAS_DOC_LAYOUT>` | Directory layout for one canvas document | `<BUSINESS_MODELS_ROOT>/<industry>/segments/<segment-slug>/business-model.md` |\",\n      \"| `<SEGMENT_INDEX>` | Segment-folder index page (created when missing) | `<BUSINESS_MODELS_ROOT>/<industry>/segments/<segment-slug>/index.md` |\",\n      \"| `<INDUSTRY_SLUG>` | Short kebab-case slug identifying the industry | derived from the scan scope |\",\n      \"| `<SEGMENT_SLUG>` | Short kebab-case slug identifying the industry segment | derived from the segment name |\",\n      \"\",\n      `If \\`${paths.docsRoot}/project-context.md\\` specifies a different business-models`,\n      \"tree, prefer that. Otherwise fall back to the defaults above.\",\n      \"\",\n      \"The default `<BUSINESS_MODELS_ROOT>` matches the path\",\n      \"`company-profile` declares as `<BUSINESS_MODELS_ROOT>` (Phase 4\",\n      \"match step) so that profiles, canvases, and BCM docs all cross-\",\n      \"link without manual path plumbing. Overriding the root in one bundle\",\n      \"means overriding it in both.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Agent Loop\",\n      \"\",\n      \"Run this loop exactly once per session. Never start a second issue.\",\n      \"\",\n      \"1. Claim one open `type:business-model` issue using phase priority:\",\n      \"   `business-models:scan` > `business-models:canvas` >\",\n      \"   `business-models:complete`.\",\n      \"2. Transition `status:ready` → `status:in-progress` and create the\",\n      \"   branch per your project's branch-naming convention.\",\n      \"3. Execute the phase handler that matches the issue's\",\n      \"   `business-models:*` label.\",\n      \"4. Commit, push, open a PR (if applicable), and close the issue per\",\n      `   your project's PR workflow — see the **${ISSUE_CLOSE_SECTION_TITLE}**`,\n      \"   section below before you close anything yourself.\",\n      \"   Stamp every PR you open with the `origin:agent` label — see the\",\n      \"   **Origin label** section below.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...renderClaimVerificationSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderOriginStampSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderIssueClosePolicySection(),\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 1: Scan (`business-models:scan`)\",\n      \"\",\n      \"**Goal:** Read upstream industry and profile artifacts to identify\",\n      \"which segments need a business-model canvas. Produce a prioritized\",\n      \"scan report and create one `business-models:canvas` issue per\",\n      \"in-scope segment.\",\n      \"\",\n      \"**Budget:** No web searches. Reading existing repo content only. One\",\n      \"scan-report file, plus N canvas issues.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the scan scope** from the issue body. The body should\",\n      \"   include:\",\n      \"   - An industry slug (or industry name) identifying the target\",\n      \"     vertical\",\n      \"   - Authorized input paths — typically an industry-discovery plan\",\n      \"     file (`<PLANS_DIR>/<slug>.plan.md`) or a research deliverable\",\n      \"   - Optional: `<INDUSTRY_SLUG>` override, custom output paths,\",\n      \"     existing segments to exclude\",\n      \"\",\n      \"2. **Read the industry-discovery plan** if one is cited. The plan's\",\n      \"   `## Cleared Verticals` table lists segments that already advanced;\",\n      \"   the scan decides which of those need a canvas.\",\n      \"\",\n      \"3. **Check existing coverage** under `<BUSINESS_MODELS_ROOT>`. For\",\n      \"   each candidate segment, confirm no `business-model.md` already\",\n      \"   exists for it. Skip segments that are already modelled (unless the\",\n      \"   issue explicitly requests a refresh).\",\n      \"\",\n      \"4. **Check open issues.** Skip any segment that already has an open\",\n      \"   `business-models:canvas` or `business-models:complete` issue.\",\n      \"\",\n      \"5. **Classify each segment** as one of:\",\n      \"   - **Full document** — the segment warrants its own canvas.\",\n      \"   - **Variation of <parent>** — the segment is a sub-variation\",\n      \"     of an existing or planned parent canvas. Note which parent.\",\n      \"   - **Defer** — the segment is in scope but blocked on missing\",\n      \"     upstream research; note the blocker.\",\n      \"\",\n      \"6. **Write the scan report** to\",\n      \"   `<SCAN_DIR>/<INDUSTRY_SLUG>-<YYYY-MM-DD>.scan.md`:\",\n      \"\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"Business Model Scan: <Industry Name>\"',\n      \"   slug: <INDUSTRY_SLUG>\",\n      \"   date: YYYY-MM-DD\",\n      \"   parent_issue: <N>\",\n      \"   status: complete\",\n      \"   ---\",\n      \"\",\n      \"   ## Source Inputs\",\n      \"   - Industry plan: <relative path>\",\n      \"   - Prior research: <relative path> (optional)\",\n      \"\",\n      \"   ## Existing Coverage\",\n      \"   - <segment>: has canvas / no canvas / issue open\",\n      \"\",\n      \"   ## Segments Needing Analysis\",\n      \"\",\n      \"   ### <Segment Name>\",\n      \"   - **Priority:** high / medium / low\",\n      \"   - **Classification:** full document / variation of <parent> / defer\",\n      \"   - **Rationale:** <why this segment needs analysis>\",\n      \"   - **Expected variations:** <size / geography / regulatory>\",\n      \"\",\n      \"   ## Recommendations\",\n      \"   - <segment> → open canvas issue (priority: <level>)\",\n      \"   - <segment> → variation of <parent>, handle in parent's complete phase\",\n      \"   - <segment> → defer until <condition>\",\n      \"   ```\",\n      \"\",\n      \"7. **Create one `business-models:canvas` issue per in-scope segment**\",\n      \"   with `Depends on: #<scan-issue>`. Each canvas issue body\",\n      \"   references the scan report, the industry, the segment name, and\",\n      \"   the authorized source list.\",\n      \"\",\n      \"8. **Commit and push** the scan report. Close the scan issue\",\n      `   ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 2: Canvas (`business-models:canvas`)\",\n      \"\",\n      \"**Goal:** Research and write a Business Model Canvas for one\",\n      \"industry segment — all nine blocks, each traced to a source.\",\n      \"\",\n      \"**Budget:** 4–8 targeted web searches to fill gaps not covered by\",\n      \"existing research. Reading industry research + web results, writing\",\n      \"one document, creating one downstream `business-models:complete`\",\n      \"issue.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the scan report and industry source** for context on this\",\n      \"   segment.\",\n      \"\",\n      \"2. **Read existing industry research** under\",\n      \"   `<BUSINESS_MODELS_ROOT>/<industry>/` for prior notes on this\",\n      \"   segment.\",\n      \"\",\n      \"3. **Read the skill's canvas template** at\",\n      \"   `.claude/skills/canvas-business-model/_references/templates/_template-canvas.md`\",\n      \"   (or the equivalent path under the `/cursor/skills/` tree on Cursor\",\n      \"   platforms). The template is authoritative — copy its structure\",\n      \"   verbatim into the output document, then populate each block.\",\n      \"\",\n      \"4. **Assess research gaps.** Determine which canvas blocks can be\",\n      \"   filled from existing research and which need targeted web\",\n      \"   searches. Prioritize blocks with the least existing coverage.\",\n      \"\",\n      \"5. **Execute targeted web searches** (4–8 total). Focus on:\",\n      \"   - Revenue models and pricing structures for this segment\",\n      \"   - Customer segment definitions and buyer personas\",\n      \"   - Key partnerships and supply-chain relationships\",\n      \"   - Cost-structure breakdown\",\n      \"   - Channel and distribution patterns\",\n      \"   - Regulatory and compliance factors affecting the business model\",\n      \"\",\n      \"6. **Write the canvas document** to\",\n      \"   `<BUSINESS_MODELS_ROOT>/<industry>/segments/<SEGMENT_SLUG>/business-model.md`\",\n      \"   following the template. Fill every one of the nine canvas blocks.\",\n      \"   Leave the `## Value Streams` and `## Variations` placeholders for\",\n      \"   the complete phase.\",\n      \"\",\n      \"   **Canvas rules:**\",\n      \"   - Every canvas block must have content — no empty blocks. Use\",\n      \"     `Not applicable — <reason>` when a block genuinely does not\",\n      \"     apply.\",\n      \"   - Every factual claim must trace to a source: either a research\",\n      \"     doc already on disk or a web-search result cited in the\",\n      \"     `## Sources` section.\",\n      \"   - Use Starlight frontmatter (`title`, `description`).\",\n      \"   - Link to related docs (industry plan, customer research, prior\",\n      \"     profiles) with **relative markdown paths** — never absolute\",\n      \"     `https://github.com/...` URLs.\",\n      \"\",\n      \"7. **Create the segment index** at\",\n      \"   `<BUSINESS_MODELS_ROOT>/<industry>/segments/<SEGMENT_SLUG>/index.md`\",\n      \"   if it does not already exist. Follow the section-index-page\",\n      \"   contract in the `shared-editing-safety` rule: a 1–2 paragraph summary of the\",\n      \"   segment plus a linked listing of every page in the folder\",\n      \"   (`./business-model.md` and any value-stream / capability pages\",\n      \"   that land later). No body `# Heading` — the frontmatter\",\n      \"   `title:` already renders as the page H1.\",\n      \"\",\n      \"8. **Create one `business-models:complete` issue** with\",\n      \"   `Depends on: #<canvas-issue>`. Its body references the path to\",\n      \"   the canvas document and names the industry and segment.\",\n      \"\",\n      \"9. **Commit and push** the canvas document. Close the canvas issue\",\n      `   ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 3: Complete (`business-models:complete`)\",\n      \"\",\n      \"**Goal:** Derive BIZBOK value streams from the canvas, document\",\n      \"variations (size, geography, regulatory), and hand off to the\",\n      \"`bcm-writer` bundle for capability modelling.\",\n      \"\",\n      \"**Budget:** 2–4 targeted web searches (regulatory and geographic\",\n      \"specifics). Reading the canvas, editing the same document,\",\n      \"creating downstream issues.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"#### Part A: Value Streams\",\n      \"\",\n      \"1. **Read the canvas document** referenced in the issue body.\",\n      \"\",\n      \"2. **Identify value streams.** Each major Value Proposition\",\n      \"   typically maps to one value stream. Common patterns:\",\n      \"\",\n      \"   | Canvas Signal | Value Stream Pattern |\",\n      \"   |---------------|----------------------|\",\n      \"   | A distinct Value Proposition | One value stream delivering that proposition |\",\n      \"   | A cluster of Key Activities serving the same VP | Stages within that stream |\",\n      \"   | Different Customer Segments receiving the same VP | Same stream, different stakeholder triggers |\",\n      \"   | A Key Activity supporting multiple VPs | Shared capability across streams |\",\n      \"\",\n      \"3. **Define each value stream** with BIZBOK structure: name,\",\n      \"   triggering stakeholder, value proposition (verbatim from the\",\n      \"   canvas), ordered stages, stage outcomes, and the Key Activities\",\n      \"   mapping for each stage.\",\n      \"\",\n      \"4. **Edit the canvas document** to replace the\",\n      \"   `## Value Streams` placeholder:\",\n      \"\",\n      \"   ```markdown\",\n      \"   ## Value Streams\",\n      \"\",\n      \"   ### <Value Stream Name>\",\n      \"\",\n      \"   **Triggering stakeholder:** <who initiates>\",\n      \"   **Value proposition:** <from the canvas>\",\n      \"\",\n      \"   | Stage | Description | Key Activities (from Canvas) | Stage Outcome |\",\n      \"   |-------|-------------|------------------------------|---------------|\",\n      \"   | <Stage 1> | <what happens> | <activities> | <outcome> |\",\n      \"   | <Stage 2> | <what happens> | <activities> | <outcome> |\",\n      \"   ```\",\n      \"\",\n      \"   **Value stream rules:**\",\n      \"   - **Minimum 2 value streams** per segment (most have 3–5).\",\n      \"   - Every value stream must trace to a Value Proposition on the\",\n      \"     canvas.\",\n      \"   - Every stage must map to at least one Key Activity on the\",\n      \"     canvas.\",\n      \"   - Stages are ordered — each stage's output feeds the next stage's\",\n      \"     input.\",\n      \"   - A single Key Activity may appear in multiple value streams.\",\n      \"   - Value-stream names are **noun phrases**, not verbs.\",\n      \"\",\n      \"#### Part B: Variations\",\n      \"\",\n      \"5. **Research variations** using 2–4 targeted web searches:\",\n      \"   - How do businesses in this segment differ at SMB vs. mid-market\",\n      \"     vs. enterprise scale?\",\n      \"   - Are there geographic or regulatory differences (e.g. varying\",\n      \"     privacy laws, industry-specific certifications)?\",\n      \"   - Do revenue models or key partnerships change by size or region?\",\n      \"\",\n      \"6. **Edit the canvas document** to replace the `## Variations`\",\n      \"   placeholder with size, geographic, and regulatory sub-sections.\",\n      \"\",\n      \"   **Variation rules:**\",\n      \"   - **Size variations are always required.** At minimum, document\",\n      \"     SMB vs. enterprise.\",\n      \"   - **Geographic variations are required when** the segment\",\n      \"     operates internationally and regulatory or market-structure\",\n      \"     differences affect the business model. Skip with\",\n      \"     `Not applicable — <reason>` if genuinely not relevant.\",\n      \"   - **Regulatory variations are required when** industry-specific\",\n      \"     standards or certifications exist that affect how the business\",\n      \"     model operates.\",\n      \"   - Only include canvas blocks that actually differ. Do not pad\",\n      '     with \"No difference\" rows.',\n      \"\",\n      \"#### Part C: Value Stream → Capability Linking\",\n      \"\",\n      \"7. **Surface capabilities for downstream BCM modelling.** For each\",\n      \"   value stream stage that maps to a Key Activity the consuming\",\n      \"   project needs to implement, identify the underlying *capability*\",\n      \"   (a noun phrase — what the business does, not how). Typical\",\n      \"   extraction:\",\n      \"\",\n      \"   - Look at each value-stream stage's Key Activities mapping.\",\n      \"   - Each Key Activity usually corresponds to one capability (e.g.\",\n      \"     Key Activity `Schedule appointments` → capability\",\n      \"     `Appointment Scheduling`).\",\n      \"   - Deduplicate across stages and across value streams.\",\n      \"\",\n      \"8. **Add a `## Value Stream to Capability Linking` section** to the\",\n      \"   canvas document, immediately after `## Variations`:\",\n      \"\",\n      \"   ```markdown\",\n      \"   ## Value Stream to Capability Linking\",\n      \"\",\n      \"   | Value Stream | Stage | Key Activity | Capability (noun) | BCM Issue |\",\n      \"   |--------------|-------|--------------|-------------------|-----------|\",\n      \"   | <stream> | <stage> | <activity> | <capability name> | #<bcm-outline-issue> |\",\n      \"   ```\",\n      \"\",\n      \"9. **For each distinct capability surfaced above**, check whether a\",\n      \"   BCM document already exists under the consuming project's\",\n      \"   `<BCM_DOC_ROOT>`. For capabilities that are **not yet modelled**,\",\n      \"   create one `bcm:outline` issue (owned by the downstream\",\n      \"   `bcm-writer` bundle) per capability, citing the canvas path and\",\n      \"   the specific value-stream stage the capability appears in. Fill\",\n      \"   the `BCM Issue` column of the linking table as each issue is\",\n      \"   created so the table is cross-linked before the complete issue\",\n      \"   closes.\",\n      \"\",\n      \"#### Part D: Commit and Handoffs\",\n      \"\",\n      \"10. **Commit and push** the updated canvas document.\",\n      \"\",\n      \"11. **Comment on the canvas issue** and the scan issue with a short\",\n      \"    summary: value-stream count, variation coverage, and the list of\",\n      \"    `bcm:outline` issues created.\",\n      \"\",\n      `12. **Close the complete issue** ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Coordination with Other Agents\",\n      \"\",\n      \"### Upstream: industry-discovery bundle\",\n      \"\",\n      \"`industry-discovery` produces the plan files this pipeline reads as\",\n      \"input to the scan phase. The scan phase's issue body should cite the\",\n      \"plan file (`<PLANS_DIR>/<slug>.plan.md`) as its source of\",\n      \"segments. Business-model scan issues are typically created as a\",\n      \"follow-up to an industry plan that cleared the fit threshold.\",\n      \"\",\n      \"### Upstream: research-pipeline bundle\",\n      \"\",\n      \"If a canvas block cannot be adequately filled from existing research\",\n      \"and the web-search budget is exhausted, create a `research:scope`\",\n      \"issue to commission a deeper research dive. Block the canvas issue on\",\n      \"the new research issue rather than shipping a thinly-sourced block.\",\n      \"\",\n      \"### Downstream: bcm-writer bundle\",\n      \"\",\n      \"Canvas documents are the authoritative source for value streams that\",\n      \"the `bcm-writer`'s Value Stream Mapping section consumes. Phase 3\",\n      \"opens `bcm:outline` issues for every distinct capability surfaced in\",\n      \"Key Activities that does not yet have a BCM document. The\",\n      \"`bcm-writer` bundle picks those issues up and decomposes each\",\n      \"capability into an L1/L2/L3 tree, citing the canvas path in its\",\n      \"Traceability section.\",\n      \"\",\n      \"### Downstream: company-profile bundle\",\n      \"\",\n      \"The `company-profile` bundle's match phase reads\",\n      \"`<BUSINESS_MODELS_ROOT>` (same default path — see Configurable\",\n      \"Paths) to identify which of its profiled companies operate in a given\",\n      \"segment. When a canvas is published, company-profile's `match` phase\",\n      \"appends a bidirectional cross-link between the matched profile and\",\n      \"the canvas. This agent never rewrites profile bodies — it only\",\n      \"publishes the canvas.\",\n      \"\",\n      \"### File Boundaries\",\n      \"\",\n      \"- **Reads:**\",\n      \"  - `<BUSINESS_MODELS_ROOT>/` — prior canvases, industry indexes\",\n      \"  - `<PLANS_DIR>/` — industry-discovery plan files\",\n      \"  - `<DELIVERABLES_DIR>/` — research deliverables\",\n      \"  - `<docsRoot>/` — any file for context\",\n      \"- **Writes:**\",\n      \"  - `<SCAN_DIR>/<INDUSTRY_SLUG>-<YYYY-MM-DD>.scan.md` (Phase 1)\",\n      \"  - `<BUSINESS_MODELS_ROOT>/<industry>/segments/<SEGMENT_SLUG>/business-model.md`\",\n      \"    (Phases 2–3)\",\n      \"  - `<BUSINESS_MODELS_ROOT>/<industry>/segments/<SEGMENT_SLUG>/index.md`\",\n      \"    (Phase 2, when missing)\",\n      \"- **Never writes to:**\",\n      \"  - `<BCM_DOC_ROOT>/` (the `bcm-writer` bundle owns this)\",\n      \"  - `<REQUIREMENTS_ROOT>/` (the `requirements-writer` bundle owns\",\n      \"    this)\",\n      \"  - `<PEOPLE_PROFILES_DIR>/`, `<COMPANIES_PROFILES_DIR>/`,\",\n      \"    `<SOFTWARE_PROFILES_DIR>/` (the profile bundles own these)\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Blocked Issues\",\n      \"\",\n      \"Follow your project's shared Blocked Issues procedure. Additional\",\n      \"block reasons specific to business-model authoring:\",\n      \"\",\n      \"- **Industry source missing.** The scan-phase issue cites a plan\",\n      \"  file that does not exist on disk.\",\n      \"- **Insufficient research.** The canvas phase cannot fill one or\",\n      \"  more blocks from existing research or targeted web searches (open\",\n      \"  a `research:scope` issue and block on it).\",\n      \"- **Conflicting sources.** Two authoritative sources contradict each\",\n      \"  other on a canvas block and the conflict cannot be reconciled by\",\n      \"  the agent.\",\n      \"- **Segment definition ambiguous.** The scan report flagged the\",\n      \"  segment as needing human clarification before a canvas can be\",\n      \"  authored.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Output Boundaries\",\n      \"\",\n      \"This agent writes **only** to the directories listed under File\",\n      \"Boundaries above. It does not write capability models, requirement\",\n      \"documents, people profiles, company profiles, or software profiles.\",\n      \"Work it surfaces in those domains is delegated via issues to the\",\n      \"appropriate specialist bundle (`bcm-writer`, `requirements-writer`,\",\n      \"`people-profile`, `company-profile`, `software-profile`).\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Rules\",\n      \"\",\n      \"- **One phase per session.** Never run two phases back-to-back in a\",\n      \"  single session.\",\n      \"- **Persist before closing.** Every phase must write its output file\",\n      \"  before closing its issue.\",\n      \"- **Canvas blocks are never empty.** Use\",\n      \"  `Not applicable — <reason>` when a block genuinely does not apply.\",\n      \"- **Size variations are always required.** Every segment has\",\n      \"  meaningful differences between SMB and enterprise operations.\",\n      \"- **Value streams derive from the canvas.** Key Activities and\",\n      \"  Value Propositions on the canvas define value streams. Do not\",\n      \"  invent value streams that do not trace to the canvas.\",\n      \"- **One segment per document.** Sub-segments share the parent\",\n      \"  document with a variation section unless their business model is\",\n      \"  fundamentally different.\",\n      \"- **No fabrication.** Every canvas block and every value-stream\",\n      \"  stage must trace to a cited source. Do not populate from general\",\n      \"  knowledge alone.\",\n      \"- **Relative links only.** Cross-references between docs use\",\n      \"  relative markdown paths, never absolute `https://github.com/...`\",\n      \"  URLs.\",\n      \"- **Produce canvases, not capabilities.** Capability modelling is\",\n      \"  the responsibility of the `bcm-writer` bundle. Hand off surfaced\",\n      \"  capabilities via `bcm:outline` issues; do not write capability\",\n      \"  decomposition in the canvas itself.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off the scan phase of a business-model cycle. */\nfunction buildScanBusinessModelsSkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"scan-business-models\",\n    description:\n      \"Kick off the scan phase of a business-model analysis cycle. Creates a business-models:scan issue for the supplied industry and dispatches Phase 1 of the business-models-analyst, which reads industry-discovery output and identifies segments needing a canvas.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"business-models-analyst\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Scan Business Models\",\n      \"\",\n      \"Kick off a business-model analysis cycle. Creates a\",\n      \"`business-models:scan` issue carrying the industry scope and\",\n      \"dispatches Phase 1 (Scan) in the business-models-analyst agent.\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/scan-business-models <industry-slug>\",\n      \"\",\n      \"Optional extensions in the issue body:\",\n      \"- `plan: <path>` — path to the industry-discovery plan file that\",\n      \"  cleared this industry for downstream research (e.g.\",\n      `  \\`${paths.industriesRoot}/plans/<slug>.plan.md\\`)`,\n      \"- `sources: <list>` — additional authorized input paths\",\n      \"- `exclude: <segment list>` — segments already covered to skip\",\n      \"- `slug: <kebab-case>` — override the derived industry slug\",\n      \"\",\n      \"## Default Paths\",\n      \"\",\n      `If the project has no override in \\`${paths.docsRoot}/project-context.md\\` or`,\n      \"`agentConfig.rules`, outputs land under:\",\n      \"\",\n      `- Scan report: \\`${paths.researchRoot}/business-models/<slug>-YYYY-MM-DD.scan.md\\``,\n      `- Canvas docs (produced by Phase 2): \\`${paths.docsRoot}/industry-research/<industry>/segments/<segment-slug>/business-model.md\\``,\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `business-models:scan` issue with `type:business-model`,\",\n      `   \\`priority:${labelsForPhase(issueDefaults, \"business-models:scan\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"business-models:scan\").status}\\`. The body must include the`,\n      \"   industry slug, the source plan path (if any), and any overrides.\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 1 (Scan) of the business-models-analyst agent.\",\n      \"3. Phase 1 creates one `business-models:canvas` issue per in-scope\",\n      \"   segment. Each canvas issue declares its `Depends on:`\",\n      \"   predecessor.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- A scan report under the project's business-models scan directory,\",\n      \"  listing which segments need canvases and which are already\",\n      \"  covered or deferred.\",\n      \"- One `business-models:canvas` issue per segment classified as\",\n      \"  `full document` in the scan report.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/**\n * Skill that kicks off the canvas phase for one segment. Normally\n * Phase 1 (Scan) creates canvas issues automatically, but this skill\n * is available for manual invocation when an operator wants to author\n * a canvas without a prior scan (e.g. a one-off segment carved out of\n * an already-modelled industry).\n */\nfunction buildCanvasBusinessModelSkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"canvas-business-model\",\n    description:\n      \"Kick off the canvas phase of a business-model analysis cycle. Creates a business-models:canvas issue for the supplied industry/segment and dispatches Phase 2 of the business-models-analyst, which researches and writes the Osterwalder nine-block canvas.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"business-models-analyst\",\n    platforms: { cursor: { exclude: true } },\n    referenceFiles: BUSINESS_MODELS_CANVAS_REFERENCE_FILES,\n    instructions: [\n      \"# Canvas Business Model\",\n      \"\",\n      \"Author a Business Model Canvas for one industry segment. Creates a\",\n      \"`business-models:canvas` issue and dispatches Phase 2 (Canvas) in\",\n      \"the business-models-analyst agent.\",\n      \"\",\n      \"Most cycles do not invoke this skill directly — Phase 1 (Scan)\",\n      \"creates canvas issues automatically from the scan report. Use this\",\n      \"skill when:\",\n      \"\",\n      \"- A new segment was carved out of an already-modelled industry\",\n      \"- A human operator wants to author a canvas without a prior scan\",\n      \"- The scan report deferred a segment and the blocker is now\",\n      \"  resolved\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/canvas-business-model <industry-slug>:<segment-slug>\",\n      \"\",\n      \"Optional extensions in the issue body:\",\n      \"- `segment_name: <name>` — human-readable segment name (defaults to\",\n      \"  the slug prettified)\",\n      \"- `sources: <list>` — authorized research-input paths\",\n      \"- `scan: <path>` — prior scan report that identified this segment\",\n      \"  (optional when invoked manually)\",\n      \"\",\n      \"## Canvas Template\",\n      \"\",\n      \"This skill ships a verbatim canvas template at\",\n      \"`.claude/skills/canvas-business-model/_references/templates/_template-canvas.md`.\",\n      \"The Phase 2 handler reads that file as its authoritative structure —\",\n      \"every canvas document copies the template and fills each of the\",\n      \"nine blocks, leaving the `## Value Streams` and `## Variations`\",\n      \"placeholders for Phase 3 (Complete).\",\n      \"\",\n      \"## Default Paths\",\n      \"\",\n      `If the project has no override in \\`${paths.docsRoot}/project-context.md\\` or`,\n      \"`agentConfig.rules`, the canvas lands at:\",\n      \"\",\n      `\\`${paths.docsRoot}/industry-research/<industry>/segments/<segment-slug>/business-model.md\\``,\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `business-models:canvas` issue with\",\n      `   \\`type:business-model\\`, \\`priority:${labelsForPhase(issueDefaults, \"business-models:canvas\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"business-models:canvas\").status}\\`.`,\n      \"   The body must include the industry slug, segment slug, and any\",\n      \"   scan-report reference.\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 2 (Canvas) of the business-models-analyst agent.\",\n      \"3. Phase 2 writes the nine-block canvas and creates a\",\n      \"   `business-models:complete` issue for the downstream Phase 3.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- A new `business-model.md` with all nine canvas blocks populated.\",\n      \"- A segment `index.md` in the same folder (if missing).\",\n      \"- One `business-models:complete` issue cross-linking back to the\",\n      \"  canvas.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off the complete phase for one canvas. */\nfunction buildCompleteBusinessModelSkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"complete-business-model\",\n    description:\n      \"Kick off the complete phase of a business-model analysis cycle. Creates a business-models:complete issue for an already-authored canvas and dispatches Phase 3 of the business-models-analyst, which derives BIZBOK value streams, documents variations, and hands off capability work to bcm-writer.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"business-models-analyst\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Complete Business Model\",\n      \"\",\n      \"Close out a business-model analysis cycle. Creates a\",\n      \"`business-models:complete` issue for a canvas that already has its\",\n      \"nine blocks populated and dispatches Phase 3 (Complete) in the\",\n      \"business-models-analyst agent.\",\n      \"\",\n      \"Phase 3 appends BIZBOK value streams, documents size / geographic /\",\n      \"regulatory variations, adds a `## Value Stream to Capability\",\n      \"Linking` section, and opens one `bcm:outline` issue per\",\n      \"undeployed capability for the downstream `bcm-writer` bundle.\",\n      \"\",\n      \"Most cycles do not need this skill — Phase 2 (Canvas) creates the\",\n      \"complete issue automatically. Use this skill when:\",\n      \"\",\n      \"- A human authored the canvas and only needs the agent to attach\",\n      \"  value streams and variations\",\n      \"- The canvas was imported from another source and needs value-\",\n      \"  stream completion\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/complete-business-model <industry-slug>:<segment-slug>\",\n      \"\",\n      \"## Default Paths\",\n      \"\",\n      `If the project has no override in \\`${paths.docsRoot}/project-context.md\\` or`,\n      \"`agentConfig.rules`, the target canvas lives at:\",\n      \"\",\n      `\\`${paths.docsRoot}/industry-research/<industry>/segments/<segment-slug>/business-model.md\\``,\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `business-models:complete` issue with\",\n      `   \\`type:business-model\\`, \\`priority:${labelsForPhase(issueDefaults, \"business-models:complete\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"business-models:complete\").status}\\`.`,\n      \"   Body must include the canvas document path.\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 3 (Complete) of the business-models-analyst agent.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- Updates to `business-model.md` — `## Value Streams`, \",\n      \"  `## Variations`, and `## Value Stream to Capability Linking`\",\n      \"  sections populated.\",\n      \"- One `bcm:outline` issue (consumed by the `bcm-writer` bundle)\",\n      \"  per distinct capability surfaced from Key Activities that does\",\n      \"  not already have a BCM document.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/**\n * Build the business-models bundle with the supplied resolved paths.\n *\n * Every reference to a canonical agent path (docs root, research root,\n * etc.) inside the rule / skill / sub-agent content strings is an\n * interpolation of the supplied `paths` struct, so a consumer override\n * of `AgentConfigOptions.paths` propagates to the rendered output.\n *\n * The bundle sits between `industry-discovery` (upstream, selects\n * verticals) and `bcm-writer` (downstream, models capabilities). It\n * assumes `bcm-writer` is enabled so Phase 3 can hand off surfaced\n * capabilities via `bcm:outline` issues, and it is read by\n * `company-profile` via the shared `<BUSINESS_MODELS_ROOT>` default\n * path (`<docsRoot>/industry-research/`).\n */\nexport function buildBusinessModelsBundle(\n  paths: ResolvedAgentPaths = DEFAULT_AGENT_PATHS,\n  issueDefaults: ResolvedIssueDefaults = DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n): AgentRuleBundle {\n  return {\n    name: \"business-models\",\n    description:\n      \"Business-model authoring pipeline: Osterwalder Business Model Canvas plus BIZBOK value streams per industry segment. 3 phases (scan, canvas, complete) with business-models:* phase labels. Sits between industry-discovery and bcm-writer in the research pipeline. Enabled by default; domain-neutral; filesystem-durable between phases.\",\n    appliesWhen: () => true,\n    rules: [\n      {\n        name: \"business-models-workflow\",\n        description:\n          \"Describes the 3-phase business-model pipeline, the business-models:* label taxonomy, and the handoff boundaries with industry-discovery (upstream) and bcm-writer (downstream).\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Business Models Workflow\",\n          \"\",\n          \"Use `/scan-business-models <industry-slug>` to kick off a\",\n          \"business-model analysis cycle. The pipeline runs in 3 phases —\",\n          \"scan, canvas, complete — each tracked by its own GitHub issue\",\n          \"labeled `business-models:scan`, `business-models:canvas`, or\",\n          \"`business-models:complete`. All issues carry `type:business-model`.\",\n          \"\",\n          \"Two additional user-invocable skills drive the downstream phases\",\n          \"directly when the default pipeline needs to be entered mid-\",\n          \"stream:\",\n          \"\",\n          \"- `/canvas-business-model <industry>:<segment>` — author the\",\n          \"  nine-block Osterwalder canvas for one segment (normally created\",\n          \"  by the scan phase automatically).\",\n          \"- `/complete-business-model <industry>:<segment>` — derive BIZBOK\",\n          \"  value streams, document variations, and hand off capabilities\",\n          \"  to `bcm-writer` (normally created by the canvas phase\",\n          \"  automatically).\",\n          \"\",\n          \"The bundle sits between `industry-discovery` (which picks\",\n          \"verticals and segments) and `bcm-writer` (which models the\",\n          \"capabilities needed to execute). Canvases describe *how the\",\n          \"business operates in a segment*; the downstream BCM writer then\",\n          \"derives capability models from the Key Activities and value\",\n          \"streams authored here. The `company-profile` bundle reads the\",\n          \"same `<BUSINESS_MODELS_ROOT>` directory\",\n          `(\\`${paths.docsRoot}/industry-research/\\` by default) to match profiled`,\n          \"companies against published canvases.\",\n          \"\",\n          \"See the `business-models-analyst` agent definition for full\",\n          \"workflow details, default paths, the Osterwalder/BIZBOK\",\n          \"methodology, and phase-by-phase instructions.\",\n        ].join(\"\\n\"),\n        platforms: {\n          cursor: { exclude: true },\n        },\n        tags: [\"workflow\"],\n      },\n    ],\n    skills: [\n      buildScanBusinessModelsSkill(paths, issueDefaults),\n      buildCanvasBusinessModelSkill(paths, issueDefaults),\n      buildCompleteBusinessModelSkill(paths, issueDefaults),\n    ],\n    subAgents: [buildBusinessModelsAnalystSubAgent(paths)],\n    labels: [\n      {\n        name: \"type:business-model\",\n        color: \"5319E7\",\n        description:\n          \"Authors or updates a Business Model Canvas plus BIZBOK value streams for an industry segment\",\n      },\n      {\n        name: \"business-models:scan\",\n        color: \"C5DEF5\",\n        description:\n          \"Phase 1: read industry-discovery output and identify segments needing a business-model canvas\",\n      },\n      {\n        name: \"business-models:canvas\",\n        color: \"BFDADC\",\n        description:\n          \"Phase 2: research and write the nine-block Osterwalder canvas for one segment\",\n      },\n      {\n        name: \"business-models:complete\",\n        color: \"D4C5F9\",\n        description:\n          \"Phase 3: derive BIZBOK value streams, document variations, and hand off capabilities to bcm-writer\",\n      },\n    ],\n  };\n}\n\n/**\n * Default-paths instance of the business-models bundle, preserved for\n * backward compatibility with consumers that import the const\n * directly. The factory above is the canonical entry point when a\n * consumer supplies `AgentConfigOptions.paths`.\n */\nexport const businessModelsBundle: AgentRuleBundle =\n  buildBusinessModelsBundle();\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { renderClaimVerificationSection } from \"./claim-verification\";\nimport {\n  ISSUE_CLOSE_RULE_REFERENCE,\n  ISSUE_CLOSE_SECTION_TITLE,\n  renderIssueClosePolicySection,\n} from \"./issue-close\";\nimport {\n  DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n  ResolvedIssueDefaults,\n  labelsForPhase,\n} from \"./issue-defaults\";\nimport { renderIssueTypeAssignmentStep } from \"./issue-type\";\nimport { renderOriginStampSection } from \"./origin-label\";\nimport { DEFAULT_AGENT_PATHS, ResolvedAgentPaths } from \"./paths\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n  AGENT_MODEL,\n  AGENT_RULE_SCOPE,\n  AgentModel,\n  AgentSkill,\n  AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that researches and profiles external companies into\n * structured markdown. Produces one profile per company and enqueues\n * downstream research issues for people and software products surfaced\n * during profiling (handed off to the `people-profile` and\n * `software-profile` bundles).\n *\n * In addition to the initial research → draft → followup cycle, the\n * agent supports three maintenance / synthesis phases:\n *\n * - `company:match` — enrich an existing profile with business-model\n *   and segment context by reading adjacent docs and editing the\n *   profile in place. No web searches.\n * - `company:refresh` — re-verify an existing profile with a small\n *   number of targeted web searches and update it in place.\n * - `company:analyze` — pure synthesis across multiple profiles in a\n *   target segment, producing a segment-level competitive analysis\n *   document. Blocked on open `company:draft` issues for the segment.\n *\n * The prompt deliberately avoids hardcoded domains, companies, or source\n * projects. Consumers configure the company taxonomy scope, output\n * paths, and downstream trigger behavior via the skill invocation and\n * by extending the rule in their own `agentConfig.rules`.\n */\nfunction buildCompanyProfileAnalystSubAgent(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n  tier: AgentModel,\n): AgentSubAgent {\n  return {\n    name: \"company-profile-analyst\",\n    description:\n      \"Researches an external company (competitor, vendor, partner, customer, etc.) from public sources and produces a structured markdown profile, then enqueues downstream `people:research` and `software:research` issues for notable people and software products surfaced during profiling. Also handles profile enrichment against business-model canvases (`company:match`), maintenance refreshes on a configurable staleness cadence (`company:refresh`), and cross-profile competitive synthesis for a segment (`company:analyze`). One company or segment per session, tracked by company:* GitHub issue labels.\",\n    model: tier,\n    maxTurns: 80,\n    platforms: { cursor: { exclude: true } },\n    prompt: [\n      \"# Company Profile Analyst Agent\",\n      \"\",\n      \"You research a single external company from public sources and write\",\n      \"a structured markdown profile, then maintain it as facts drift and\",\n      \"roll profiles up into segment-level competitive analysis. Each\",\n      \"session claims one GitHub issue — one phase, one company (or one\",\n      \"segment for `company:analyze`) — and produces files on disk plus\",\n      \"optional follow-up research issues.\",\n      \"\",\n      \"This agent is **domain-neutral**. It makes no assumptions about what\",\n      \"the consuming project sells, which industry it serves, or which\",\n      \"companies matter to it. All domain-specific vocabulary, output\",\n      \"locations, and profile-template overrides come from the invoking\",\n      \"issue body or the consuming project's configuration.\",\n      \"\",\n      \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n      \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...PROJECT_CONTEXT_READER_SECTION,\n      \"## Design Principles\",\n      \"\",\n      \"1. **One company per session.** Never profile two companies in a\",\n      \"   single session, even if they came up together. The `company:analyze`\",\n      \"   phase is the single exception — it synthesizes across multiple\",\n      \"   profiles in **one segment** but never researches a new company.\",\n      \"2. **Public sources only.** Use the company's own site, press, product\",\n      \"   docs, job listings, and other public material. Do not attempt to\",\n      \"   access gated or paywalled content unless the invoking issue body\",\n      \"   explicitly authorizes it.\",\n      \"3. **Filesystem durability.** The profile file is the deliverable. It\",\n      \"   is committed to disk before the profile issue closes. Downstream\",\n      \"   phases read from disk — never rely on session memory.\",\n      \"4. **Generic over specific.** No hardcoded company types, taxonomies,\",\n      \"   or competitive assumptions. Use the generic company-type taxonomy\",\n      \"   below and let consuming projects override it.\",\n      \"5. **Cite everything.** Every non-trivial factual claim in the profile\",\n      \"   must carry a source citation (URL plus access date).\",\n      \"6. **Follow-up, don't widen scope.** If the session turns up adjacent\",\n      \"   research questions (a key person worth profiling, a product worth\",\n      \"   evaluating), emit a follow-up issue rather than expanding the\",\n      \"   profile beyond its scope. Notable people are handed off to the\",\n      \"   `people-profile` bundle via `people:research` issues; software\",\n      \"   products are handed off to the `software-profile` bundle via\",\n      \"   `software:research` issues.\",\n      \"7. **Enrichment is not re-research.** `company:match` reads existing\",\n      \"   docs and edits the profile; it never runs web searches. Refresh is\",\n      \"   the only maintenance phase that goes back to the public web.\",\n      \"8. **Synthesis waits for drafts.** `company:analyze` blocks if any\",\n      \"   `company:draft` issues for the target segment are still open.\",\n      \"   Never publish a partial landscape.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Company Type Taxonomy\",\n      \"\",\n      \"Pick exactly one type per company profile. The taxonomy is\",\n      \"deliberately generic — consuming projects override it via\",\n      \"`agentConfig.rules` if they need a domain-specific refinement.\",\n      \"\",\n      \"| Type | Use for |\",\n      \"|------|---------|\",\n      \"| `competitor` | Companies that sell a substitutable offering to the same customers. |\",\n      \"| `industry-player` | Notable companies in the same industry that are not direct competitors (adjacent offerings, upstream/downstream, ecosystem). |\",\n      \"| `software-vendor` | Companies whose software this project uses, integrates with, or evaluates as a build-vs-buy option. |\",\n      \"| `customer` | Existing or prospective customers worth understanding in depth. |\",\n      \"| `partner` | Strategic or channel partners, integrators, resellers, design partners. |\",\n      \"| `investor` | Funds, angels, corporate investors relevant to fundraising or market positioning. |\",\n      \"\",\n      \"If the company plausibly fits two types, prefer the one that reflects\",\n      \"the **reason the profile was requested**, and note the secondary type\",\n      \"in the profile body.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## State Machine Overview\",\n      \"\",\n      \"```\",\n      \"┌───────────────────┐     ┌──────────────────────┐     ┌───────────────────┐\",\n      \"│ 1. RESEARCH       │────▶│ 2. DRAFT PROFILE     │────▶│ 3. FOLLOWUP       │\",\n      \"│ Collect public    │     │ Write the structured │     │ Create follow-up  │\",\n      \"│ sources into a    │     │ markdown profile to  │     │ research issues   │\",\n      \"│ bounded notes     │     │ the configured path  │     │ for people and    │\",\n      \"│ file              │     │                      │     │ software surfaced │\",\n      \"└───────────────────┘     └──────────────────────┘     └───────────────────┘\",\n      \"                                                                │\",\n      \"                                                                ▼\",\n      \"                                                    ┌───────────────────┐\",\n      \"                                                    │ 4. MATCH          │\",\n      \"                                                    │ Enrich profile    │\",\n      \"                                                    │ with business-    │\",\n      \"                                                    │ model and segment │\",\n      \"                                                    │ context. No web.  │\",\n      \"                                                    └───────────────────┘\",\n      \"\",\n      \"┌───────────────────┐                           ┌───────────────────┐\",\n      \"│ 5. REFRESH        │  (cadence-driven,         │ 6. ANALYZE        │\",\n      \"│ Re-verify an      │   or on-demand)           │ Synthesize across │\",\n      \"│ existing profile  │                           │ profiles in one   │\",\n      \"│ with targeted web │                           │ segment. No web.  │\",\n      \"│ searches. Update  │                           │ Blocks on open    │\",\n      \"│ in place.         │                           │ company:draft.    │\",\n      \"└───────────────────┘                           └───────────────────┘\",\n      \"```\",\n      \"\",\n      \"**Issue labels encode the phase:**\",\n      \"\",\n      \"| Label | Phase | Session work |\",\n      \"|-------|-------|-------------|\",\n      \"| `company:research` | 1. Research | Gather public sources. Write a bounded research-notes file. Create the draft issue. |\",\n      \"| `company:draft` | 2. Draft | Read the research notes. Write the structured profile to `<PROFILES_DIR>`. Create the followup and (if enabled) match issues. |\",\n      \"| `company:followup` | 3. Followup | Read the profile. Enqueue people/software research issues for items surfaced in the profile. |\",\n      \"| `company:match` | 4. Match | Read the profile. Enrich it with business-model, segment, and size context from existing docs. Bidirectionally cross-link matched business-model files. No web. |\",\n      \"| `company:refresh` | 5. Refresh | Read an existing profile. Run 4–6 targeted web searches for recent developments. Update the profile in place and add a revision-history entry. |\",\n      \"| `company:analyze` | 6. Analyze | Read every profile in one segment. Write a segment-level competitive-analysis document combining feature matrix, positioning, and strategic implications. No web. |\",\n      \"\",\n      \"All issues also carry `type:company-profile` and a `status:*` label.\",\n      \"\",\n      \"**Issue count per company cycle:** 1 research + 1 draft + 0–1 followup +\",\n      \"0–1 match = **2–4 sessions** on the initial cycle. `company:refresh`\",\n      \"and `company:analyze` are independent downstream cycles that run on\",\n      \"their own cadence.\",\n      \"\",\n      \"**Shortened paths:**\",\n      \"- Research phase determines the company is out of scope (not\",\n      \"  relevant, insufficient public material) → research issue closes\",\n      \"  with a justification and no downstream issues are created → **1 session**.\",\n      \"- Short profile with no follow-ups needed and no business-model\",\n      \"  context to match against → **2 sessions**.\",\n      \"- Refresh that finds no material change → **1 session** (revision-\",\n      \"  history entry only, profile body unchanged).\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Configurable Paths\",\n      \"\",\n      \"The pipeline uses these placeholders. Consuming projects override the\",\n      \"defaults by passing paths in the `/profile-company`, `/match-company`,\",\n      \"`/refresh-company`, or `/analyze-segment` skill invocations, or by\",\n      \"extending this rule in their own `agentConfig.rules`.\",\n      \"\",\n      \"| Placeholder | Meaning | Default |\",\n      \"|-------------|---------|---------|\",\n      `| \\`<COMPANY_ROOT>\\` | Root folder for company profiles | \\`${paths.companiesRoot}/\\` |`,\n      \"| `<PROFILES_DIR>` | Final company profile files | `<COMPANY_ROOT>/profiles/` |\",\n      \"| `<NOTES_DIR>` | Research-notes files from Phase 1 | `<COMPANY_ROOT>/notes/` |\",\n      \"| `<ANALYSIS_DIR>` | Segment-level competitive-analysis documents from Phase 6 | `<COMPANY_ROOT>/analysis/` |\",\n      \"| `<COMPANY_SLUG>` | Short kebab-case slug identifying the company | derived from the company name |\",\n      \"| `<SEGMENT_SLUG>` | Short kebab-case slug identifying the industry segment | derived from the segment name |\",\n      `| \\`<BUSINESS_MODELS_ROOT>\\` | Where existing business-model canvases live (consumed by Phase 4) | \\`${paths.docsRoot}/industry-research/\\` |`,\n      `| \\`<PEOPLE_PROFILES_DIR>\\` | Where existing people profiles live (for duplicate detection during followup) | \\`${paths.peopleRoot}/profiles/\\` |`,\n      `| \\`<SOFTWARE_PROFILES_DIR>\\` | Where existing software profiles live (for duplicate detection during followup) | \\`${paths.softwareRoot}/profiles/\\` |`,\n      \"\",\n      `If \\`${paths.docsRoot}/project-context.md\\` specifies a different company-research`,\n      \"tree (for example by reusing the research-pipeline deliverables\",\n      \"folder), prefer that. Otherwise fall back to the defaults above.\",\n      \"Business-model canvases are managed by the `business-models` bundle —\",\n      \"this agent is a **read-only consumer** of `<BUSINESS_MODELS_ROOT>`,\",\n      \"with the single exception of appending a bidirectional cross-link\",\n      \"back to the matched profile (Phase 4, Step 6).\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Refresh Cadence\",\n      \"\",\n      \"Profiles go stale. Companies launch products, raise rounds, rotate\",\n      \"leadership, or pivot. The pipeline supports a configurable refresh\",\n      \"cadence so `company:refresh` issues can be filed on a schedule\",\n      \"without hardcoding the interval:\",\n      \"\",\n      \"- **Default staleness threshold:** 180 days from the profile's\",\n      \"  `date` frontmatter.\",\n      \"- **Override:** the invoking issue body may specify a `refresh_days: N`\",\n      \"  field, or the consuming project may set a project-wide default in\",\n      `  \\`${paths.docsRoot}/project-context.md\\` (look for a`,\n      \"  `## Refresh Cadence` section) or in `agentConfig.rules`.\",\n      \"\",\n      \"When the `/refresh-company` skill is invoked for a slug that already\",\n      \"has a profile:\",\n      \"\",\n      \"- If the profile is **younger** than the staleness threshold, the\",\n      \"  skill exits with a message pointing to the existing profile. Pass\",\n      \"  `force: true` in the issue body to refresh anyway.\",\n      \"- If the profile is **older** than the staleness threshold, the\",\n      \"  pipeline files a `company:refresh` issue and Phase 5 updates the\",\n      \"  existing file in place, preserving its slug and bumping the\",\n      \"  `date` frontmatter.\",\n      \"\",\n      \"Refresh mode never changes the profile's primary type without an\",\n      \"explicit override in the refresh request — type changes are material\",\n      \"and warrant a human review step.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Agent Loop\",\n      \"\",\n      \"Run this loop exactly once per session. Never start a second issue.\",\n      \"\",\n      \"1. Claim one open `type:company-profile` issue using phase priority:\",\n      \"   `company:research` > `company:draft` > `company:followup` >\",\n      \"   `company:match` > `company:refresh` > `company:analyze`.\",\n      \"2. Transition `status:ready` → `status:in-progress` and create the\",\n      \"   branch per your project's branch-naming convention.\",\n      \"3. Execute the phase handler that matches the issue's `company:*`\",\n      \"   label.\",\n      \"4. Commit, push, open a PR (if applicable), and close the issue per\",\n      `   your project's PR workflow — see the **${ISSUE_CLOSE_SECTION_TITLE}**`,\n      \"   section below before you close anything yourself.\",\n      \"   Stamp every PR you open with the `origin:agent` label — see the\",\n      \"   **Origin label** section below.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...renderClaimVerificationSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderOriginStampSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderIssueClosePolicySection(),\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 1: Research (`company:research`)\",\n      \"\",\n      \"**Goal:** Gather public sources into a bounded research-notes file.\",\n      \"\",\n      \"**Budget:** Public web search only, unless the issue body authorizes\",\n      \"additional sources. Write one notes file. Do not write the profile\",\n      \"in this phase.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the issue body.** It should include:\",\n      \"   - The company name and website (if known)\",\n      \"   - The requested company type from the taxonomy above\",\n      \"   - The reason the profile was requested (framing — what does the\",\n      \"     invoking project want to learn?)\",\n      \"   - Optional: `<COMPANY_SLUG>` override, custom output paths\",\n      \"\",\n      \"2. **Derive `<COMPANY_SLUG>`** if not supplied — a 2–4 word kebab-case\",\n      \"   summary of the company name. Ensure the slug is not already in use\",\n      \"   under `<PROFILES_DIR>/` or `<NOTES_DIR>/`.\",\n      \"\",\n      \"3. **Gather sources.** Prioritize in this order:\",\n      \"   - The company's own website (home, product, pricing, about, careers)\",\n      \"   - Recent public press releases and reputable news coverage\",\n      \"   - Public product documentation and changelogs\",\n      \"   - Job listings (signals on stack, team size, and hiring focus)\",\n      \"   - Public profiles on well-known directories (Crunchbase, LinkedIn\",\n      \"     company page, GitHub organization) when the issue body authorizes\",\n      \"     them\",\n      \"\",\n      \"4. **Write a research-notes file** to\",\n      \"   `<NOTES_DIR>/<COMPANY_SLUG>.notes.md`:\",\n      \"\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"Research Notes: <company name>\"',\n      \"   slug: <COMPANY_SLUG>\",\n      \"   company_type: <one of the taxonomy values>\",\n      \"   date: YYYY-MM-DD\",\n      \"   parent_issue: <N>\",\n      \"   ---\",\n      \"\",\n      \"   ## Framing\",\n      \"   <why this company was requested and what to learn>\",\n      \"\",\n      \"   ## Raw Findings\",\n      \"   - <finding> — source: <citation>\",\n      \"\",\n      \"   ## Candidate People of Interest\",\n      \"   - <name, role> — source: <citation>\",\n      \"\",\n      \"   ## Candidate Products / Software of Interest\",\n      \"   - <product name> — source: <citation>\",\n      \"\",\n      \"   ## Open Questions\",\n      \"   <anything the notes could not answer from public sources>\",\n      \"\",\n      \"   ## Sources\",\n      \"   - <source URL or file path> — <date accessed>\",\n      \"   ```\",\n      \"\",\n      \"5. **Create the `company:draft` issue** with `Depends on: #<research-issue>`.\",\n      \"   Its body references the notes file path and the requested company\",\n      \"   type.\",\n      \"\",\n      \"6. **Commit and push** the notes file. Close the research issue\",\n      `   ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 2: Draft Profile (`company:draft`)\",\n      \"\",\n      \"**Goal:** Write the structured company profile from the research notes.\",\n      \"\",\n      \"**Budget:** No new web searches unless explicitly needed to fill a\",\n      \"gap the notes flagged. Write one profile file.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the research-notes file** referenced in the issue body.\",\n      \"\",\n      \"2. **Check for duplicates.** If `<PROFILES_DIR>/<COMPANY_SLUG>.md`\",\n      \"   already exists, open it and decide whether to update in place or\",\n      \"   flag a naming collision. Never silently overwrite a non-trivial\",\n      \"   existing profile.\",\n      \"\",\n      \"3. **Write the profile** to `<PROFILES_DIR>/<COMPANY_SLUG>.md` using\",\n      \"   the template below. All sections are required; use\",\n      \"   `_Not available in public sources._` when a section cannot be\",\n      \"   filled from the notes.\",\n      \"\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"<company name>\"',\n      \"   slug: <COMPANY_SLUG>\",\n      \"   company_type: <one of the taxonomy values>\",\n      \"   website: <primary URL>\",\n      \"   date: YYYY-MM-DD\",\n      \"   refresh_days: <N, default 180>\",\n      \"   parent_issue: <N>\",\n      \"   notes: <NOTES_DIR>/<COMPANY_SLUG>.notes.md\",\n      \"   referencedIn: []\",\n      \"   ---\",\n      \"\",\n      \"   ## Summary\",\n      \"   <2–4 sentence elevator description: what they do, who they sell to>\",\n      \"\",\n      \"   ## Classification\",\n      \"   - **Primary type:** <taxonomy value>\",\n      \"   - **Secondary type (if any):** <taxonomy value or `n/a`>\",\n      \"   - **Relevance to this project:** <1–2 sentences tying the company\",\n      \"     back to the framing from the notes>\",\n      \"\",\n      \"   ## Offering\",\n      \"   - **Products / services:** <bullet list with one-line descriptions>\",\n      \"   - **Target customers:** <who they sell to>\",\n      \"   - **Pricing model:** <if disclosed>\",\n      \"\",\n      \"   ## Company\",\n      \"   - **Founded:** <year if known>\",\n      \"   - **Headquarters:** <city, country if known>\",\n      \"   - **Size signals:** <headcount, funding stage, public/private — if known>\",\n      \"   - **Notable people:** <founders, relevant leaders>\",\n      \"\",\n      \"   ## Technology Signals\",\n      \"   <stack hints from job listings, product docs, public engineering\",\n      \"   content — each bullet cited>\",\n      \"\",\n      \"   ## Market Position\",\n      \"   <which segment(s) they play in, where they sit on the\",\n      \"   competitive map, who they compete with — cited>\",\n      \"\",\n      \"   ## Positioning / Differentiation\",\n      \"   <how they describe themselves and how they differ from adjacent\",\n      \"   companies — use their own language, cited, rather than inferred>\",\n      \"\",\n      \"   ## Risks / Open Questions\",\n      \"   <what the profile could not answer; flag anything the follow-up\",\n      \"   phase should escalate>\",\n      \"\",\n      \"   ## Follow-up Candidates\",\n      \"   - **People to profile:** <list of candidate name, role pairs>\",\n      \"   - **Products / software to evaluate:** <list of candidate product\",\n      \"     names>\",\n      \"\",\n      \"   ## Revision History\",\n      \"   | Date | Changes |\",\n      \"   |------|---------|\",\n      \"   | YYYY-MM-DD | Initial profile |\",\n      \"\",\n      \"   ## Sources\",\n      \"   - <source URL> — <date accessed>\",\n      \"   ```\",\n      \"\",\n      \"4. **Apply the `temporal-framing-convention` rule.** Every\",\n      \"   time-sensitive factual claim in the profile — ownership,\",\n      \"   leadership tenure, regulatory status, litigation, dated metrics\",\n      \"   — must carry an inline `as of [YYYY-MM-DD]` or `as of [Month\",\n      \"   YYYY]` qualifier on its **first** occurrence in the document.\",\n      \"   Use the granularity that matches the source citation (precise\",\n      \"   date for a filing or press release; month for a self-reported\",\n      \"   `About` page). The qualifier is mechanical, not editorial — it\",\n      \"   is the signal Phase 5 (Refresh) uses to grep for stale claims.\",\n      \"\",\n      \"5. **Decide whether a follow-up issue is warranted.** Create a\",\n      \"   `company:followup` issue (depending on this draft issue) only if\",\n      \"   the profile lists at least one follow-up candidate. Otherwise,\",\n      \"   note in the draft issue's closing comment that no follow-up is\",\n      \"   needed.\",\n      \"\",\n      \"6. **File a `company:match` issue** (depending on this draft issue)\",\n      \"   so the profile gets enriched against the project's business-model\",\n      \"   canvases. Skip the match issue only when the invoking project has\",\n      \"   no business-model canvases at all (Phase 4 will detect and exit\",\n      \"   gracefully in that case).\",\n      \"\",\n      \"7. **Commit and push** the profile file. Close the draft issue\",\n      `   ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 3: Followup (`company:followup`)\",\n      \"\",\n      \"**Goal:** Create downstream research issues for the people and\",\n      \"software products surfaced in the profile. Hand the candidates off to\",\n      \"the `people-profile` and `software-profile` bundles so they can be\",\n      \"researched independently.\",\n      \"\",\n      \"**Budget:** No new research. Read the profile, enqueue issues, close\",\n      \"the phase. Markdown cross-references in the profile's\",\n      \"`## Follow-up Candidates` section are preserved — issue creation is\",\n      \"**additive** on top of the existing notes-only behavior.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the profile file** referenced in the issue body.\",\n      \"\",\n      \"2. **Enqueue a `people:research` issue per candidate** under\",\n      \"   `Follow-up Candidates > People to profile` that is worth\",\n      \"   downstream research. Each issue must carry:\",\n      \"\",\n      \"   - `type:people-profile`\",\n      \"   - `people:research`\",\n      `   - \\`priority:${labelsForPhase(issueDefaults, \"people:research\").priority}\\``,\n      `   - \\`status:${labelsForPhase(issueDefaults, \"people:research\").status}\\``,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"   The issue body must include:\",\n      \"   - A **discovery source** line naming this company profile\",\n      \"     (`Discovered while profiling: <company name>`)\",\n      \"   - A link to the company profile path (`Company profile: <PROFILES_DIR>/<COMPANY_SLUG>.md`)\",\n      \"   - Enough identifying metadata — full name, role/title, and\",\n      \"     employing company — that the `people-profile-analyst` agent can\",\n      \"     begin research without revisiting this company profile\",\n      \"\",\n      \"3. **Enqueue a `software:research` issue per candidate** under\",\n      \"   `Follow-up Candidates > Products / software to evaluate` that is\",\n      \"   worth downstream research. Each issue must carry:\",\n      \"\",\n      \"   - `type:software-profile`\",\n      \"   - `software:research`\",\n      `   - \\`priority:${labelsForPhase(issueDefaults, \"software:research\").priority}\\``,\n      `   - \\`status:${labelsForPhase(issueDefaults, \"software:research\").status}\\``,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"   The issue body must include:\",\n      \"   - A **discovery source** line naming this company profile\",\n      \"     (`Discovered while profiling: <company name>`)\",\n      \"   - A link to the company profile path (`Company profile: <PROFILES_DIR>/<COMPANY_SLUG>.md`)\",\n      \"   - Enough identifying metadata — product name and vendor (usually\",\n      \"     this company if it builds the product, otherwise the upstream\",\n      \"     vendor) — that the `software-profile-analyst` agent can begin\",\n      \"     research without revisiting this company profile\",\n      \"\",\n      \"4. **Avoid duplicates.** Before opening a `people:research` or\",\n      \"   `software:research` issue, verify no existing profile covers the\",\n      \"   candidate:\",\n      \"\",\n      \"   - People: check `<PEOPLE_PROFILES_DIR>/` for a matching profile\",\n      \"     file (by derived slug or by searching the directory for the\",\n      \"     person's name). If a profile exists, reuse it as a cross-reference\",\n      \"     only — **do not** open a new `people:research` issue.\",\n      \"   - Software: check `<SOFTWARE_PROFILES_DIR>/` the same way. If a\",\n      \"     profile exists, reuse it as a cross-reference only — **do not**\",\n      \"     open a new `software:research` issue.\",\n      \"   - Also scan open issues carrying the matching `people:research` or\",\n      \"     `software:research` label so this phase never re-opens research\",\n      \"     that is already queued.\",\n      \"\",\n      \"5. **Exercise restraint.** Only create downstream issues for people\",\n      \"   and software products that are **genuinely relevant** to the\",\n      \"   framing of this profile — executives, founders, and decision-makers\",\n      \"   for people; products the company builds or materially depends on\",\n      \"   for software. Do **not** open issues for every name mentioned in\",\n      \"   passing, every SaaS tool listed in a job ad, or every tangential\",\n      \"   partner. When in doubt, leave the candidate as a markdown\",\n      \"   cross-reference in the profile and skip the downstream issue.\",\n      \"\",\n      \"6. **Assume the peers are present.** This pipeline assumes the\",\n      \"   `people-profile` and `software-profile` bundles are enabled in the\",\n      \"   consuming project. If a consuming project has disabled one of\",\n      \"   them, flag the followup issue with `status:needs-attention` and\",\n      \"   list the candidates that could not be routed — never invent an\",\n      \"   alternative label taxonomy.\",\n      \"\",\n      \"7. **Cross-link** — update the profile's `## Follow-up Candidates`\",\n      \"   section so each entry references its newly-created issue number\",\n      \"   (or the existing profile path, for candidates that were skipped\",\n      \"   because a profile already exists).\",\n      \"\",\n      \"8. **Commit and push** (if the profile was updated). Close the\",\n      `   followup issue ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 4: Match (`company:match`)\",\n      \"\",\n      \"**Goal:** Enrich an existing profile with business-model and segment\",\n      \"context from the adjacent business-model canvases and industry-\",\n      \"segment descriptions already tracked in the project. Create\",\n      \"bidirectional cross-links so both the profile and the matched\",\n      \"business-model document reference each other.\",\n      \"\",\n      \"This phase is **enrichment of a known profile**, not entity\",\n      \"deduplication — the profile already exists. It is triggered in two\",\n      \"ways:\",\n      \"\",\n      \"1. **Downstream of draft.** Phase 2 files a `company:match` issue\",\n      \"   for every new profile once the draft is committed.\",\n      \"2. **Downstream of a new business-model canvas.** When the\",\n      \"   `business-models` bundle lands a new canvas (or the orchestrator\",\n      \"   scans for profiles that should be re-matched), `company:match`\",\n      \"   issues are filed for each existing profile that might fit the new\",\n      \"   canvas.\",\n      \"\",\n      \"**Budget:** No web searches. Read existing docs, edit the profile,\",\n      \"cross-link the matched business-model file. Anything that cannot be\",\n      \"decided from the project's own documents is flagged in the profile's\",\n      \"`## Risks / Open Questions` section, not resolved with a web search.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the target profile** at the path referenced in the issue\",\n      \"   body. The issue body must carry the profile path; if it does not,\",\n      \"   close the issue with `status:needs-attention` and stop.\",\n      \"\",\n      \"2. **Identify the profile's industry / segment context.** Read the\",\n      \"   profile's `## Summary`, `## Market Position`, and `referencedIn`\",\n      \"   frontmatter to determine which industry(ies) and segment(s) the\",\n      \"   company plays in.\",\n      \"\",\n      \"3. **Scan `<BUSINESS_MODELS_ROOT>` for candidate canvases.** Walk\",\n      \"   the directory tree looking for business-model documents in\",\n      \"   relevant segments. A typical layout is\",\n      \"   `<BUSINESS_MODELS_ROOT>/<industry>/segments/<segment>/business-model.md`,\",\n      \"   but consuming projects may use a different layout — accept any\",\n      \"   markdown file named `business-model*.md` (or matching the pattern\",\n      `   the consuming project declares in \\`${paths.docsRoot}/project-context.md\\`).`,\n      \"   If the directory does not exist or contains no canvases, exit\",\n      \"   gracefully: add a short note to the profile's `## Risks / Open\",\n      `   Questions\\` section and close the issue ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"4. **For each candidate canvas, score the match.** For each canvas:\",\n      \"   - Read the Customer Segments, Key Activities, Value Propositions,\",\n      \"     and Revenue Streams sections (if present).\",\n      \"   - Decide whether the profiled company fits one of the customer\",\n      \"     segments (customer match), offers a competing value proposition\",\n      \"     (competitor match), supplies a key activity as a vendor (vendor\",\n      \"     match), or is named explicitly as a partner (partner match).\",\n      \"   - If the canvas documents size variations (SMB / mid-market /\",\n      \"     enterprise), pick the variation that matches the profiled\",\n      \"     company's size signals (headcount, funding, revenue).\",\n      \"   - Record matches only when the evidence is unambiguous — skip\",\n      \"     weak or inferred matches.\",\n      \"\",\n      \"5. **Enrich the profile.** Add or update a `## Business Model\",\n      \"   Context` section using the template below. Place it after\",\n      \"   `## Market Position` and before `## Positioning / Differentiation`\",\n      \"   so the synthesis flows naturally:\",\n      \"\",\n      \"   ```markdown\",\n      \"   ## Business Model Context\",\n      \"\",\n      \"   ### Matched Business Models\",\n      \"\",\n      \"   | Business Model | Segment | Match Type | Size Variation |\",\n      \"   |----------------|---------|------------|----------------|\",\n      \"   | [<canvas title>](<relative path to business-model.md>) | <segment> | <customer / competitor / vendor / partner> | <SMB / Mid-Market / Enterprise or `n/a`> |\",\n      \"\",\n      \"   ### Segment Classification\",\n      \"\",\n      \"   - **Primary segment:** [<segment name>](<relative path to segment index>) — <one sentence on fit>\",\n      \"   - **Secondary segment(s):** <list or `n/a`>\",\n      \"\",\n      \"   ### Size Classification\",\n      \"\",\n      \"   Based on <headcount>, <revenue/funding>, and <any other size\",\n      \"   signal>, this company matches the **<SMB / Mid-Market /\",\n      \"   Enterprise>** variation in the <segment> business model.\",\n      \"   ```\",\n      \"\",\n      \"   Use `_No matched business models in <BUSINESS_MODELS_ROOT>._` as\",\n      \"   the table body when Step 3 found candidates but Step 4 scored\",\n      \"   zero matches.\",\n      \"\",\n      \"6. **Update the matched business-model documents bidirectionally.**\",\n      \"   For every row in the matched-models table, append a cross-link\",\n      \"   to the canvas's own Traceability (or Sources) section — do not\",\n      \"   rewrite the canvas body. A single line is enough:\",\n      \"\",\n      \"   ```markdown\",\n      \"   - **Profiled company:** [<company name>](<relative path to profile.md>) — match type: <customer / competitor / vendor / partner>\",\n      \"   ```\",\n      \"\",\n      \"   If a canvas already lists this profile, do not duplicate the line.\",\n      \"   If the canvas has no Traceability or Sources section, skip the\",\n      \"   canvas and flag it in the profile's `## Risks / Open Questions`\",\n      \"   section rather than inventing a new section in someone else's\",\n      \"   document.\",\n      \"\",\n      \"7. **Update the profile's `referencedIn` frontmatter.** Add the\",\n      \"   relative paths of every matched business-model document and\",\n      \"   segment index so downstream audit tooling can traverse the link\",\n      \"   graph without re-scanning the tree.\",\n      \"\",\n      \"8. **Append a revision-history row.**\",\n      \"\",\n      \"   ```markdown\",\n      \"   | YYYY-MM-DD | Matched to business models: <comma-separated segment list> |\",\n      \"   ```\",\n      \"\",\n      \"9. **Commit and push.** Report the matched segments on the match\",\n      \"   issue with a short comment, and close it\",\n      `   ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 5: Refresh (`company:refresh`)\",\n      \"\",\n      \"**Goal:** Re-verify an existing profile with a small number of\",\n      \"targeted web searches for recent developments, then update the\",\n      \"profile in place.\",\n      \"\",\n      \"**Budget:** 4–6 targeted web searches, focused on recent activity.\",\n      \"Do not redo the full research-phase sweep.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the existing profile** at the path referenced in the issue\",\n      \"   body. If the profile file is missing, close the issue with\",\n      \"   `status:needs-attention` and stop.\",\n      \"\",\n      \"2. **Confirm the staleness threshold.** Compare the profile's `date`\",\n      \"   frontmatter against today's date and the `refresh_days`\",\n      \"   frontmatter (or the project default from the Refresh Cadence\",\n      \"   section above). If the profile is younger than the threshold and\",\n      \"   the issue body does not set `force: true`, close the issue with\",\n      \"   a short comment and stop — do not burn the search budget.\",\n      \"\",\n      \"3. **Grep for `as of ` qualifiers.** Per the\",\n      \"   `temporal-framing-convention` rule, every time-sensitive claim in\",\n      \"   the profile carries an inline `as of [YYYY-MM-DD]` or `as of\",\n      \"   [Month YYYY]` qualifier. Build the list of qualified claims and\",\n      \"   compute the age (in days) of each one against today's date.\",\n      \"   Classify each claim against the cadence table in the\",\n      \"   `temporal-framing-convention` rule:\",\n      \"   - **company-leadership** — 90 days\",\n      \"   - **regulatory-status** — 30 days\",\n      \"   - **litigation** — 30 days\",\n      \"   - **ownership** — 180 days\",\n      \"   - **dated-metrics** — 180 days\",\n      \"\",\n      \"   Treat every qualifier older than its category's cadence as a\",\n      \"   re-verification target for the targeted-search step below. If the\",\n      \"   profile contains **no** `as of ` qualifiers at all, treat the\",\n      \"   entire profile as needing **back-fill** — apply the convention to\",\n      \"   every time-sensitive claim before running the targeted searches.\",\n      \"\",\n      \"4. **Run 4–6 targeted searches.** Focus on the categories surfaced by\",\n      \"   the qualifier grep (step 3), plus any additional signals worth a\",\n      \"   refresh:\",\n      \"   - `<company name>` + recent news, press releases, or blog posts\",\n      \"   - Product launches, feature changes, or pricing updates\",\n      \"   - Funding rounds, acquisitions, or material ownership changes\",\n      \"   - Leadership changes (CEO, CTO, CPO, notable departures/arrivals)\",\n      \"   - New partnerships, certifications, or regulatory milestones\",\n      \"\",\n      \"5. **Update the profile in place.** Edit the affected sections with\",\n      \"   the new information. Cite every new claim. Preserve the slug and\",\n      \"   the original `parent_issue` field. Bump the `date` frontmatter to\",\n      \"   today's date. **Update the `as of` qualifier** on every claim you\",\n      \"   re-verified — change the date to today's date when the claim\",\n      \"   still holds; rewrite the framing when the claim has changed.\",\n      \"   Surface unverifiable or stale-and-changed claims through\",\n      \"   `## Risks / Open Questions` rather than silently dropping them.\",\n      \"\",\n      \"6. **Do not silently re-type the company.** If the refresh surfaces\",\n      \"   evidence that the company's primary type has changed (e.g., an\",\n      \"   industry-player that now sells a directly competing product),\",\n      \"   flag it in `## Risks / Open Questions` and stop — do **not**\",\n      \"   rewrite the `company_type` frontmatter without an explicit\",\n      \"   override in the refresh issue body (`retype: <new type>`).\",\n      \"\",\n      \"7. **Append a revision-history row.** Summarize the delta in one\",\n      \"   line:\",\n      \"\",\n      \"   ```markdown\",\n      \"   | YYYY-MM-DD | Refreshed: <one-line summary of what changed> |\",\n      \"   ```\",\n      \"\",\n      \"   When the search budget finds no material change, the row still\",\n      \"   appears so the next scheduled refresh knows this profile was\",\n      \"   reviewed:\",\n      \"\",\n      \"   ```markdown\",\n      \"   | YYYY-MM-DD | Refreshed: no material change |\",\n      \"   ```\",\n      \"\",\n      \"8. **Update reference entries** (if the project tracks company\",\n      \"   references under research directories). If the company's\",\n      \"   relevance to a research area has shifted — for example, it is no\",\n      \"   longer a live competitor, or it now plays in a new segment —\",\n      \"   update the corresponding entry under `referencedIn` and the\",\n      \"   research-area doc that links to this profile.\",\n      \"\",\n      \"9. **Commit and push.** Report the delta on the refresh issue with\",\n      \"   a short comment (or `no material change`), and close it\",\n      `   ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 6: Analyze (`company:analyze`)\",\n      \"\",\n      \"**Goal:** Produce a segment-level competitive analysis by\",\n      \"synthesizing every profile in the target segment. The deliverable\",\n      \"is one markdown document under `<ANALYSIS_DIR>` combining a\",\n      \"feature-comparison matrix, a positioning map, and the strategic\",\n      \"implications for the consuming project.\",\n      \"\",\n      \"**Budget:** No web searches. Pure synthesis from existing profiles\",\n      \"and (optionally) existing product docs the consuming project\",\n      \"maintains.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the segment scope from the issue body.** It must carry\",\n      \"   `<SEGMENT_SLUG>` plus the path of every profile to include (or a\",\n      \"   glob that resolves to them). If the issue body is ambiguous,\",\n      \"   close with `status:needs-attention` and stop.\",\n      \"\",\n      \"2. **Block on open draft issues.** Query for open\",\n      \"   `company:draft` issues whose title or body mentions the segment\",\n      \"   slug:\",\n      \"\",\n      \"   ```bash\",\n      \"   gh issue list \\\\\",\n      \"     --label 'company:draft' --state open \\\\\",\n      \"     --search '<SEGMENT_SLUG> in:title,body' \\\\\",\n      \"     --json number,title --limit 200\",\n      \"   ```\",\n      \"\",\n      \"   If the query returns any issues, this analyze issue must block on\",\n      \"   them. Add `Depends on: #<N>` lines for every open draft, apply\",\n      \"   `status:blocked`, remove `status:in-progress`, and stop — **do\",\n      \"   not publish a partial landscape**. The issue will be eligible\",\n      \"   again once the drafts close.\",\n      \"\",\n      \"3. **Read every in-scope profile.** Collect each profile's Summary,\",\n      \"   Offering, Classification, Market Position, Positioning /\",\n      \"   Differentiation, and Risks / Open Questions sections.\",\n      \"\",\n      \"4. **Derive a feature axis.** Build the feature axis from the\",\n      \"   union of bullets across each profile's Offering section (and, if\",\n      \"   present, a project-maintained feature taxonomy under\",\n      \"   `<BUSINESS_MODELS_ROOT>`). Do **not** invent features not\",\n      \"   represented in at least one profile or the project's taxonomy.\",\n      \"\",\n      \"5. **Write the analysis document** to\",\n      \"   `<ANALYSIS_DIR>/<SEGMENT_SLUG>.md` using the template below. Use\",\n      \"   `_Not available in profiles._` in any cell a profile does not\",\n      \"   document. Never fabricate a `Yes/No` from a missing field.\",\n      \"\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"<segment name> Competitive Analysis\"',\n      \"   slug: <SEGMENT_SLUG>\",\n      \"   segment: <segment name>\",\n      \"   date: YYYY-MM-DD\",\n      \"   status: draft\",\n      \"   profiles:\",\n      \"     - <relative path to profile 1>\",\n      \"     - <relative path to profile 2>\",\n      \"   ---\",\n      \"\",\n      \"   ## Market Overview\",\n      \"   <landscape summary — total players, market structure, trends\",\n      \"    visible from the profiles>\",\n      \"\",\n      \"   ## Feature Comparison Matrix\",\n      \"   | Feature | <Company A> | <Company B> | <Company C> |\",\n      \"   |---------|-------------|-------------|-------------|\",\n      \"   | <feature> | Yes / No / Partial | ... | ... |\",\n      \"\",\n      \"   ## Pricing Comparison\",\n      \"   <pricing tiers across profiles, where disclosed>\",\n      \"\",\n      \"   ## Positioning Map\",\n      \"   <where each player sits — by price vs. feature depth, or by\",\n      \"    segment focus. Textual description; link to an external diagram\",\n      \"    if the consuming project maintains one.>\",\n      \"\",\n      \"   ## Strengths & Vulnerabilities\",\n      \"   | Company | Key Strength | Key Vulnerability |\",\n      \"   |---------|--------------|-------------------|\",\n      \"   | <company> | <strength> | <vulnerability> |\",\n      \"\",\n      \"   ## Strategic Implications\",\n      \"   <which features matter most, where the consuming project can\",\n      \"    differentiate, what pricing the landscape supports, and which\",\n      \"    competitive threats to watch>\",\n      \"\",\n      \"   ## Recommended Actions\",\n      \"   | Action | Priority | Rationale |\",\n      \"   |--------|----------|-----------|\",\n      \"   | <action> | High / Medium / Low | <why> |\",\n      \"\",\n      \"   ## Sources\",\n      \"   - <relative path to profile 1>\",\n      \"   - <relative path to profile 2>\",\n      \"\",\n      \"   ## Revision History\",\n      \"   | Date | Changes |\",\n      \"   |------|---------|\",\n      \"   | YYYY-MM-DD | Initial analysis |\",\n      \"   ```\",\n      \"\",\n      \"6. **Do not edit the underlying profiles.** `company:analyze` is a\",\n      \"   synthesis phase — profiles are **inputs only**. Any cross-link\",\n      \"   from a profile to the analysis document should be added by a\",\n      \"   follow-up `company:match` pass, not by this phase.\",\n      \"\",\n      \"7. **Commit and push.** Name the analysis document path on the\",\n      \"   analyze issue with a short comment, and close it\",\n      `   ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Output Boundaries\",\n      \"\",\n      \"This agent writes **only** to:\",\n      \"\",\n      \"- `<NOTES_DIR>/` — research-notes files (Phase 1)\",\n      \"- `<PROFILES_DIR>/` — company profiles (Phase 2, updated in Phases\",\n      \"  3, 4, and 5)\",\n      \"- `<ANALYSIS_DIR>/` — segment-level competitive-analysis documents\",\n      \"  (Phase 6)\",\n      \"\",\n      \"In Phase 3, this agent also **creates `people:research` and\",\n      \"`software:research` issues** for people and software products\",\n      \"surfaced in the profile. It never writes the downstream profiles\",\n      \"themselves — those are the responsibility of the\",\n      \"`people-profile-analyst` and `software-profile-analyst` agents, which\",\n      \"pick up the issues this pipeline creates.\",\n      \"\",\n      \"In Phase 4, this agent appends a single bidirectional cross-link\",\n      \"line to matched business-model documents under\",\n      \"`<BUSINESS_MODELS_ROOT>`. It never rewrites the canvas body, adds\",\n      \"new canvas sections, or otherwise mutates business-model content —\",\n      \"that remains the responsibility of the `business-models` bundle.\",\n      \"\",\n      \"In Phase 5, this agent only updates an existing profile in place —\",\n      \"it never forks a new profile under a different slug.\",\n      \"\",\n      \"In Phase 6, this agent only writes a new segment-level analysis\",\n      \"document. It never edits the underlying company profiles.\",\n      \"\",\n      \"The pipeline produces **company profiles, notes, and segment\",\n      \"analyses**. Deeper research on people or products is delegated to\",\n      \"downstream research pipelines via `people:research` and\",\n      \"`software:research` issues — this agent never writes person\",\n      \"profiles, software profiles, product evaluations, or\",\n      \"requirement-style documents itself. Keep this boundary clean so\",\n      \"the company-profile pipeline stays generic.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Rules\",\n      \"\",\n      \"- **One company per session.** Never profile two companies back-to-back.\",\n      \"  `company:analyze` is the single exception — it synthesizes one\",\n      \"  segment per session, not one company.\",\n      \"- **Persist before closing.** Every phase must write its output file\",\n      \"  before closing its issue.\",\n      \"- **Cite everything.** Profile claims without source citations do not\",\n      \"  belong in the deliverable.\",\n      \"- **No assumed competition.** Never call a company a competitor unless\",\n      \"  the invoking issue body or the consuming project's configuration\",\n      \"  says so.\",\n      \"- **Delegate, don't duplicate.** People and software products\",\n      \"  surfaced during profiling are handed off to the `people-profile`\",\n      \"  and `software-profile` bundles via `people:research` and\",\n      \"  `software:research` issues in Phase 3 — never inlined as person or\",\n      \"  software profiles in this pipeline.\",\n      \"- **Check before enqueueing.** Before opening a `people:research` or\",\n      \"  `software:research` issue, verify no existing profile or open\",\n      \"  research issue already covers the candidate. Reuse existing\",\n      \"  profiles as cross-references rather than re-queuing research.\",\n      \"- **Restrain the queue.** Only enqueue downstream research for people\",\n      \"  and products that are genuinely relevant to the framing of this\",\n      \"  profile. Do not open issues for every name or product mentioned in\",\n      \"  passing.\",\n      \"- **Produce profiles and analyses, not requirement documents.** Do\",\n      \"  not open `type:requirement` or formal evaluation issues from this\",\n      \"  pipeline. Follow-up research is scoped through `people:research`\",\n      \"  and `software:research` only.\",\n      \"- **Match is read-mostly.** Phase 4 edits the target profile and\",\n      \"  appends one line to each matched business-model document. It never\",\n      \"  rewrites canvas bodies, never runs web searches, and never edits\",\n      \"  other profiles.\",\n      \"- **Refresh respects the cadence.** Phase 5 exits early when the\",\n      \"  profile is younger than the staleness threshold and `force: true`\",\n      \"  is not set. It always appends a revision-history row so the next\",\n      \"  scheduled run knows the profile was reviewed.\",\n      \"- **Analyze blocks on open drafts.** Phase 6 refuses to publish a\",\n      \"  partial landscape. If any `company:draft` issues for the target\",\n      \"  segment are still open, the analyze issue is marked\",\n      \"  `status:blocked` with `Depends on:` lines pointing at each draft.\",\n      \"- **Refresh, don't fork.** When a profile exists and is past its\",\n      \"  cadence, update in place rather than creating a new slug.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/**\n * Regression eval suite shipped alongside the `profile-company` skill\n * at `.claude/skills/profile-company/evals/evals.json`. Each entry\n * exercises a distinct branch of the pipeline:\n *\n * - A fresh profile from a company name that triggers type inference\n *   and `people:research` / `software:research` hand-offs.\n * - A profile that must cite its source tiers correctly (T1/T2/T3/T4)\n *   because one claim conflicts across sources.\n * - A follow-up cycle where the profile already exists and the user\n *   expects refresh semantics, not a fork.\n *\n * Suites follow the skill-evals schema — see the `skill-evals` rule\n * content rendered by `./skill-evals.ts#renderSkillEvalsRuleContent`.\n */\nfunction buildProfileCompanyEvalsJson(\n  issueDefaults: ResolvedIssueDefaults,\n): string {\n  const research = labelsForPhase(issueDefaults, \"company:research\");\n  return JSON.stringify(\n    {\n      skill_name: \"profile-company\",\n      evals: [\n        {\n          id: 1,\n          prompt:\n            \"/profile-company Acme Registration — they're a mid-market B2B event platform we ran into at a trade show last month. framing: competitive analysis for our self-service registration feature.\",\n          expected_output: `A \\`company:research\\` issue is created with \\`type:company-profile\\`, \\`priority:${research.priority}\\`, and \\`status:${research.status}\\`. The issue body carries the company name, an inferred or stated type (likely \\`competitor\\` given the framing), the framing text, and any supplied overrides. Phase 1 produces a research-notes file under the project's notes directory with sources annotated by tier (T1/T2/T3/T4) and date. Phase 2 opens a \\`company:draft\\` issue and may additionally open \\`people:research\\` issues for notable leaders surfaced and \\`software:research\\` issues for adjacent product mentions. The skill does not author person profiles, software profiles, or comparative analyses itself.`,\n          files: [],\n          product_context_refs: [\n            \"Mission\",\n            \"Domain Vocabulary\",\n            \"In-Scope Capabilities\",\n          ],\n        },\n        {\n          id: 2,\n          prompt:\n            \"Profile a startup called Lumen Events. Their current company page lists a 150-person team but a TechCrunch article from six months ago said they were at 80 people. Handle the conflict.\",\n          expected_output:\n            \"The `company:research` issue body captures the conflict up-front under a dedicated conflict-resolution note. The research notes file annotates the live company page as a T1 living source and the TechCrunch article as a T3 secondary source. Conflict resolution follows the documented hierarchy: T1 wins on headcount (a fast-decay claim), so the current-state profile records 150 employees. The profile adds an inline note flagging that the T3 source is six months old and may simply be stale. Sources section lists each citation with tier, access date or publish date, and URL.\",\n          files: [],\n          product_context_refs: [\"Domain Vocabulary\"],\n        },\n        {\n          id: 3,\n          prompt:\n            \"/profile-company Acme Registration — we already have a profile for them but it's nine months old. Refresh it.\",\n          expected_output:\n            \"The pipeline routes through the refresh phase (not a fresh profile). It reads the existing profile slug and refuses to create a second profile under a new slug. When the existing profile is younger than the configured staleness threshold and `force: true` is not set, the refresh phase exits early and appends a revision-history row noting the review. When the profile is past cadence (nine months qualifies for most fast-decay fields), the refresh updates fast-decay claims in place (headcount, leadership, pricing, product features) while preserving stable history, and appends a revision-history row citing what changed and which sources were re-checked. No new profile file is created.\",\n          files: [],\n          product_context_refs: [\"Domain Vocabulary\"],\n        },\n      ],\n    },\n    null,\n    2,\n  );\n}\n\n/**\n * Reference files emitted alongside the `profile-company` SKILL.md.\n * Currently ships the eval suite only — additional reference assets\n * (profile templates, notes stubs) land here as the bundle grows.\n */\nfunction buildProfileCompanyReferenceFiles(\n  issueDefaults: ResolvedIssueDefaults,\n): ReadonlyArray<{ readonly path: string; readonly content: string }> {\n  return [\n    {\n      path: \"evals/evals.json\",\n      content: buildProfileCompanyEvalsJson(issueDefaults),\n    },\n  ];\n}\n\n/** Skill that kicks off a company profile cycle. */\nfunction buildProfileCompanySkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"profile-company\",\n    description:\n      \"Kick off a company-profile pipeline. Creates a company:research issue for the given company and dispatches Phase 1 (Research) in the company-profile-analyst agent.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"company-profile-analyst\",\n    platforms: { cursor: { exclude: true } },\n    referenceFiles: buildProfileCompanyReferenceFiles(issueDefaults),\n    instructions: [\n      \"# Profile Company\",\n      \"\",\n      \"Kick off a company-profile pipeline. Creates a `company:research`\",\n      \"issue carrying the company name, type, and framing, then dispatches\",\n      \"Phase 1 (Research) in the company-profile-analyst agent.\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/profile-company <company-name>\",\n      \"\",\n      \"Optional extensions in the issue body:\",\n      \"- `type: <competitor | industry-player | software-vendor | customer |\",\n      \"   partner | investor>` — override the default type inference\",\n      \"- `website: <url>` — canonical website if not obvious from the name\",\n      \"- `framing: <text>` — why this profile was requested and what to learn\",\n      \"- `slug: <kebab-case>` — override the derived company slug\",\n      \"- `sources: <list>` — additional authorized sources beyond public web\",\n      \"\",\n      \"## Default Paths\",\n      \"\",\n      `If the project has no override in \\`${paths.docsRoot}/project-context.md\\` or`,\n      \"`agentConfig.rules`, outputs land under:\",\n      \"\",\n      `- \\`${paths.companiesRoot}/notes/<slug>.notes.md\\``,\n      `- \\`${paths.companiesRoot}/profiles/<slug>.md\\``,\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `company:research` issue with `type:company-profile`,\",\n      `   \\`priority:${labelsForPhase(issueDefaults, \"company:research\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"company:research\").status}\\`. Body must include the`,\n      \"   company name, selected type, framing, and any overrides.\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 1 (Research) of the company-profile-analyst agent.\",\n      \"3. Phase 1 creates the `company:draft` issue. Phase 2 may create a\",\n      \"   `company:followup` issue **and** a `company:match` issue. Each\",\n      \"   downstream issue declares its `Depends on:` predecessor.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- A research-notes file under the project's notes directory\",\n      \"- A single company profile under the profiles directory\",\n      \"- `people:research` issues for notable people surfaced in the profile\",\n      \"  (handed off to the `people-profile` bundle)\",\n      \"- `software:research` issues for software products surfaced in the\",\n      \"  profile (handed off to the `software-profile` bundle)\",\n      \"- A `company:match` issue so the profile is enriched against the\",\n      \"  project's business-model canvases\",\n      \"- This pipeline produces **company profiles only** — it does not\",\n      \"  write person profiles, software profiles, product evaluations, or\",\n      \"  comparative analyses itself. Segment-level analysis is produced by\",\n      \"  the separate `/analyze-segment` skill.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off a company match (enrichment) cycle. */\nfunction buildMatchCompanySkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"match-company\",\n    description:\n      \"Kick off a company-profile match (enrichment) cycle. Creates a company:match issue for an existing profile and dispatches Phase 4 (Match) in the company-profile-analyst agent. Match enriches the profile with business-model, segment, and size context from existing docs — no web searches.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"company-profile-analyst\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Match Company\",\n      \"\",\n      \"Enrich an existing company profile against the project's\",\n      \"business-model canvases, industry segments, and size descriptions.\",\n      \"Creates a `company:match` issue for the target profile and\",\n      \"dispatches Phase 4 (Match) in the company-profile-analyst agent.\",\n      \"\",\n      \"**This is enrichment of a known profile, not entity\",\n      \"deduplication** — the profile already exists and must be passed by\",\n      \"path.\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/match-company <path-to-profile>\",\n      \"\",\n      \"Optional extensions in the issue body:\",\n      \"- `business_models_root: <path>` — override `<BUSINESS_MODELS_ROOT>`\",\n      \"  if the project's business-model canvases do not live at the\",\n      \"  default location\",\n      \"- `only: <comma-separated list of segment slugs>` — match only\",\n      \"  against the listed segments (useful when a new canvas triggers a\",\n      \"  re-match)\",\n      \"\",\n      \"## Default Paths\",\n      \"\",\n      `If the project has no override in \\`${paths.docsRoot}/project-context.md\\` or`,\n      \"`agentConfig.rules`, the agent reads canvases from:\",\n      \"\",\n      `- \\`${paths.docsRoot}/industry-research/\\``,\n      \"\",\n      \"## Budget\",\n      \"\",\n      \"- **No web searches.** Phase 4 reads existing docs and edits the\",\n      \"  profile + one cross-link per matched canvas. Anything that cannot\",\n      \"  be decided from existing docs is flagged in the profile's\",\n      \"  `## Risks / Open Questions` section.\",\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `company:match` issue with `type:company-profile`,\",\n      `   \\`priority:${labelsForPhase(issueDefaults, \"company:match\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"company:match\").status}\\`. Body must include the`,\n      \"   profile path and any overrides.\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 4 (Match) of the company-profile-analyst agent.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- The profile gains a `## Business Model Context` section\",\n      \"- Each matched business-model canvas gains a single cross-link line\",\n      \"  in its Traceability / Sources section\",\n      \"- The profile's `referencedIn` frontmatter is updated with matched\",\n      \"  paths\",\n      \"- A revision-history row summarizing the matched segments\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off a company refresh (maintenance) cycle. */\nfunction buildRefreshCompanySkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"refresh-company\",\n    description:\n      \"Kick off a company-profile refresh cycle. Creates a company:refresh issue for an existing profile and dispatches Phase 5 (Refresh) in the company-profile-analyst agent. Refresh re-verifies the profile with 4–6 targeted web searches and updates it in place. Respects a configurable staleness threshold so profiles younger than the threshold exit early.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"company-profile-analyst\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Refresh Company\",\n      \"\",\n      \"Re-verify an existing company profile with a small number of\",\n      \"targeted web searches and update the profile in place. Creates a\",\n      \"`company:refresh` issue for the target profile and dispatches\",\n      \"Phase 5 (Refresh) in the company-profile-analyst agent.\",\n      \"\",\n      \"Refresh respects a configurable **staleness threshold** so scheduled\",\n      \"refreshes do not burn search budget on profiles that are still\",\n      \"fresh.\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/refresh-company <path-to-profile>\",\n      \"\",\n      \"Optional extensions in the issue body:\",\n      \"- `refresh_days: <N>` — override the default 180-day staleness\",\n      \"  threshold for this run\",\n      \"- `force: true` — refresh even if the profile is younger than the\",\n      \"  threshold\",\n      \"- `retype: <taxonomy value>` — explicitly allow Phase 5 to change\",\n      \"  the profile's `company_type` when the refresh finds material\",\n      \"  evidence of a type change\",\n      \"\",\n      \"## Staleness Threshold\",\n      \"\",\n      \"Order of precedence (first match wins):\",\n      \"\",\n      \"1. `refresh_days` in the issue body (per-run override)\",\n      \"2. `refresh_days` frontmatter on the profile itself\",\n      \"3. Project-wide default declared under a `## Refresh Cadence`\",\n      `   section in \\`${paths.docsRoot}/project-context.md\\``,\n      \"4. Built-in default: **180 days**\",\n      \"\",\n      \"If the profile's `date` frontmatter plus the resolved threshold is\",\n      \"in the future (i.e. the profile is still fresh) and `force: true`\",\n      \"is not set, Phase 5 closes the refresh issue with a short comment\",\n      \"and stops without running any searches.\",\n      \"\",\n      \"## Budget\",\n      \"\",\n      \"- **4–6 targeted web searches** focused on recent news, product\",\n      \"  launches, funding/acquisitions, leadership changes, and\",\n      \"  partnerships / certifications.\",\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `company:refresh` issue with `type:company-profile`,\",\n      `   \\`priority:${labelsForPhase(issueDefaults, \"company:refresh\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"company:refresh\").status}\\`. Body must include the`,\n      \"   profile path and any overrides.\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 5 (Refresh) of the company-profile-analyst agent.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- The profile is updated in place (sections edited, `date` bumped,\",\n      \"  slug preserved)\",\n      \"- A revision-history row summarizing the delta — or\",\n      \"  `Refreshed: no material change` when the search budget found\",\n      \"  nothing material\",\n      \"- Reference entries updated if the company's relevance to a research\",\n      \"  area shifted\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off a segment-level competitive analysis cycle. */\nfunction buildAnalyzeSegmentSkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"analyze-segment\",\n    description:\n      \"Kick off a segment-level competitive-analysis cycle. Creates a company:analyze issue for the target segment and dispatches Phase 6 (Analyze) in the company-profile-analyst agent. Analyze synthesizes every profile in the segment into one competitive-analysis document. Blocks on open company:draft issues for the segment.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"company-profile-analyst\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Analyze Segment\",\n      \"\",\n      \"Produce a segment-level competitive analysis by synthesizing every\",\n      \"company profile in the target segment into one markdown document.\",\n      \"Creates a `company:analyze` issue and dispatches Phase 6 (Analyze)\",\n      \"in the company-profile-analyst agent.\",\n      \"\",\n      \"**This is pure synthesis** — no web searches, no new profile work.\",\n      \"All inputs must already exist under the profiles directory before\",\n      \"you run this skill.\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/analyze-segment <segment-slug>\",\n      \"\",\n      \"Optional extensions in the issue body:\",\n      \"- `profiles: <list of paths>` — explicit list of profile files to\",\n      \"  include; otherwise the agent discovers profiles by scanning for\",\n      \"  the segment slug in each profile's `referencedIn` frontmatter\",\n      \"- `analysis_dir: <path>` — override `<ANALYSIS_DIR>` if the project\",\n      \"  stores analyses somewhere other than the default\",\n      \"\",\n      \"## Default Paths\",\n      \"\",\n      `If the project has no override in \\`${paths.docsRoot}/project-context.md\\` or`,\n      \"`agentConfig.rules`, outputs land under:\",\n      \"\",\n      `- \\`${paths.companiesRoot}/analysis/<segment-slug>.md\\``,\n      \"\",\n      \"## Blocking Rule\",\n      \"\",\n      \"Phase 6 refuses to publish a partial landscape. If any\",\n      \"`company:draft` issues whose title or body mention\",\n      \"`<SEGMENT_SLUG>` are still open, the analyze issue is marked\",\n      \"`status:blocked` with `Depends on: #<N>` lines pointing at each\",\n      \"open draft, `status:in-progress` is removed, and Phase 6 exits\",\n      \"without writing the analysis. The issue becomes eligible again\",\n      \"once the drafts close.\",\n      \"\",\n      \"## Budget\",\n      \"\",\n      \"- **No web searches.** Pure synthesis from existing profiles (and\",\n      \"  optionally the project's own product docs).\",\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `company:analyze` issue with `type:company-profile`,\",\n      `   \\`priority:${labelsForPhase(issueDefaults, \"company:analyze\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"company:analyze\").status}\\`. Body must include the`,\n      \"   segment slug and any overrides.\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 6 (Analyze) of the company-profile-analyst agent.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- One markdown document at `<ANALYSIS_DIR>/<SEGMENT_SLUG>.md`\",\n      \"  combining feature-comparison matrix, pricing comparison,\",\n      \"  positioning map, strengths & vulnerabilities, strategic\",\n      \"  implications, and recommended actions — every claim sourced back\",\n      \"  to the underlying profiles\",\n      \"- This skill does **not** edit the underlying profiles. Cross-\",\n      \"  linking a profile back to the analysis is the job of a\",\n      \"  subsequent `company:match` pass.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/**\n * Build the company-profile bundle with the supplied resolved paths.\n *\n * Every reference to a canonical agent path (docs root, etc.) inside\n * the rule / skill / sub-agent content strings is an interpolation of\n * the supplied `paths` struct, so a consumer override of\n * `AgentConfigOptions.paths` propagates to the rendered output.\n *\n * Ships a sub-agent (`company-profile-analyst`), four user-invocable\n * skills (`/profile-company`, `/match-company`, `/refresh-company`,\n * `/analyze-segment`), and `type:company-profile` plus `company:*`\n * phase labels for the six phases.\n */\nexport function buildCompanyProfileBundle(\n  paths: ResolvedAgentPaths = DEFAULT_AGENT_PATHS,\n  issueDefaults: ResolvedIssueDefaults = DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n  tier: AgentModel = AGENT_MODEL.BALANCED,\n): AgentRuleBundle {\n  return {\n    name: \"company-profile\",\n    description:\n      \"Company research and profiling pipeline: research, draft profile, followup, match, refresh, analyze. Enabled by default; domain-neutral; filesystem-durable between phases. Phase 3 (Followup) hands surfaced people and software products off to the `people-profile` and `software-profile` bundles via `people:research` and `software:research` issues. Phase 4 (Match) enriches profiles against business-model canvases. Phase 5 (Refresh) re-verifies profiles on a configurable staleness cadence. Phase 6 (Analyze) synthesizes profiles in a segment into a competitive-analysis document.\",\n    appliesWhen: () => true,\n    rules: [\n      {\n        name: \"company-profile-workflow\",\n        description:\n          \"Describes the 6-phase company-profile pipeline, the company:* label taxonomy, and the boundary against downstream research agents.\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Company Profile Workflow\",\n          \"\",\n          \"Use `/profile-company <company-name>` to kick off a company\",\n          \"research and profiling pipeline. The pipeline runs in up to 6\",\n          \"phases — research, draft, followup, match, refresh, analyze —\",\n          \"each tracked by its own GitHub issue labeled `company:research`,\",\n          \"`company:draft`, `company:followup`, `company:match`,\",\n          \"`company:refresh`, or `company:analyze`. All issues carry\",\n          \"`type:company-profile`.\",\n          \"\",\n          \"Three additional user-invocable skills drive the maintenance and\",\n          \"synthesis phases independently:\",\n          \"\",\n          \"- `/match-company <path-to-profile>` — enrich an existing\",\n          \"  profile with business-model and segment context from the\",\n          \"  project's business-model canvases (Phase 4, no web searches).\",\n          \"- `/refresh-company <path-to-profile>` — re-verify an existing\",\n          \"  profile with 4–6 targeted web searches and update it in place\",\n          \"  (Phase 5, respects a configurable staleness threshold).\",\n          \"- `/analyze-segment <segment-slug>` — synthesize every profile\",\n          \"  in a segment into one competitive-analysis document (Phase 6,\",\n          \"  no web searches; blocks on open `company:draft` issues for\",\n          \"  the segment).\",\n          \"\",\n          \"The pipeline produces **company profiles, notes, and segment\",\n          \"analyses**. Deeper research on notable people and software\",\n          \"products surfaced while profiling is delegated to the\",\n          \"`people-profile` and `software-profile` bundles via\",\n          \"`people:research` and `software:research` issues opened during\",\n          \"Phase 3 (Followup).\",\n          \"\",\n          \"See the `company-profile-analyst` agent definition for full\",\n          \"workflow details, default paths, the company-type taxonomy, the\",\n          \"staleness-threshold rules, and phase-by-phase instructions.\",\n        ].join(\"\\n\"),\n        platforms: {\n          cursor: { exclude: true },\n        },\n        tags: [\"workflow\"],\n      },\n    ],\n    skills: [\n      buildProfileCompanySkill(paths, issueDefaults),\n      buildMatchCompanySkill(paths, issueDefaults),\n      buildRefreshCompanySkill(paths, issueDefaults),\n      buildAnalyzeSegmentSkill(paths, issueDefaults),\n    ],\n    subAgents: [buildCompanyProfileAnalystSubAgent(paths, issueDefaults, tier)],\n    labels: [\n      {\n        name: \"type:company-profile\",\n        color: \"0E8A16\",\n        description:\n          \"Work that produces or maintains a company profile or its research notes\",\n      },\n      {\n        name: \"company:research\",\n        color: \"C5DEF5\",\n        description:\n          \"Phase 1: gather public sources about a company into a research-notes file\",\n      },\n      {\n        name: \"company:draft\",\n        color: \"BFDADC\",\n        description:\n          \"Phase 2: write the structured company profile from research notes\",\n      },\n      {\n        name: \"company:followup\",\n        color: \"D4C5F9\",\n        description:\n          \"Phase 3: enqueue follow-up research issues for people and products surfaced in the profile\",\n      },\n      {\n        name: \"company:match\",\n        color: \"FBCA04\",\n        description:\n          \"Phase 4: enrich a company profile with business-model, segment, and size context from existing docs\",\n      },\n      {\n        name: \"company:refresh\",\n        color: \"F9D0C4\",\n        description:\n          \"Phase 5: re-verify an existing company profile with targeted web searches and update it in place\",\n      },\n      {\n        name: \"company:analyze\",\n        color: \"5319E7\",\n        description:\n          \"Phase 6: synthesize every company profile in a segment into a competitive-analysis document\",\n      },\n    ],\n  };\n}\n\n/**\n * Default-paths instance of the company-profile bundle, preserved for\n * backward compatibility with consumers that import the const\n * directly. The factory above is the canonical entry point when a\n * consumer supplies `AgentConfigOptions.paths`.\n */\nexport const companyProfileBundle: AgentRuleBundle =\n  buildCompanyProfileBundle();\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { renderClaimVerificationSection } from \"./claim-verification\";\nimport {\n  ISSUE_CLOSE_RULE_REFERENCE,\n  ISSUE_CLOSE_SECTION_TITLE,\n  renderIssueClosePolicySection,\n} from \"./issue-close\";\nimport {\n  DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n  ResolvedIssueDefaults,\n  labelsForPhase,\n} from \"./issue-defaults\";\nimport { renderIssueTypeAssignmentStep } from \"./issue-type\";\nimport { renderOriginStampSection } from \"./origin-label\";\nimport { DEFAULT_AGENT_PATHS, ResolvedAgentPaths } from \"./paths\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n  AGENT_MODEL,\n  AGENT_RULE_SCOPE,\n  AgentModel,\n  AgentSkill,\n  AgentSubAgent,\n} from \"../types\";\n\n/**\n * Verbatim customer-profile page template shipped to the consuming\n * project alongside the `/profile-customer` skill. Emitted as\n * `_references/templates/_template-customer-profile.md` under the\n * skill directory so the profile-phase handler resolves it locally\n * without reaching back into configulator.\n *\n * The template is domain-neutral: it captures the structural shape\n * of a customer archetype (segment, goals, jobs-to-be-done,\n * constraints, buying process, technology landscape, regulatory\n * applicability, sources) without hardcoding any specific industry,\n * vertical, or buyer persona. Concrete values are filled in by the\n * profile phase.\n */\nconst TEMPLATE_CUSTOMER_PROFILE = `---\ntitle: \"<Customer Archetype Name>\"\ndescription: \"Customer archetype profile for <Customer Archetype Name>.\"\narchetype: <ARCHETYPE_SLUG>\nsegment: <SEGMENT_SLUG>\n---\n\n| Field | Value |\n|-------|-------|\n| **Archetype** | <short noun phrase identifying the archetype> |\n| **Segment** | <industry or market segment> |\n| **Company size** | <SMB / mid-market / enterprise / consumer / other> |\n| **Geography** | <primary region / country / jurisdiction> |\n| **Status** | <active / prospect / pilot / lapsed> |\n| **Last reviewed** | YYYY-MM-DD |\n\n## Overview\n\n<2–3 paragraphs introducing this archetype: who they are, what they\ndo, and why they matter to the consuming project. Avoid naming\nspecific companies here — the archetype describes the shape of the\ncustomer, not any one instance.>\n\n## Segment and Size\n\n- **Segment definition:** <what makes this segment distinct>\n- **Size band:** <employees / revenue / seats / users, as applicable>\n- **Geographic reach:** <where these customers operate>\n- **Representative examples:** <3–5 named organizations that fit the\n  archetype, each linked to its canonical company profile when one\n  exists>\n\n## Goals\n\nTop-level goals the archetype is trying to achieve. Frame each as a\ndurable outcome, not a tactical task.\n\n| Goal | Why It Matters | Measurable Signal |\n|------|----------------|-------------------|\n| <goal statement> | <why this goal drives decisions> | <how success shows up> |\n\n## Jobs To Be Done\n\nCapture the work the archetype is hiring a solution to do. Use the\nstandard JTBD shape — *when [situation], I want to [motivation], so\nI can [outcome]*. Distinguish functional, emotional, and social\njobs when meaningful.\n\n| Job | Situation | Motivation | Outcome | Type |\n|-----|-----------|------------|---------|------|\n| <job name> | <when ...> | <I want to ...> | <so I can ...> | <functional / emotional / social> |\n\n## Constraints\n\nConstraints that shape what the archetype can adopt or afford. These\nare the reasons a well-designed product still loses the deal.\n\n| Constraint | Why It Binds | Implication |\n|------------|--------------|-------------|\n| <constraint> | <what forces it> | <what it rules out> |\n\nCommon constraint categories to consider: budget, procurement cycle,\ntechnical integration, data-residency, regulatory, internal staffing,\nchange-management appetite.\n\n## Buying Process\n\n| Stage | Who Is Involved | What They Need to See | Time Horizon |\n|-------|-----------------|----------------------|--------------|\n| <awareness / evaluation / decision / adoption> | <roles> | <evidence required> | <typical duration> |\n\n### Decision Roles\n\n- **Economic buyer:** <role and typical seniority>\n- **Technical buyer:** <role>\n- **User champion:** <role>\n- **Blocker risk:** <role most likely to veto>\n\n## Technology Landscape\n\nCurrent systems, integration expectations, and technical pain points\ncharacteristic of this archetype. Keep it vendor-neutral — name\nspecific products only when the archetype is defined by them.\n\n| Capability Area | Typical Current State | Pain Point | Integration Expectation |\n|-----------------|----------------------|-----------|-------------------------|\n| <area> | <what they run today> | <what hurts> | <what a new tool must do> |\n\n## Regulatory Applicability\n\nRegulations that typically apply to this archetype. Link to regulation\npages under the regulatory-research tree when they exist.\n\n| Regulation | Jurisdiction | Why It Applies | Product Implication | Link |\n|-----------|--------------|----------------|---------------------|------|\n| <regulation> | <jurisdiction> | <what triggers it for this archetype> | <what the product must provide> | <relative link> |\n\nIf no regulatory-research pages exist yet for this archetype's scope,\nreplace this table with\n\\`Regulatory applicability pending — no regulatory research exists yet\nfor this scope.\\` and surface the gap as an open question.\n\n## Feature-to-Need Map\n\nMap capabilities the archetype needs to the features that satisfy\nthem. Rows in this table are populated from the competitors phase\n(which ingests rows from the shared feature matrix) and from\ngoal-and-jobs analysis here. Unmet needs flagged in this table are\nthe primary source of \\`req:scan\\` seeds the competitors phase hands\noff to the requirements-analyst bundle.\n\n| Need | Source Job / Goal | Priority | Competitor Coverage | Our Product Coverage | Status |\n|------|-------------------|----------|---------------------|----------------------|--------|\n| <need statement> | <linked job or goal> | <high / medium / low> | <competitor list or \"None\"> | <feature or \"Gap\"> | <covered / partial / unmet> |\n\n## Key Contacts\n\n| Person | Role | Organization | Profile |\n|--------|------|--------------|---------|\n| <name> | <title> | <org> | <relative link to people-profile or \"Pending\"> |\n\n## Sources\n\n1. [<Title>](<URL>) — <brief description>\n\n## Revision History\n\n| Date | Author | Changes |\n|------|--------|---------|\n| YYYY-MM-DD | <author> | Initial archetype profile |\n`;\n\n/**\n * Reference files emitted alongside the `/profile-customer` SKILL.md.\n * Currently just the customer-profile-page template; kept as a\n * `ReadonlyArray` so future reference material (e.g. a JTBD cheat\n * sheet) can be added without changing the bundle shape.\n */\nconst CUSTOMER_PROFILE_REFERENCE_FILES: ReadonlyArray<{\n  readonly path: string;\n  readonly content: string;\n}> = [\n  {\n    path: \"_references/templates/_template-customer-profile.md\",\n    content: TEMPLATE_CUSTOMER_PROFILE,\n  },\n];\n\n/**\n * Sub-agent that researches end customers as first-class entities —\n * segment, jobs-to-be-done, constraints, buying process — and maps\n * competitor features to each archetype's needs. The pipeline is\n * distinct from `company-profile` (which profiles any company) in\n * that it centers the *customer as buyer/user* and closes the loop\n * from unmet need to `req:scan` seed in the requirements pipeline.\n *\n * The prompt is deliberately domain-neutral. Concrete industries,\n * archetype names, regulations, and competitor sets come from the\n * invoking issue body, `docs/src/content/docs/project-context.md`,\n * or the consuming project's `agentConfig.rules` — not from the\n * bundle.\n */\nfunction buildCustomerProfileAnalystSubAgent(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n  tier: AgentModel,\n): AgentSubAgent {\n  return {\n    name: \"customer-profile-analyst\",\n    description:\n      \"Authors customer-archetype research through a 3-phase pipeline (discover → profile → competitors). Segments customer archetypes, profiles each archetype's goals, jobs-to-be-done, constraints, and buying process, then maps competitor features (from the shared software-profile feature matrix) to each archetype's needs and hands off unmet-need gaps to the requirements-analyst as req:scan seeds. One phase per session, tracked by customer:* GitHub issue labels with filesystem-based durability between phases.\",\n    model: tier,\n    maxTurns: 80,\n    platforms: { cursor: { exclude: true } },\n    prompt: [\n      \"# Customer Profile Analyst Agent\",\n      \"\",\n      \"You run a structured customer-archetype research pipeline: discover\",\n      \"the customer archetypes relevant to the consuming project, profile\",\n      \"each archetype's goals, jobs-to-be-done, constraints, and buying\",\n      \"process, and map competitor features (from the shared software-\",\n      \"profile feature matrix) to each archetype's needs. Each phase runs\",\n      \"as its **own agent session**, triggered by a GitHub issue with a\",\n      \"`customer:*` phase label. You handle exactly **one phase per\",\n      \"session** — read the issue to determine which phase to execute.\",\n      \"\",\n      \"This pipeline is **customer-centric**, not product-centric. The\",\n      \"subject of every profile is the customer as a buyer and user — what\",\n      \"they are trying to accomplish, what binds them, and what they are\",\n      \"willing to adopt — not the consuming project's offering. The\",\n      \"consuming project enters the picture only as one possible answer to\",\n      \"the archetype's needs, evaluated alongside the competitor set.\",\n      \"\",\n      \"This agent is **domain-neutral**. It makes no assumptions about\",\n      \"which industries are in scope, which archetypes matter, which\",\n      \"competitors exist, or which needs are latent vs. satisfied. All\",\n      \"concrete vocabulary — archetype names, segment slugs, competitor\",\n      \"sets, regulation identifiers, and need taxonomies — comes from the\",\n      `invoking issue body, \\`${paths.docsRoot}/project-context.md\\`, or`,\n      \"the consuming project's configuration.\",\n      \"\",\n      \"This pipeline is **distinct from `company-profile`**. The\",\n      \"`company-profile` bundle profiles any company entity — competitor,\",\n      \"vendor, partner, customer organization. This bundle profiles\",\n      \"**customer archetypes** (the shape of a buyer/user segment) and\",\n      \"maps competitor features to archetype needs. When an archetype\",\n      \"references a specific customer organization, this pipeline hands\",\n      \"off to `company-profile` via a `company:research` issue rather\",\n      \"than duplicating the org profile itself.\",\n      \"\",\n      \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n      \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...PROJECT_CONTEXT_READER_SECTION,\n      \"## Design Principles\",\n      \"\",\n      \"1. **Customer-centric, not product-centric.** Every profile is\",\n      \"   written from the customer's point of view. The consuming\",\n      \"   project's offering is one option among many — never the default\",\n      \"   frame.\",\n      \"2. **Archetype over instance.** Profiles describe the *shape* of a\",\n      \"   customer segment, not a single named organization. When a named\",\n      \"   organization is profiled in depth, hand it off to the\",\n      \"   `company-profile` bundle via `company:research`.\",\n      \"3. **Jobs-to-be-done framing.** Capture the work the customer is\",\n      \"   hiring a solution to do. Use the standard JTBD shape — *when\",\n      \"   [situation], I want to [motivation], so I can [outcome]*.\",\n      \"4. **Feature-to-need mapping.** The competitors phase is the load-\",\n      \"   bearing step. It ingests rows from the shared software-profile\",\n      \"   feature matrix and maps each feature to the owning archetype's\",\n      \"   needs, then flags unmet needs as `req:scan` seeds for the\",\n      \"   requirements pipeline.\",\n      \"5. **Filesystem durability.** Every phase persists its output to a\",\n      \"   file on disk before closing its issue. Downstream phases read\",\n      \"   those files — never rely on session memory.\",\n      \"6. **Issue graph = state machine.** Phase ordering is encoded with\",\n      \"   `Depends on: #N` links between phase issues. Profile runs only\",\n      \"   after the discover phase identifies the archetype; competitors\",\n      \"   runs only after the profile lands.\",\n      \"7. **Generic over specific.** No hardcoded archetype names, segment\",\n      \"   vocabularies, or competitor assumptions. Use placeholders that\",\n      \"   the invoking issue or consuming project fills in.\",\n      \"8. **Research, not authoring of canonical profiles.** This pipeline\",\n      \"   produces archetype profiles, competitor analyses, and feature-\",\n      \"   to-need maps. It never writes canonical company or people\",\n      \"   profiles, capability models, or requirement documents — those\",\n      \"   are the responsibility of the `company-profile`, `people-\",\n      \"   profile`, `bcm-writer`, and `requirements-writer` bundles.\",\n      \"   Surfaced work is delegated to those bundles via issues.\",\n      \"9. **No fabrication.** Every factual claim must trace to a cited\",\n      \"   source — public research, meeting transcripts, sales materials,\",\n      \"   or an existing documented source. When source material is\",\n      \"   insufficient, block the issue rather than filling gaps from\",\n      \"   general knowledge.\",\n      \"10. **Unmet needs close the loop.** The value of this pipeline is\",\n      \"    the `req:scan` seed it produces for every unmet need the\",\n      \"    archetype carries. An archetype profile with no feature-to-need\",\n      \"    analysis has no operational use.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Source Credibility\",\n      \"\",\n      \"| Tier | Description | Examples | Usage Rules |\",\n      \"|------|-------------|----------|-------------|\",\n      \"| **Tier 1** | Official, authoritative sources | Primary research (recorded customer interviews, sales-call transcripts), published case studies, analyst reports (Gartner, Forrester, equivalent), peer-reviewed studies, official customer documentation | A single Tier 1 source is sufficient to mark a claim as supported. Claims about buying process, budget, and decision authority **require** Tier 1 or Tier 2. |\",\n      \"| **Tier 2** | Reputable professional sources | Vendor case studies, trade-press coverage, industry whitepapers, conference talks, established industry newsletters | Two Tier 2 sources, or one Tier 2 + contextual support, marks a claim as supported. Acceptable as sole source for non-critical colour. |\",\n      \"| **Tier 3** | Informal sources | Blog posts, forums, vendor marketing, social media, Wikipedia | Flag single-source Tier 3 claims. Never sufficient alone for competitive-gap or buying-process claims. |\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## State Machine Overview\",\n      \"\",\n      \"Customer research flows through **3 phases**:\",\n      \"\",\n      \"```\",\n      \"┌───────────┐   ┌───────────┐   ┌─────────────┐\",\n      \"│1. DISCOVER│──▶│2. PROFILE │──▶│3. COMPETI-  │\",\n      \"│Scan for   │   │Research   │   │   TORS      │\",\n      \"│archetypes │   │one arche- │   │Map feature  │\",\n      \"│across the │   │type; write│   │matrix rows  │\",\n      \"│consuming  │   │structured │   │to archetype │\",\n      \"│project    │   │page       │   │needs; flag  │\",\n      \"│           │   │           │   │unmet gaps   │\",\n      \"└───────────┘   └───────────┘   └─────────────┘\",\n      \"```\",\n      \"\",\n      \"**Issue labels encode the phase:**\",\n      \"\",\n      \"| Label | Phase | Session work |\",\n      \"|-------|-------|-------------|\",\n      \"| `customer:discover` | 1. Discover | Scan meeting notes, industry research, company profiles, and prior customer-profile output for archetype candidates. Write a discovery report. Create `customer:profile` issues for each prioritized archetype. 0 web searches. |\",\n      \"| `customer:profile` | 2. Profile | Research one archetype. Populate the archetype page (segment, goals, jobs, constraints, buying process, technology landscape). Create the blocked `customer:competitors` issue and hand off company / people research as needed. 4–8 targeted web searches. |\",\n      \"| `customer:competitors` | 3. Competitors | Map rows from the shared software-profile feature matrix to the archetype's needs. Identify unmet needs. Hand off each unmet need as a `req:scan` seed to the requirements-analyst bundle. 4–8 targeted web searches (for competitor gap filling). |\",\n      \"\",\n      \"All issues also carry `type:customer-profile` and a `status:*` label.\",\n      \"\",\n      \"**Issue count per archetype:** 1 profile + 1 competitors = **2\",\n      \"sessions** (discover is shared across a scope).\",\n      \"\",\n      \"**Shortened paths:**\",\n      \"- Profile a single known archetype with no discovery step (direct\",\n      \"  hand-off from another agent) → **1 session**.\",\n      \"- Re-run competitor mapping after the feature matrix was refreshed\",\n      \"  → **1 session**.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Configurable Paths\",\n      \"\",\n      \"The pipeline uses these placeholders. Consuming projects override the\",\n      \"defaults by passing paths in the skill invocations or by extending\",\n      \"this rule in their own `agentConfig.rules`.\",\n      \"\",\n      \"| Placeholder | Meaning | Default |\",\n      \"|-------------|---------|---------|\",\n      `| \\`<CUSTOMER_ROOT>\\` | Root folder for customer-archetype research | \\`${paths.docsRoot}/customer-research/\\` |`,\n      \"| `<ARCHETYPE_DIR>` | Per-scope directory holding archetype profile pages | `<CUSTOMER_ROOT>/archetypes/` |\",\n      \"| `<ARCHETYPE_PAGE>` | One-archetype profile page | `<ARCHETYPE_DIR>/<ARCHETYPE_SLUG>.md` |\",\n      \"| `<COMPETITORS_DIR>` | Per-archetype competitor analyses | `<CUSTOMER_ROOT>/competitors/` |\",\n      \"| `<COMPETITORS_PAGE>` | One-archetype competitor-analysis page | `<COMPETITORS_DIR>/<ARCHETYPE_SLUG>.md` |\",\n      \"| `<DISCOVERY_DIR>` | Discovery reports written during Phase 1 | `<researchRoot>/customer/` |\",\n      `| \\`<MATRIX_FILE>\\` | Shared software-profile feature-matrix file | \\`${paths.softwareRoot}/feature-matrix.md\\` |`,\n      \"| `<SCOPE_SLUG>` | Short kebab-case slug identifying the discovery scope | derived from the discover issue |\",\n      \"| `<ARCHETYPE_SLUG>` | Short kebab-case slug identifying one archetype | derived from the profile issue |\",\n      \"\",\n      `If \\`${paths.docsRoot}/project-context.md\\` specifies a different`,\n      \"customer-research tree or matrix path, prefer that. Otherwise fall\",\n      \"back to the defaults above.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Agent Loop\",\n      \"\",\n      \"Run this loop exactly once per session. Never start a second issue.\",\n      \"\",\n      \"1. Claim one open `type:customer-profile` issue using phase\",\n      \"   priority: `customer:discover` > `customer:profile` >\",\n      \"   `customer:competitors`. Within a phase, prefer the oldest ready\",\n      \"   issue (FIFO).\",\n      \"2. Transition `status:ready` → `status:in-progress` and create the\",\n      \"   branch per your project's branch-naming convention.\",\n      \"3. Execute the phase handler that matches the issue's `customer:*`\",\n      \"   label.\",\n      \"4. Commit, push, open a PR (if applicable), and close the issue per\",\n      `   your project's PR workflow — see the **${ISSUE_CLOSE_SECTION_TITLE}**`,\n      \"   section below before you close anything yourself.\",\n      \"   Stamp every PR you open with the `origin:agent` label — see the\",\n      \"   **Origin label** section below.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...renderClaimVerificationSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderOriginStampSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderIssueClosePolicySection(),\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 1: Discover (`customer:discover`)\",\n      \"\",\n      \"**Goal:** Identify and segment the customer archetypes relevant to\",\n      \"the consuming project's current scope. Produce a discovery report\",\n      \"listing candidate archetypes with enough context to create profile\",\n      \"issues.\",\n      \"\",\n      \"**Budget:** No web searches. Pure reading and synthesis across the\",\n      \"project's existing documentation.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the discover issue body.** Extract:\",\n      \"   - The discovery scope (`<SCOPE_SLUG>`) — typically an industry,\",\n      \"     a segment, or the consuming project as a whole\",\n      \"   - Authorized input paths (meeting-notes root, industry-research\",\n      \"     root, existing customer-research tree, existing company\",\n      \"     profiles)\",\n      \"   - Optional: known archetypes to include, archetypes to exclude,\",\n      \"     and a priority hint\",\n      \"\",\n      \"2. **Read related project context.** Check\",\n      `   \\`${paths.docsRoot}/project-context.md\\` for the consuming`,\n      \"   project's mission, target segments, and any archetypes already\",\n      \"   called out by other agents.\",\n      \"\",\n      \"3. **Scan existing documentation** for archetype candidates:\",\n      \"   - Meeting transcripts that reference customers, prospects, or\",\n      \"     segments\",\n      \"   - Industry-research pages that describe target segments\",\n      \"   - Company profiles already tagged as `customer`\",\n      \"   - Prior customer-research output in `<CUSTOMER_ROOT>`\",\n      \"\",\n      \"4. **Cluster mentions into archetypes.** Group individual customer\",\n      \"   references by shared segment, size band, geography, and\",\n      \"   jobs-to-be-done signals. An archetype is a reusable shape — if\",\n      \"   three customers share segment, size, and primary job, they are\",\n      \"   one archetype, not three.\",\n      \"\",\n      \"5. **Write the discovery report** to\",\n      \"   `<DISCOVERY_DIR>/customer-discover-<SCOPE_SLUG>-<YYYY-MM-DD>.md`:\",\n      \"\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"Customer Discovery: <Scope>\"',\n      \"   date: YYYY-MM-DD\",\n      \"   parent_issue: <N>\",\n      \"   status: active\",\n      \"   scope: <SCOPE_SLUG>\",\n      \"   ---\",\n      \"\",\n      \"   ## Scope Context\",\n      \"   - **Scope:** <SCOPE_SLUG>\",\n      \"   - **Sources scanned:** <counts by source type>\",\n      \"\",\n      \"   ## Identified Archetypes\",\n      \"\",\n      \"   ### <Archetype Name>\",\n      \"   - **Segment:** <industry / market segment>\",\n      \"   - **Size band:** <SMB / mid-market / enterprise / consumer>\",\n      \"   - **Representative customers:** <3–5 named orgs>\",\n      \"   - **Key signals:** <what clusters them>\",\n      \"   - **Priority:** <high / medium / low>\",\n      \"   - **Existing coverage:** <path if already profiled, or 'None'>\",\n      \"\",\n      \"   ## Already Covered\",\n      \"   <archetypes with existing profile pages under\",\n      \"   <ARCHETYPE_DIR>; skip profile-issue creation for these>\",\n      \"\",\n      \"   ## Recommendations\",\n      \"   - <archetype> → create profile issue (priority: <level>)\",\n      \"   - <archetype> → already covered, no action\",\n      \"   - <archetype> → defer until <condition>\",\n      \"\",\n      \"   ## Sources\",\n      \"   1. <relative path> — <what it contributed>\",\n      \"   ```\",\n      \"\",\n      \"6. **Create one `customer:profile` issue per recommended\",\n      \"   archetype.** Each issue cites the discovery report, names the\",\n      \"   archetype, and identifies the segment. Apply the discover issue's\",\n      \"   priority as the default; escalate if the scope flags a higher-\",\n      \"   priority archetype.\",\n      \"\",\n      \"7. **Commit and push** the discovery report. Close the discover\",\n      `   issue ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 2: Profile (`customer:profile`)\",\n      \"\",\n      \"**Goal:** Research one archetype in depth and populate the archetype\",\n      \"page with segment, goals, jobs-to-be-done, constraints, buying\",\n      \"process, technology landscape, and regulatory applicability.\",\n      \"\",\n      \"**Budget:** 4–8 targeted web searches. Writes one archetype page,\",\n      \"creates the blocked competitors issue, and may create\",\n      \"`company:research` and `people:research` issues for representative\",\n      \"customers and notable contacts.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the discovery report** for context on this archetype's\",\n      \"   priority and scope.\",\n      \"\",\n      \"2. **Read the customer-profile-page template** at\",\n      \"   `.claude/skills/profile-customer/_references/templates/_template-customer-profile.md`.\",\n      \"   The template is authoritative — copy its structure verbatim into\",\n      \"   the archetype page, then populate each section from research.\",\n      \"\",\n      \"3. **Read existing archetype pages** in the same `<ARCHETYPE_DIR>`\",\n      \"   to follow consistent structure and avoid duplication.\",\n      \"\",\n      \"4. **Read prior art.** Scan meeting transcripts, industry research,\",\n      \"   and company profiles that reference the representative customers\",\n      \"   in this archetype.\",\n      \"\",\n      \"5. **Execute 4–8 targeted web searches** to fill gaps:\",\n      \"   - Representative customer overviews (primary use cases,\",\n      \"     published case studies)\",\n      \"   - Segment-level buying-process research and analyst coverage\",\n      \"   - Published jobs-to-be-done or customer-interview research\",\n      \"   - Pain points characteristic of the segment\",\n      \"   - Regulations that govern this archetype's operations\",\n      \"\",\n      \"   If a search returns low-quality results, try one reformulated\",\n      \"   query before moving on. Never exceed the 8-search cap.\",\n      \"\",\n      \"6. **Populate the archetype page** at `<ARCHETYPE_PAGE>` by copying\",\n      \"   the template verbatim and filling each section. Every factual\",\n      \"   claim carries a source citation.\",\n      \"\",\n      \"7. **Create the `customer:competitors` issue** blocked on this\",\n      \"   profile issue (`Depends on: #<this-issue>`). Its body references\",\n      \"   the archetype page and the feature matrix path.\",\n      \"\",\n      \"8. **Create `company:research` issues** for representative\",\n      \"   customer organizations that do not already have a canonical\",\n      \"   profile or an open `company:research` issue. The\",\n      \"   `company-profile` bundle owns the downstream profile; this\",\n      \"   agent only hands off. Each issue must carry:\",\n      \"\",\n      \"   - `type:company-profile`\",\n      \"   - `company:research`\",\n      `   - \\`priority:${labelsForPhase(issueDefaults, \"company:research\").priority}\\``,\n      `   - \\`status:${labelsForPhase(issueDefaults, \"company:research\").status}\\``,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"9. **Create `people:research` issues** for notable contacts\",\n      \"   (economic buyers, technical buyers, user champions) surfaced in\",\n      \"   sources. Keep the list small — at most three individuals per\",\n      \"   profile session — and skip anyone already profiled or queued.\",\n      \"   Each issue must carry:\",\n      \"\",\n      \"   - `type:people-profile`\",\n      \"   - `people:research`\",\n      `   - \\`priority:${labelsForPhase(issueDefaults, \"people:research\").priority}\\``,\n      `   - \\`status:${labelsForPhase(issueDefaults, \"people:research\").status}\\``,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"10. **Verify all handoffs were created** before committing.\",\n      \"\",\n      \"11. **Commit and push** the archetype page. Close the profile issue\",\n      `    ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 3: Competitors (`customer:competitors`)\",\n      \"\",\n      \"**Goal:** Map rows from the shared software-profile feature matrix\",\n      \"to the archetype's needs, identify unmet needs, and hand off each\",\n      \"unmet need as a `req:scan` seed to the requirements-analyst bundle.\",\n      \"\",\n      \"**Budget:** 4–8 targeted web searches — only for closing competitor\",\n      \"coverage gaps the feature matrix does not already answer. No\",\n      \"searches if the matrix is comprehensive enough on its own.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the archetype page** with full goals, jobs, constraints,\",\n      \"   and any preliminary feature-to-need rows.\",\n      \"\",\n      \"2. **Read the shared feature matrix** at `<MATRIX_FILE>`. This is\",\n      \"   the canonical competitor feature data produced by the\",\n      \"   `software-profile` bundle's matrix phase. Rows are scored against\",\n      \"   segment weights — use the scores as a signal but treat the\",\n      \"   archetype's explicit jobs and constraints as authoritative.\",\n      \"\",\n      \"3. **Read existing competitor analyses** in `<COMPETITORS_DIR>` to\",\n      \"   follow consistent structure and avoid duplication.\",\n      \"\",\n      \"4. **Execute up to 4–8 targeted web searches** only to fill\",\n      \"   competitor-coverage gaps the feature matrix does not answer:\",\n      \"   - Competitor products in this archetype's segment that are not\",\n      \"     yet in the matrix\",\n      \"   - Recent competitive moves (M&A, product launches, pricing\",\n      \"     shifts) relevant to the archetype's buying process\",\n      \"   - Published customer complaints or unmet-need signals\",\n      \"\",\n      \"   Skip this step if the matrix already covers the segment.\",\n      \"\",\n      \"5. **Write the competitor-analysis page** at `<COMPETITORS_PAGE>`:\",\n      \"\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"Competitors: <Archetype Name>\"',\n      '   description: \"Competitive analysis for the <Archetype Name> archetype.\"',\n      \"   archetype: <ARCHETYPE_SLUG>\",\n      \"   ---\",\n      \"\",\n      \"   ## Market Overview\",\n      \"   <Brief overview of the competitive landscape this archetype\",\n      \"   evaluates.>\",\n      \"\",\n      \"   ## Key Competitors\",\n      \"\",\n      \"   | Competitor | Relationship | Matrix Row | Threat Level |\",\n      \"   |------------|--------------|------------|--------------|\",\n      \"   | <competitor> | <direct / indirect / adjacent> | <matrix link> | <high / medium / low> |\",\n      \"\",\n      \"   ## Feature-to-Need Map\",\n      \"\",\n      \"   Each row maps one archetype need to the competitor features that\",\n      \"   satisfy it. Competitor features come from `<MATRIX_FILE>`. Rows\",\n      \"   flagged `unmet` are handed off as `req:scan` seeds to the\",\n      \"   requirements-analyst bundle.\",\n      \"\",\n      \"   | Need | Source Job / Goal | Priority | Competitors Covering | Our Product | Status |\",\n      \"   |------|-------------------|----------|----------------------|-------------|--------|\",\n      \"   | <need> | <linked job> | <high / medium / low> | <list or 'None'> | <feature or 'Gap'> | <covered / partial / unmet> |\",\n      \"\",\n      \"   ## Unmet Needs\",\n      \"\",\n      \"   | Need | Priority | Why It's Unmet | Handoff Issue |\",\n      \"   |------|----------|----------------|---------------|\",\n      \"   | <need> | <high / medium / low> | <competitor coverage gap + our gap> | #<N> |\",\n      \"\",\n      \"   ## Implications\",\n      \"   <What the feature-to-need map implies for the consuming\",\n      \"   project's roadmap — which unmet needs are highest leverage,\",\n      \"   which are already well-covered by competitors, which are table\",\n      \"   stakes vs. differentiators.>\",\n      \"\",\n      \"   ## Sources\",\n      \"   1. [<Title>](<URL>) — <brief description>\",\n      \"   ```\",\n      \"\",\n      \"6. **Edit the archetype page's Feature-to-Need Map section** so it\",\n      \"   matches the map authored here. The archetype page stays the\",\n      \"   canonical surface for downstream agents; the competitor page is\",\n      \"   the detailed working document.\",\n      \"\",\n      \"7. **Create `req:scan` issues** for each unmet need. Each issue\",\n      \"   hands off to the `requirements-analyst` bundle so its scan phase\",\n      \"   can deduplicate and open `req:write` issues in the appropriate\",\n      \"   category. Each handoff issue must carry:\",\n      \"\",\n      \"   - `type:requirement`\",\n      \"   - `req:scan`\",\n      `   - \\`priority:${labelsForPhase(issueDefaults, \"req:scan\").priority}\\``,\n      `   - \\`status:${labelsForPhase(issueDefaults, \"req:scan\").status}\\``,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"   The body must also:\",\n      \"   - Link back to the archetype page and the competitor page\",\n      \"   - Cite the specific unmet-need row and the originating job\",\n      \"   - Escalate the priority above the bundle default when the\",\n      \"     archetype is high-priority and the gap is a deal-breaker\",\n      \"\",\n      \"8. **Create `company:research` issues** for competitor organizations\",\n      \"   referenced in the analysis that do not already have a canonical\",\n      \"   profile or an open `company:research` issue. Each issue must\",\n      \"   carry:\",\n      \"\",\n      \"   - `type:company-profile`\",\n      \"   - `company:research`\",\n      `   - \\`priority:${labelsForPhase(issueDefaults, \"company:research\").priority}\\``,\n      `   - \\`status:${labelsForPhase(issueDefaults, \"company:research\").status}\\``,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"9. **Create `people:research` issues** for notable competitor\",\n      \"   leadership or customer-advocacy figures surfaced in the analysis.\",\n      \"   Keep this list small — at most three individuals per competitors\",\n      \"   session — and skip anyone already profiled or queued. Each\",\n      \"   issue must carry:\",\n      \"\",\n      \"   - `type:people-profile`\",\n      \"   - `people:research`\",\n      `   - \\`priority:${labelsForPhase(issueDefaults, \"people:research\").priority}\\``,\n      `   - \\`status:${labelsForPhase(issueDefaults, \"people:research\").status}\\``,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"10. **Commit and push** the competitor-analysis page and the\",\n      `    updated archetype page. Close the competitors issue ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Coordination with Other Agents\",\n      \"\",\n      \"### Upstream: meeting-analyst, industry-discovery, research-pipeline\",\n      \"\",\n      \"Meeting transcripts (especially external meetings), industry-\",\n      \"discovery deliverables, and research-pipeline notes are the primary\",\n      \"inputs to the discover phase. A human opens a `customer:discover`\",\n      \"issue when enough upstream signal has accumulated. This agent never\",\n      \"auto-creates `customer:discover` issues.\",\n      \"\",\n      \"### Upstream: software-profile bundle\",\n      \"\",\n      \"The software-profile bundle's matrix phase produces the canonical\",\n      \"feature-matrix file (`<MATRIX_FILE>`) that the competitors phase\",\n      \"consumes. This agent **reads** the matrix; it never writes to it.\",\n      \"If a competitor product is missing from the matrix, this agent\",\n      \"creates a `software:research` issue rather than adding rows itself.\",\n      \"\",\n      \"### Downstream: requirements-analyst bundle\",\n      \"\",\n      \"Phase 3 (Competitors) hands off actionable unmet needs to the\",\n      \"`requirements-analyst` bundle via `req:scan` issues. Each handoff\",\n      \"issue body identifies the originating archetype and job so the\",\n      \"downstream `requirements-writer` phase picks up the right category\",\n      \"template. This agent never writes requirement documents itself.\",\n      \"\",\n      \"### Downstream: company-profile bundle\",\n      \"\",\n      \"This agent creates `company:research` issues for representative\",\n      \"customer organizations (Phase 2) and competitor organizations\",\n      \"(Phase 3) that do not already have a canonical profile. The\",\n      \"`company-profile` bundle's Phase 1 (research) consumes those issues\",\n      \"and produces the canonical profile. **This boundary is load-\",\n      \"bearing:** the customer-profile pipeline targets archetypes;\",\n      \"`company-profile` targets individual companies. Do not profile a\",\n      \"named customer organization in depth inside an archetype page —\",\n      \"hand it off.\",\n      \"\",\n      \"### Downstream: people-profile bundle\",\n      \"\",\n      \"This agent creates `people:research` issues for notable contacts\",\n      \"(buyers, champions, competitor leadership) surfaced during profile\",\n      \"and competitors phases. The `people-profile` bundle's Phase 1\",\n      \"(research) consumes those issues and produces the canonical person\",\n      \"profile. This agent never writes canonical people profiles itself.\",\n      \"\",\n      \"### File Boundaries\",\n      \"\",\n      \"- **Reads:**\",\n      \"  - `<CUSTOMER_ROOT>/` — prior discovery reports, archetype pages,\",\n      \"    and competitor analyses\",\n      \"  - `<DISCOVERY_DIR>/` — discovery reports\",\n      \"  - `<MATRIX_FILE>` — shared feature matrix (read-only)\",\n      \"  - `<docsRoot>/` — project context, industry-research,\",\n      \"    meeting-notes, regulatory-research, and existing company / people\",\n      \"    profiles for framing context\",\n      \"- **Writes:**\",\n      \"  - `<DISCOVERY_DIR>/customer-discover-<SCOPE_SLUG>-<YYYY-MM-DD>.md` (Phase 1)\",\n      \"  - `<ARCHETYPE_PAGE>` (Phase 2; Phase 3 updates the Feature-to-Need Map)\",\n      \"  - `<COMPETITORS_PAGE>` (Phase 3)\",\n      \"- **Never writes to:**\",\n      \"  - Any canonical company-profile or people-profile path (the\",\n      \"    `company-profile` and `people-profile` bundles own those)\",\n      \"  - `<MATRIX_FILE>` (the `software-profile` bundle owns it)\",\n      \"  - `<BCM_DOC_ROOT>/` (the `bcm-writer` bundle owns this)\",\n      \"  - `<REQUIREMENTS_ROOT>/` (the `requirements-writer` bundle owns\",\n      \"    this)\",\n      \"  - `<BUSINESS_MODELS_ROOT>/` (the `business-models` bundle owns\",\n      \"    this)\",\n      \"  - `<REGULATORY_ROOT>/` (the `regulatory-research` bundle owns\",\n      \"    this)\",\n      \"  - `<STANDARDS_ROOT>/` (the `standards-research` bundle owns this)\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Blocked Issues\",\n      \"\",\n      \"Follow your project's shared Blocked Issues procedure. Additional\",\n      \"block reasons specific to customer research:\",\n      \"\",\n      \"- **No archetype signal.** Discovery phase cannot find enough\",\n      \"  evidence for any archetype to be worth profiling.\",\n      \"- **Feature matrix missing.** Competitors phase requires\",\n      \"  `<MATRIX_FILE>` to exist. If it does not, block and hand off to\",\n      \"  `software-profile` via a `software:matrix` issue.\",\n      \"- **Representative customer behind a non-disclosure.** The archetype\",\n      \"  depends on a customer whose engagement is covered by NDA and\",\n      \"  cannot be summarized from public sources. Block until legal review.\",\n      \"- **Competitors issue arrived before profile completed.** Phase 3\",\n      \"  blocks on the Phase 2 profile issue closing.\",\n      \"- **Regulatory applicability unresolvable.** The archetype\",\n      \"  references regulations that have no regulatory-research page and\",\n      \"  no regulatory:scan issue is open for the scope. Open one and\",\n      \"  block.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Rules\",\n      \"\",\n      \"- **One phase per session.** Never run two phases back-to-back in a\",\n      \"  single session.\",\n      \"- **One archetype per profile session.** Phase 2 is scoped to\",\n      \"  exactly one archetype — never profile multiple archetypes at\",\n      \"  once.\",\n      \"- **Persist before closing.** Every phase must write its output file\",\n      \"  before closing its issue.\",\n      \"- **Search budgets are caps, not targets.** Do not exceed 0\",\n      \"  searches in discover, 8 in profile, or 8 in competitors.\",\n      \"- **Customer-centric framing.** Every profile is written from the\",\n      \"  customer's point of view. Do not default to describing the\",\n      \"  consuming project's offering.\",\n      \"- **Archetype, not instance.** Do not profile a named customer\",\n      \"  organization in depth inside an archetype page — hand it off to\",\n      \"  the `company-profile` bundle via `company:research`.\",\n      \"- **Cite everything.** Every non-trivial factual claim carries a\",\n      \"  source citation. Claims about buying process, budget, or decision\",\n      \"  authority require at least Tier 2 support.\",\n      \"- **No fabrication.** Every claim in a discovery report, archetype\",\n      \"  page, or competitor analysis must trace to a cited source. Do not\",\n      \"  populate from general knowledge alone.\",\n      \"- **Relative links only.** Cross-references between docs use\",\n      \"  relative markdown paths, never absolute `https://github.com/...`\",\n      \"  URLs.\",\n      \"- **Read-only over the feature matrix.** Never edit `<MATRIX_FILE>`.\",\n      \"  Missing rows are a `software-profile` concern; open a\",\n      \"  `software:research` or `software:matrix` issue instead.\",\n      \"- **Never cross agent boundaries.** Do not write canonical company\",\n      \"  or people profiles, requirement documents, capability models,\",\n      \"  business-model canvases, regulatory pages, or standards pages.\",\n      \"  Hand off surfaced work via `company:research`, `people:research`,\",\n      \"  `software:research`, `regulatory:scan`, or `req:scan` issues.\",\n      \"- **Unmet needs produce `req:scan` seeds.** Phase 3 is not complete\",\n      \"  until every unmet need in the Feature-to-Need Map has a matching\",\n      \"  `req:scan` issue open or explicitly deferred with a reason.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off the discover phase of a customer-research campaign. */\nfunction buildDiscoverCustomersSkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"discover-customers\",\n    description:\n      \"Kick off the discover phase of a customer-research campaign. Creates a customer:discover issue for the supplied scope (industry, segment, or the consuming project as a whole) and dispatches Phase 1 of the customer-profile-analyst, which scans existing documentation for archetype candidates, writes a discovery report, and creates downstream customer:profile issues.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"customer-profile-analyst\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Discover Customer Archetypes\",\n      \"\",\n      \"Kick off a customer-research campaign for a given scope — an\",\n      \"industry, a market segment, or the consuming project as a whole.\",\n      \"Creates a `customer:discover` issue carrying the scope identifier\",\n      \"and dispatches Phase 1 (Discover) in the customer-profile-analyst\",\n      \"agent.\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/discover-customers <scope-slug>\",\n      \"\",\n      \"Optional extensions in the issue body:\",\n      \"- `scope_name: <human-readable name>` — defaults to the slug\",\n      \"  prettified\",\n      \"- `include_archetypes: <list>` — archetypes that must be covered\",\n      \"- `exclude_archetypes: <list>` — archetypes to skip\",\n      \"- `sources: <list>` — additional authorized input paths\",\n      \"\",\n      \"## Default Paths\",\n      \"\",\n      \"If the project has no override in\",\n      `\\`${paths.docsRoot}/project-context.md\\` or \\`agentConfig.rules\\`,`,\n      \"outputs land under:\",\n      \"\",\n      `- Discovery report: \\`${paths.researchRoot}/customer/customer-discover-<scope-slug>-<YYYY-MM-DD>.md\\``,\n      `- Archetype pages (Phase 2): \\`${paths.docsRoot}/customer-research/archetypes/<archetype-slug>.md\\``,\n      `- Competitor analyses (Phase 3): \\`${paths.docsRoot}/customer-research/competitors/<archetype-slug>.md\\``,\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `customer:discover` issue with `type:customer-profile`,\",\n      `   \\`priority:${labelsForPhase(issueDefaults, \"customer:discover\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"customer:discover\").status}\\`. The body must include the`,\n      \"   scope slug and any known archetypes to include or exclude.\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 1 (Discover) of the customer-profile-analyst agent.\",\n      \"3. Phase 1 writes the discovery report and creates one\",\n      \"   `customer:profile` issue per prioritized archetype.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- A discovery report under the project's research directory,\",\n      \"  listing candidate archetypes with segment, size, representative\",\n      \"  customers, and priority.\",\n      \"- One `customer:profile` issue per prioritized archetype.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off the profile phase for one customer archetype. */\nfunction buildProfileCustomerSkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"profile-customer\",\n    description:\n      \"Kick off the profile phase for one customer archetype. Creates a customer:profile issue for the supplied archetype and dispatches Phase 2 of the customer-profile-analyst, which populates the archetype page with segment, goals, jobs-to-be-done, constraints, buying process, technology landscape, and regulatory applicability using the ship-with customer-profile-page template.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"customer-profile-analyst\",\n    platforms: { cursor: { exclude: true } },\n    referenceFiles: CUSTOMER_PROFILE_REFERENCE_FILES,\n    instructions: [\n      \"# Profile Customer Archetype\",\n      \"\",\n      \"Author an archetype profile page for one customer archetype.\",\n      \"Creates a `customer:profile` issue and dispatches Phase 2 (Profile)\",\n      \"in the customer-profile-analyst agent.\",\n      \"\",\n      \"Most campaigns do not invoke this skill directly — Phase 1\",\n      \"(Discover) creates profile issues automatically. Use this skill\",\n      \"when:\",\n      \"\",\n      \"- A single archetype needs refreshed research without a full\",\n      \"  discovery pass\",\n      \"- A new archetype emerges between scheduled discovery sessions\",\n      \"- The discover phase deferred an archetype and the blocker is now\",\n      \"  resolved\",\n      \"- Another agent (e.g. `industry-discovery`) flagged a segment that\",\n      \"  needs its own archetype page\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/profile-customer <archetype-slug>\",\n      \"\",\n      \"Optional extensions in the issue body:\",\n      \"- `discovery_report: <path>` — prior discovery-phase report\",\n      \"  (optional when invoked manually)\",\n      \"- `segment: <slug>` — segment the archetype belongs to\",\n      \"- `sources: <list>` — additional authorized input paths (meeting\",\n      \"  transcripts, industry-research pages, prior customer notes)\",\n      \"\",\n      \"## Customer-Profile Template\",\n      \"\",\n      \"This skill ships a verbatim customer-profile-page template at\",\n      \"`.claude/skills/profile-customer/_references/templates/_template-customer-profile.md`.\",\n      \"The Phase 2 handler reads that file as its authoritative structure —\",\n      \"every archetype page copies the template and fills segment, goals,\",\n      \"jobs-to-be-done, constraints, buying process, technology landscape,\",\n      \"regulatory applicability, and the preliminary feature-to-need map.\",\n      \"\",\n      \"## Default Paths\",\n      \"\",\n      \"If the project has no override in\",\n      `\\`${paths.docsRoot}/project-context.md\\` or \\`agentConfig.rules\\`,`,\n      \"the archetype page lands at:\",\n      \"\",\n      `\\`${paths.docsRoot}/customer-research/archetypes/<archetype-slug>.md\\``,\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `customer:profile` issue with `type:customer-profile`,\",\n      `   \\`priority:${labelsForPhase(issueDefaults, \"customer:profile\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"customer:profile\").status}\\`. The body must include the`,\n      \"   archetype slug and (optionally) the segment slug.\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 2 (Profile) of the customer-profile-analyst agent.\",\n      \"   The agent runs 4–8 targeted web searches and populates the\",\n      \"   archetype page.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- A populated archetype page with segment, goals, jobs-to-be-done,\",\n      \"  constraints, buying process, technology landscape, regulatory\",\n      \"  applicability, and a preliminary feature-to-need map.\",\n      \"- One blocked `customer:competitors` issue for the downstream\",\n      \"  Phase 3.\",\n      \"- `company:research` issues for representative customer\",\n      \"  organizations not yet profiled.\",\n      \"- `people:research` issues for notable contacts (economic buyer,\",\n      \"  technical buyer, user champion) not yet profiled.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off the competitors phase for one customer archetype. */\nfunction buildAnalyzeCustomerCompetitorsSkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"analyze-customer-competitors\",\n    description:\n      \"Kick off the competitors phase for one customer archetype. Creates a customer:competitors issue for the supplied archetype and dispatches Phase 3 of the customer-profile-analyst, which maps rows from the shared software-profile feature matrix to the archetype's needs, identifies unmet needs, and hands off each unmet need as a req:scan seed to the requirements-analyst bundle.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"customer-profile-analyst\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Analyze Customer Competitors\",\n      \"\",\n      \"Map rows from the shared software-profile feature matrix to one\",\n      \"customer archetype's needs, identify unmet needs, and hand off each\",\n      \"unmet need to the requirements pipeline as a `req:scan` seed.\",\n      \"Creates a `customer:competitors` issue and dispatches Phase 3\",\n      \"(Competitors) in the customer-profile-analyst agent.\",\n      \"\",\n      \"Most campaigns do not invoke this skill directly — Phase 2\",\n      \"(Profile) creates the competitors issue automatically, blocked on\",\n      \"the profile issue that spawned it. Use this skill when:\",\n      \"\",\n      \"- An archetype page was refreshed and the feature-to-need map\",\n      \"  needs a re-run\",\n      \"- The feature matrix was refreshed with new competitor rows and\",\n      \"  the archetype's map needs to incorporate them\",\n      \"- A human authored the archetype page and needs the competitive\",\n      \"  analysis synthesized separately\",\n      \"- The competitors phase was deferred and the profile is now\",\n      \"  landed\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/analyze-customer-competitors <archetype-slug>\",\n      \"\",\n      \"Required extensions in the issue body:\",\n      \"- `archetype_page: <path>` — link to the archetype profile page\",\n      \"  being analyzed\",\n      \"\",\n      \"Optional extensions:\",\n      \"- `matrix_file: <path>` — override for the shared feature-matrix\",\n      `  file. Defaults to \\`${paths.softwareRoot}/feature-matrix.md\\`.`,\n      \"\",\n      \"## Default Paths\",\n      \"\",\n      \"If the project has no override in\",\n      `\\`${paths.docsRoot}/project-context.md\\` or \\`agentConfig.rules\\`,`,\n      \"the competitor-analysis page lands at:\",\n      \"\",\n      `\\`${paths.docsRoot}/customer-research/competitors/<archetype-slug>.md\\``,\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `customer:competitors` issue with\",\n      `   \\`type:customer-profile\\`, \\`priority:${labelsForPhase(issueDefaults, \"customer:competitors\").priority}\\`, and`,\n      `   \\`status:${labelsForPhase(issueDefaults, \"customer:competitors\").status}\\` (or \\`status:blocked\\` when still dependent on a`,\n      \"   Phase 2 profile issue). Body must include the archetype page\",\n      \"   path.\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 3 (Competitors) of the customer-profile-analyst\",\n      \"   agent. The agent reads `<MATRIX_FILE>` and runs up to 4–8 web\",\n      \"   searches only to close competitor-coverage gaps the matrix does\",\n      \"   not answer.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- A competitor-analysis page with market overview, key competitors,\",\n      \"  feature-to-need map, unmet-needs table, and implications.\",\n      \"- The archetype page's Feature-to-Need Map section is rewritten to\",\n      \"  match the detailed analysis.\",\n      \"- One `req:scan` issue (consumed by the `requirements-analyst`\",\n      \"  bundle) per unmet need identified. Each handoff carries the\",\n      \"  originating archetype, job, and priority so the downstream\",\n      \"  `requirements-writer` phase picks up the right template.\",\n      \"- `company:research` issues for competitor organizations not yet\",\n      \"  profiled.\",\n      \"- Optional `people:research` issues for notable competitor\",\n      \"  leadership.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/**\n * Customer-profile bundle — enabled by default.\n *\n * Consuming projects can disable it with\n * `excludeBundles: [\"customer-profile\"]`. `appliesWhen` always\n * returns `true` per the workflow-bundle peer-present assumption.\n *\n * Ships a sub-agent (`customer-profile-analyst`), three\n * user-invocable skills (`/discover-customers`, `/profile-customer`,\n * `/analyze-customer-competitors`), a customer-profile-page template\n * (emitted alongside the profile skill), and `type:customer-profile`\n * plus `customer:*` phase labels.\n *\n * The bundle sits downstream of `meeting-analysis`,\n * `industry-discovery`, and `research-pipeline` (which surface the\n * need for customer-archetype research) and hands off unmet needs to\n * the `requirements-analyst` bundle via `req:scan` issues, and\n * canonical profiles to `company-profile` and `people-profile` for\n * representative customer organizations, competitor organizations,\n * and notable contacts.\n *\n * Distinct from `company-profile`: the `company-profile` bundle\n * targets any company entity (competitor, vendor, partner, customer\n * organization); this bundle targets **customer archetypes** (the\n * reusable shape of a buyer/user segment) and closes the loop from\n * unmet need to `req:scan` seed via the shared software-profile\n * feature matrix.\n */\nexport function buildCustomerProfileBundle(\n  paths: ResolvedAgentPaths = DEFAULT_AGENT_PATHS,\n  issueDefaults: ResolvedIssueDefaults = DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n  tier: AgentModel = AGENT_MODEL.BALANCED,\n): AgentRuleBundle {\n  return {\n    name: \"customer-profile\",\n    description:\n      \"Customer-archetype research pipeline: discover, profile, competitors. 3 phases with customer:* phase labels. Segments customer archetypes, profiles each archetype's goals, jobs-to-be-done, constraints, and buying process, then maps competitor features (from the shared software-profile feature matrix) to each archetype's needs and hands off unmet-need gaps to the requirements-analyst bundle as req:scan seeds. Enabled by default; domain-neutral; customer-centric (distinct from company-profile); filesystem-durable between phases.\",\n    appliesWhen: () => true,\n    rules: [\n      {\n        name: \"customer-profile-workflow\",\n        description:\n          \"Describes the 3-phase customer-profile pipeline, the customer:* label taxonomy, and the handoff boundaries with requirements-analyst (req:scan seeds), company-profile, people-profile, and software-profile (read-only feature matrix).\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Customer Profile Workflow\",\n          \"\",\n          \"Use `/discover-customers <scope-slug>` to kick off a\",\n          \"customer-archetype research campaign. The pipeline runs in 3\",\n          \"phases — discover, profile, competitors — each tracked by its\",\n          \"own GitHub issue labeled `customer:discover`,\",\n          \"`customer:profile`, or `customer:competitors`. All issues carry\",\n          \"`type:customer-profile`.\",\n          \"\",\n          \"Two additional user-invocable skills drive the downstream\",\n          \"phases directly when the default pipeline needs to be entered\",\n          \"mid-stream:\",\n          \"\",\n          \"- `/profile-customer <archetype-slug>` — author one archetype\",\n          \"  page (normally created by the discover phase automatically).\",\n          \"- `/analyze-customer-competitors <archetype-slug>` — map the\",\n          \"  shared feature matrix to an archetype's needs and hand off\",\n          \"  `req:scan` seeds to the `requirements-analyst` bundle\",\n          \"  (normally created by the profile phase automatically).\",\n          \"\",\n          \"The bundle produces **discovery reports, archetype profile\",\n          \"pages, and competitor-analysis pages with feature-to-need\",\n          \"maps**. It never writes canonical company or people profiles,\",\n          \"requirement documents, capability models, business-model\",\n          \"canvases, regulatory pages, or standards pages — surfaced work\",\n          \"is delegated to the `company-profile`, `people-profile`, and\",\n          \"`requirements-analyst` bundles via `company:research`,\",\n          \"`people:research`, and `req:scan` issues respectively.\",\n          \"\",\n          \"This pipeline is **distinct from `company-profile`**. The\",\n          \"`company-profile` bundle targets any company entity; this\",\n          \"bundle targets **customer archetypes** (the reusable shape of\",\n          \"a buyer/user segment) and maps competitor features to archetype\",\n          \"needs. When an archetype references a specific customer\",\n          \"organization, the pipeline hands off to `company-profile` via\",\n          \"`company:research` rather than duplicating the organizational\",\n          \"profile.\",\n          \"\",\n          \"The competitors phase is **read-only** over the shared\",\n          \"software-profile feature-matrix file. Missing competitor rows\",\n          \"are a `software-profile` concern; this bundle opens\",\n          \"`software:research` issues rather than editing the matrix.\",\n          \"\",\n          \"Consumer-specific vocabularies (which industries, archetypes,\",\n          \"and segments to cover) are supplied per-project via\",\n          `\\`${paths.docsRoot}/project-context.md\\` or the invoking`,\n          \"issue body. The bundle is domain-neutral — no archetypes,\",\n          \"segments, or competitors are hardcoded.\",\n          \"\",\n          \"See the `customer-profile-analyst` agent definition for full\",\n          \"workflow details, default paths, configurable placeholders, and\",\n          \"phase-by-phase instructions.\",\n        ].join(\"\\n\"),\n        platforms: {\n          cursor: { exclude: true },\n        },\n        tags: [\"workflow\"],\n      },\n    ],\n    skills: [\n      buildDiscoverCustomersSkill(paths, issueDefaults),\n      buildProfileCustomerSkill(paths, issueDefaults),\n      buildAnalyzeCustomerCompetitorsSkill(paths, issueDefaults),\n    ],\n    subAgents: [\n      buildCustomerProfileAnalystSubAgent(paths, issueDefaults, tier),\n    ],\n    labels: [\n      {\n        name: \"type:customer-profile\",\n        color: \"5319E7\",\n        description:\n          \"Researches a customer archetype: discovery, deep profile, or competitor analysis\",\n      },\n      {\n        name: \"customer:discover\",\n        color: \"C5DEF5\",\n        description:\n          \"Phase 1: scan docs for archetype candidates, write discovery report, create profile issues\",\n      },\n      {\n        name: \"customer:profile\",\n        color: \"BFDADC\",\n        description:\n          \"Phase 2: deep-research one archetype: segment, goals, JTBD, constraints, buying process, tech\",\n      },\n      {\n        name: \"customer:competitors\",\n        color: \"D4C5F9\",\n        description:\n          \"Phase 3: map feature-matrix rows to archetype needs and hand off req:scan seeds\",\n      },\n    ],\n  };\n}\n\n/**\n * Default-paths instance of the customer-profile bundle, preserved\n * for backward compatibility with consumers that import the const\n * directly. The factory above is the canonical entry point when a\n * consumer supplies `AgentConfigOptions.paths`.\n */\nexport const customerProfileBundle: AgentRuleBundle =\n  buildCustomerProfileBundle();\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { DEFAULT_AGENT_PATHS, ResolvedAgentPaths } from \"./paths\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n  AGENT_MODEL,\n  AGENT_RULE_SCOPE,\n  AgentProcedure,\n  AgentSkill,\n  AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent scaffolding for the docs-sync pipeline. Keeps documentation\n * in lockstep with code as the monorepo evolves by running in two\n * modes: (1) a **pre-PR sync check** that detects drift introduced by\n * a diff and updates docs or files follow-ups, and (2) a **full-\n * codebase audit** that produces a prioritized doc backlog.\n *\n * **Status: scaffolding only.** This bundle is the first child of the\n * docs-sync epic. The sub-agent prompt and skill instructions describe\n * the intended contract but the behavior is deliberately not\n * implemented — drift-detection, TSDoc stub insertion, API-extractor\n * integration, link integrity, and audit-mode scoring are all carried\n * by downstream child issues. Invoking `/docs-sync-pr` or\n * `/docs-sync-audit` against this scaffold produces a no-op session\n * that explains the state and stops.\n *\n * Implements the epic design in a neutral, domain-agnostic way:\n * configurable doc root (typically the Starlight singleton at\n * `/docs`) and configurable package roots (typically `packages/`)\n * come from the invoking issue body or the consuming project's\n * configuration. No hardcoded domains, companies, or product names.\n */\nfunction buildDocsSyncSubAgent(_paths: ResolvedAgentPaths): AgentSubAgent {\n  return {\n    name: \"docs-sync\",\n    description:\n      \"Keeps documentation in lockstep with code. Runs in two modes: (1) pre-PR sync check (diff-scoped, `docs-sync:scan` -> `docs-sync:fix`) that detects drift a diff introduces and either auto-applies mechanical fixes, flags advisory findings, or hard-blocks the PR; and (2) full-repo audit (`/docs-sync-audit`) that emits a prioritized `docs:write` backlog. This issue ships the scaffold only — behavior is implemented by downstream child issues.\",\n    model: AGENT_MODEL.BALANCED,\n    maxTurns: 80,\n    platforms: { cursor: { exclude: true } },\n    prompt: [\n      \"# Docs-Sync Agent (scaffold)\",\n      \"\",\n      \"This sub-agent keeps documentation in lockstep with code. It runs\",\n      \"in one of two modes per session:\",\n      \"\",\n      \"- **Pre-PR sync check** — invoked via `/docs-sync-pr`, scoped to\",\n      \"  the diff on the current branch against `main`. Emits a sticky\",\n      \"  `## Docs sync` comment on the PR, auto-applies mechanical fixes,\",\n      \"  and either clears, adds an advisory, or applies\",\n      \"  `review:human-required` to hand off to `pr-reviewer`.\",\n      \"- **Full-repo audit** — invoked via `/docs-sync-audit`, walks the\",\n      \"  whole monorepo (or a named scope), produces a prioritized\",\n      \"  backlog of `docs:write` follow-up issues.\",\n      \"\",\n      \"## Status: scaffolding only\",\n      \"\",\n      \"This release ships the **skeleton** of the docs-sync pipeline so\",\n      \"downstream child issues have a stable home. The behavior below is\",\n      \"intentionally **not yet implemented**:\",\n      \"\",\n      \"- Drift detection (API-extractor, TSDoc parsing, reference\",\n      \"  extraction, link integrity, code-sample compilation).\",\n      \"- Mechanical fixes (TSDoc stubs, dead-link updates, registry\",\n      \"  sync, rename-follow in prose).\",\n      \"- Advisory / blocking routing, sticky PR comment, pr-reviewer\",\n      \"  handoff.\",\n      \"- Audit-mode walker, 5-factor scoring, `docs:write` backlog\",\n      \"  emission.\",\n      \"\",\n      \"When invoked against this scaffold, post a one-line comment on\",\n      \"the tracking issue explaining that the pipeline is not yet wired\",\n      \"and stop. Do not attempt to apply fixes, open follow-up issues,\",\n      \"or block a PR — the behavior belongs to subsequent child issues\",\n      \"of the parent epic.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...PROJECT_CONTEXT_READER_SECTION,\n      \"## Design Overview\",\n      \"\",\n      \"The docs-sync pipeline mirrors the `maintenance-audit` pattern:\",\n      \"audit-first, narrow-write second, filesystem-durable between\",\n      \"phases. It runs through **2 phases** once the pipeline is wired:\",\n      \"\",\n      \"| Phase | Label | Writes? |\",\n      \"|-------|-------|---------|\",\n      \"| 1. Scan | `docs-sync:scan` | Audit report to disk; no doc edits |\",\n      \"| 2. Fix | `docs-sync:fix` | **Narrow** mechanical edits only, plus `docs:write` follow-ups for conceptual changes |\",\n      \"\",\n      \"Drift classifications are encoded via two additional labels:\",\n      \"\",\n      \"| Label | Meaning |\",\n      \"|-------|---------|\",\n      \"| `docs-sync:advisory` | Drift was detected but does not block the PR. Posted as a non-blocking note on the sticky `## Docs sync` comment. |\",\n      \"| `docs-sync:blocking` | Drift blocks the PR. Applied together with `review:human-required` so `pr-reviewer` owns the merge gate. |\",\n      \"\",\n      \"All pipeline issues also carry `type:docs-sync` and a `status:*`\",\n      \"label.\",\n      \"\",\n      \"## Invocation modes (scaffolded)\",\n      \"\",\n      \"- **`/docs-sync-pr <branch>`** — diff-scoped check against\",\n      \"  `main`. Intended to run after a code change, before\",\n      \"  `/review-pr`. Manual invocation only in this scaffolding\",\n      \"  release; a GitHub Actions trigger is on the roadmap (tracked\",\n      \"  as a follow-up epic to the parent docs-sync epic).\",\n      \"- **`/docs-sync-audit [<scope>]`** — full-repo or scoped audit.\",\n      \"  Produces a prioritized backlog of `docs:write` issues once\",\n      \"  child issues land the walker and the scoring model.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 1: Scan\",\n      \"\",\n      \"Phase 1 walks the repo, runs every registered drift check, and\",\n      \"writes a single combined **audit report** to disk. Phase 1 never\",\n      \"edits documentation — only the persisted report changes between\",\n      \"scan and fix.\",\n      \"\",\n      \"### Audit report\",\n      \"\",\n      \"The report shape is exported from `@codedrifters/configulator`\",\n      \"as `AuditReport` (under `src/docs-sync/scan/`) so Phase 2 and\",\n      \"any downstream consumers share one definition. Reports are\",\n      \"persisted at:\",\n      \"\",\n      \"```\",\n      \".state/docs-sync/<issue-number>-audit.json\",\n      \"```\",\n      \"\",\n      \"Every report carries a `schemaVersion`, the `issueNumber`, the\",\n      \"invocation `mode` (`pr` or `audit`), the `generatedAt` UTC\",\n      \"timestamp, the `repoRoot`, and an optional `scope` label, plus\",\n      \"two parallel views of the findings:\",\n      \"\",\n      \"- **`categories`** — findings grouped by drift-check category.\",\n      \"  Every category key is always present; empty arrays are\",\n      \"  persisted explicitly. The five categories are `apiDiff`,\",\n      \"  `tsdocCoverage`, `referenceMismatches`, `linkFailures`, and\",\n      \"  `sampleFailures`.\",\n      \"- **`findings`** — the same records re-aggregated as a single\",\n      \"  flat array, sorted by severity (`blocking` first), then\",\n      \"  category, file, line, and subject. Provided so consumers\",\n      \"  that don't need the category grouping can iterate one array\",\n      \"  and see the merge-blocking findings at the top.\",\n      \"\",\n      \"Every finding carries a `category`, `severity`\",\n      \"(`mechanical` / `advisory` / `blocking`), `location`, `subject`,\",\n      \"`details`, and an optional `fixHint` for the Phase 2 fix agent.\",\n      \"\",\n      \"### Orchestrator\",\n      \"\",\n      \"The scan is driven by `runScan(...)` (also exported under\",\n      \"`src/docs-sync/scan/`). The orchestrator accepts a list of\",\n      \"`AuditCheckRunner` instances, invokes each one in registration\",\n      \"order, merges the findings into the report, and (optionally)\",\n      \"persists the report to disk. The default check list is empty —\",\n      \"this skeleton release runs cleanly with no checks registered\",\n      \"and produces a schema-compliant report whose category arrays\",\n      \"are all empty.\",\n      \"\",\n      \"Children of the parent docs-sync epic plug runners into the\",\n      \"orchestrator: API/TSDoc/reference checks land first, link\",\n      \"and fenced-sample checks land second, the fix phase reads the\",\n      \"persisted report, and the audit-mode walker reuses the same\",\n      \"report shape.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Write Boundaries\",\n      \"\",\n      \"Even once the pipeline is wired, the following boundaries are\",\n      \"non-negotiable:\",\n      \"\",\n      \"- **Mechanical fixes only.** The agent never rewrites conceptual\",\n      \"  prose, ADRs, requirement bodies, or BCM capability models.\",\n      \"  Those go to `docs:write` follow-ups routed to the appropriate\",\n      \"  writer bundle or to a human.\",\n      \"- **Policy-protected paths stay off-limits.** Paths already\",\n      \"  listed in `human-required.paths` in the PR Review Policy\",\n      \"  (ADRs, `project-context.md`, `.github/workflows/**`,\",\n      \"  `.projenrc.ts`, `CLAUDE.md`, `.claude/**`,\",\n      \"  `packages/**/package.json`) are never auto-edited by this\",\n      \"  agent — it only flags them.\",\n      \"- **No merge calls.** The agent never invokes `gh pr merge`.\",\n      \"  When drift blocks a PR it applies `review:human-required`\",\n      \"  and `pr-reviewer` owns the merge gate.\",\n      \"- **AST-grounded references.** All symbol references are\",\n      \"  extracted from the TypeScript compiler AST, never from prose\",\n      \"  recall — preventing hallucinated API names.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Rules\",\n      \"\",\n      \"- **Scaffolding only.** Do not implement drift detection,\",\n      \"  mechanical fixes, or backlog emission in this sub-agent prompt —\",\n      \"  those behaviors belong to downstream child issues of the parent\",\n      \"  epic.\",\n      \"- **Stop on invocation.** When invoked against the scaffold,\",\n      \"  post a one-line comment explaining the pipeline is not yet\",\n      \"  wired and stop.\",\n      \"- **Respect the two-phase contract.** Once children land the\",\n      \"  behavior, Phase 1 (Scan) writes a durable audit report and\",\n      \"  never edits docs; Phase 2 (Fix) reads the report, applies only\",\n      \"  mechanical idempotent fixes, and files `docs:write` follow-ups\",\n      \"  for conceptual changes.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/**\n * Skill stub: pre-PR drift check. Invocation currently no-ops against\n * the scaffold — behavior is carried by downstream child issues of\n * the parent docs-sync epic.\n */\nfunction buildDocsSyncPrSkill(): AgentSkill {\n  return {\n    name: \"docs-sync-pr\",\n    description:\n      \"Pre-PR docs-sync drift check (scaffold). Once downstream child issues wire the behavior, this skill runs a diff-scoped scan against main, auto-applies mechanical fixes, and either clears, posts an advisory, or applies `review:human-required`. Currently no-ops with an explanatory comment.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"docs-sync\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Docs-Sync PR (scaffold)\",\n      \"\",\n      \"Run the pre-PR docs-sync drift check against the current branch.\",\n      \"\",\n      \"## Status: scaffold\",\n      \"\",\n      \"This skill is part of the docs-sync scaffolding release. The\",\n      \"drift-detection behavior is deliberately not yet implemented —\",\n      \"downstream child issues of the parent docs-sync epic will wire\",\n      \"API-extractor diffing, TSDoc parsing, reference extraction, link\",\n      \"integrity, and code-sample compilation into a single scan, then\",\n      \"add the fix phase that auto-applies mechanical repairs or flags\",\n      \"advisory / blocking drift.\",\n      \"\",\n      \"When invoked today, this skill should:\",\n      \"\",\n      \"1. Post a one-line comment on the invoking PR explaining that\",\n      \"   the docs-sync pipeline is scaffolded but not yet functional.\",\n      \"2. Exit without creating issues, editing files, or applying\",\n      \"   labels.\",\n      \"\",\n      \"## Usage (once wired)\",\n      \"\",\n      \"```\",\n      \"/docs-sync-pr <branch>\",\n      \"```\",\n      \"\",\n      \"Where `<branch>` is the head branch of the PR to check. The\",\n      \"skill diffs the branch against `main`, runs the scan checks, and\",\n      \"posts a sticky `## Docs sync` comment on the PR.\",\n      \"\",\n      \"## Output (once wired)\",\n      \"\",\n      \"- Mechanical fixes committed to the branch under narrow write\",\n      \"  boundaries (missing TSDoc stubs, dead-link updates, registry\",\n      \"  sync, rename-follow in prose).\",\n      \"- A sticky `## Docs sync` comment summarizing detected drift,\",\n      \"  advisory findings, and any blocking issues.\",\n      \"- `docs-sync:advisory` or `docs-sync:blocking` applied to the\",\n      \"  PR as appropriate. Blocking drift additionally applies\",\n      \"  `review:human-required` so `pr-reviewer` owns the merge gate.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/**\n * Skill stub: full-repo docs audit. Invocation currently no-ops\n * against the scaffold — behavior is carried by downstream child\n * issues of the parent docs-sync epic.\n */\nfunction buildDocsSyncAuditSkill(): AgentSkill {\n  return {\n    name: \"docs-sync-audit\",\n    description:\n      \"Full-repo docs-sync audit (scaffold). Once downstream child issues wire the walker and the 5-factor scoring model, this skill emits a prioritized `docs:write` backlog. Currently no-ops with an explanatory comment.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"docs-sync\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Docs-Sync Audit (scaffold)\",\n      \"\",\n      \"Run the full-repo (or scoped) docs-sync audit. Produces a\",\n      \"prioritized backlog of `docs:write` follow-up issues ordered by\",\n      \"API-surface coverage, critical-path weight, stale-page age,\",\n      \"orphan-page detection, and inbound link count.\",\n      \"\",\n      \"## Status: scaffold\",\n      \"\",\n      \"This skill is part of the docs-sync scaffolding release. The\",\n      \"audit walker and scoring model are deliberately not yet\",\n      \"implemented — downstream child issues of the parent docs-sync\",\n      \"epic will wire them in.\",\n      \"\",\n      \"When invoked today, this skill should:\",\n      \"\",\n      \"1. Post a one-line comment on the invoking issue explaining\",\n      \"   that the audit walker is scaffolded but not yet functional.\",\n      \"2. Exit without creating issues, editing files, or applying\",\n      \"   labels.\",\n      \"\",\n      \"## Usage (once wired)\",\n      \"\",\n      \"```\",\n      \"/docs-sync-audit [<scope>]\",\n      \"```\",\n      \"\",\n      \"Where `<scope>` is an optional path filter (for example a\",\n      \"specific package or a specific docs subtree). Omit the scope\",\n      \"to audit the full repo.\",\n      \"\",\n      \"## Output (once wired)\",\n      \"\",\n      \"- A `docs-sync-audit-<YYYY-MM-DD>.md` report committed to the\",\n      \"  docs audit root.\",\n      \"- One `docs:write` follow-up issue per actionable finding,\",\n      \"  prioritized per the 5-factor scoring model declared in the\",\n      \"  parent epic's design.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/**\n * Render the shell body of the `.claude/procedures/extract-api.sh`\n * helper. Exported so the docs-sync bundle can register it as an\n * `AgentProcedure` and the bundles test suite can assert on the\n * script's contents.\n *\n * The helper runs `@microsoft/api-extractor` end-to-end for a single\n * package and writes the `.api.md` rollup to the scratch folder\n * declared by that package's `api-extractor.json`. Rollups are\n * **regenerate-on-scan** per the docs-sync epic resolved decision #3\n * — the scan phase consumes the freshly-regenerated rollup in-memory\n * rather than comparing against a committed baseline.\n *\n * Exit codes: `0` success, `1` usage / missing directory, `2` no\n * `api-extractor.json` at the target path, `3` the extractor exited\n * non-zero (compile error or extractor failure).\n */\nexport function renderExtractApiProcedure(): string {\n  return [\n    \"#!/usr/bin/env bash\",\n    \"# extract-api.sh — Run @microsoft/api-extractor for a single package.\",\n    \"#\",\n    \"# Usage:\",\n    \"#   .claude/procedures/extract-api.sh <package-dir>\",\n    \"#\",\n    \"# Where `<package-dir>` is a path (relative to the repo root, or\",\n    \"# absolute) to a sub-project that carries an `api-extractor.json`\",\n    \"# file generated by the configulator `ApiExtractor` component.\",\n    \"#\",\n    \"# Runs the extractor end-to-end and writes the `.api.md` rollup to\",\n    \"# the scratch folder declared by the package's `api-extractor.json`\",\n    \"# (default: `<package-dir>/.api-extractor/`). Rollups are\",\n    \"# **regenerated on scan** rather than committed to git per the\",\n    \"# docs-sync epic resolved decision #3 — the scan phase consumes the\",\n    \"# freshly-regenerated rollup in-memory.\",\n    \"#\",\n    \"# Exit codes:\",\n    \"#   0  — extraction succeeded; rollup written to the scratch folder.\",\n    \"#   1  — usage error (missing / unreadable package dir).\",\n    \"#   2  — the package has no `api-extractor.json` config.\",\n    \"#   3  — the extractor exited non-zero (compile error, missing entry\",\n    \"#        point, extractor-internal failure).\",\n    \"#\",\n    \"# Dependencies: expects `pnpm` on PATH and the target package's\",\n    \"# `node_modules` to carry `@microsoft/api-extractor` (added as a\",\n    \"# devDep by configulator's TypeScriptProject class).\",\n    \"\",\n    \"set -uo pipefail\",\n    \"\",\n    \"err() {\",\n    '  printf \"extract-api.sh: %s\\\\n\" \"$*\" >&2',\n    \"}\",\n    \"\",\n    'if [ \"$#\" -lt 1 ]; then',\n    '  err \"usage: extract-api.sh <package-dir>\"',\n    \"  exit 1\",\n    \"fi\",\n    \"\",\n    'pkg_dir=\"$1\"',\n    \"\",\n    'if [ ! -d \"$pkg_dir\" ]; then',\n    '  err \"package directory not found: $pkg_dir\"',\n    \"  exit 1\",\n    \"fi\",\n    \"\",\n    'config_file=\"$pkg_dir/api-extractor.json\"',\n    'if [ ! -f \"$config_file\" ]; then',\n    '  err \"no api-extractor.json found at $config_file\"',\n    \"  err \\\"ensure the package is a TypeScriptProject with ApiExtractor enabled and re-run 'pnpm exec projen'.\\\"\",\n    \"  exit 2\",\n    \"fi\",\n    \"\",\n    \"# Resolve the binary. Prefer the target package's local binary so\",\n    \"# the extractor version matches what configulator pinned for this\",\n    \"# package. Fall back to a workspace-aware `pnpm exec` lookup when\",\n    \"# the package hasn't installed its own copy yet. The local-bin\",\n    \"# path is resolved relative to the package root so the lookup\",\n    \"# still works after we `cd` into it.\",\n    'local_bin=\"./node_modules/.bin/api-extractor\"',\n    'if [ -x \"$pkg_dir/node_modules/.bin/api-extractor\" ]; then',\n    '  bin_cmd=(\"$local_bin\")',\n    \"else\",\n    '  bin_cmd=(pnpm --filter \"$(node -p \"require(\\'$pkg_dir/package.json\\').name\")\" exec api-extractor)',\n    \"fi\",\n    \"\",\n    \"# `--local` tells the extractor to regenerate the report in place\",\n    \"# rather than treating a missing file as a baseline-diff violation.\",\n    \"# The scan phase captures its own baseline in-memory — the file on\",\n    \"# disk is just the currently-extracted rollup.\",\n    \"#\",\n    \"# `@microsoft/api-extractor` does not create the report folder\",\n    \"# itself; ensure it exists so the first run after a fresh clone\",\n    \"# does not fail on a missing scratch directory.\",\n    \"(\",\n    '  cd \"$pkg_dir\" && mkdir -p .api-extractor && \"${bin_cmd[@]}\" run --local --config api-extractor.json',\n    \")\",\n    \"status=$?\",\n    \"\",\n    'if [ \"$status\" -ne 0 ]; then',\n    '  err \"api-extractor exited with status $status for $pkg_dir\"',\n    \"  exit 3\",\n    \"fi\",\n    \"\",\n    \"# Surface the path to the produced rollup so callers can read it\",\n    \"# without hard-coding the scratch folder layout. The extractor\",\n    \"# writes `<unscopedPackageName>.api.md` into the folder declared\",\n    \"# by `apiReport.reportFolder` in `api-extractor.json` — matches\",\n    \"# the default the configulator ApiExtractor component ships.\",\n    'report_dir=\"$pkg_dir/.api-extractor\"',\n    'if [ -d \"$report_dir\" ]; then',\n    '  find \"$report_dir\" -maxdepth 2 -type f -name \"*.api.md\" -print || true',\n    \"fi\",\n    \"\",\n    \"exit 0\",\n  ].join(\"\\n\");\n}\n\n/**\n * `AgentProcedure` definition for `.claude/procedures/extract-api.sh`.\n * Registered on the docs-sync bundle so it ships when the bundle is\n * force-included — matches the packaging of other bundled procedures\n * (see `orchestratorBundle.procedures`).\n */\nexport const extractApiProcedure: AgentProcedure = {\n  name: \"extract-api.sh\",\n  description:\n    \"Run @microsoft/api-extractor for a single package and write the .api.md rollup to the scratch folder declared by the package's api-extractor.json. Rollups are regenerate-on-scan per docs-sync epic #448 resolved decision #3 — never committed to git.\",\n  content: renderExtractApiProcedure(),\n};\n\n/**\n * Render the shell body of the `.claude/procedures/check-links.sh`\n * helper. Exported so the docs-sync bundle can register it as an\n * `AgentProcedure` and the bundles test suite can assert on the\n * script's contents.\n *\n * The helper wraps two external tools — `astro check` (internal\n * links) and `lychee` (external `https://…` URLs) — and normalizes\n * their per-finding output into a single JSON-array stream of\n * `{ url, docPath, line, kind, reason }` records on stdout. The\n * downstream docs-sync scan phase (#519/#520) consumes that stream\n * and decides which findings are advisory and which block the PR.\n *\n * Detection is **data**, not failure: the helper exits `0` whenever\n * a tool ran successfully, regardless of how many broken links it\n * reported. Non-zero exits are reserved for tool-level failures\n * (missing binary, config error, IO failure).\n *\n * Exit codes: `0` success, `1` usage error or unreadable docs\n * root, `2` a required external tool is missing, `3` a tool ran\n * but exited non-zero for a reason other than broken-link\n * detection.\n */\nexport function renderCheckLinksProcedure(): string {\n  return [\n    \"#!/usr/bin/env bash\",\n    \"# check-links.sh — Link integrity checker for the Starlight docs site.\",\n    \"#\",\n    \"# Usage:\",\n    \"#   .claude/procedures/check-links.sh <mode> <docs-root> [<site-dir>]\",\n    \"#\",\n    \"# Where:\",\n    \"#   <mode>      — one of `internal`, `external`, or `all`.\",\n    \"#   <docs-root> — path to the markdown content tree\",\n    \"#                 (e.g. `docs/src/content/docs`). Walked recursively\",\n    \"#                 for `*.md` / `*.mdx` files.\",\n    \"#   <site-dir>  — (optional, internal/all only) path to the Starlight\",\n    \"#                 project root that contains `astro.config.{ts,mjs,js}`.\",\n    \"#                 Defaults to two levels up from `<docs-root>` so the\",\n    \"#                 standard Starlight layout (`<site>/src/content/docs`)\",\n    \"#                 resolves automatically.\",\n    \"#\",\n    \"# Wraps two external tools:\",\n    \"#   - `astro check`  — internal links and content-collection refs\",\n    \"#                      inside the Starlight site.\",\n    \"#   - `lychee`       — external `https://…` URLs across the docs tree\",\n    \"#                      (https://github.com/lycheeverse/lychee).\",\n    \"#\",\n    \"# Output (stdout, single JSON array):\",\n    \"#\",\n    \"#   [\",\n    \"#     {\",\n    '#       \"url\":     \"<href as written in the markdown source>\",',\n    '#       \"docPath\": \"<path relative to <docs-root>>\",',\n    '#       \"line\":    <1-indexed line number>,',\n    '#       \"kind\":    \"internal\" | \"external\",',\n    '#       \"reason\":  \"<short tool-supplied diagnostic>\"',\n    \"#     },\",\n    \"#     ...\",\n    \"#   ]\",\n    \"#\",\n    \"# An empty array (`[]`) is emitted when no broken links are found.\",\n    \"# Detection is **data**, not failure: this helper exits 0 when a\",\n    \"# tool ran successfully and reported zero or more broken links.\",\n    \"# The downstream docs-sync scan phase (#519/#520) is responsible\",\n    \"# for deciding which findings are advisory and which block.\",\n    \"#\",\n    \"# Exit codes:\",\n    \"#   0  — every requested tool ran successfully; findings (zero or\",\n    \"#        more) are on stdout as a JSON array.\",\n    \"#   1  — usage error (missing args, unreadable docs root).\",\n    \"#   2  — a required external tool is not installed or not on PATH\",\n    \"#        (`astro` / `lychee` / `node` / `jq`).\",\n    \"#   3  — a tool ran but exited non-zero for a reason other than\",\n    \"#        broken-link detection (config error, IO error, network\",\n    \"#        failure for lychee, etc.). Stderr carries the diagnostic.\",\n    \"#\",\n    \"# The script never edits files. Diagnostics flow to stderr; the\",\n    \"# only thing on stdout is the normalized JSON array.\",\n    \"\",\n    \"set -uo pipefail\",\n    \"\",\n    \"err() {\",\n    '  printf \"check-links.sh: %s\\\\n\" \"$*\" >&2',\n    \"}\",\n    \"\",\n    'if [ \"$#\" -lt 2 ]; then',\n    '  err \"usage: check-links.sh <internal|external|all> <docs-root> [<site-dir>]\"',\n    \"  exit 1\",\n    \"fi\",\n    \"\",\n    'mode=\"$1\"',\n    'docs_root=\"$2\"',\n    'site_dir=\"${3:-}\"',\n    \"\",\n    'case \"$mode\" in',\n    \"  internal | external | all) ;;\",\n    \"  *)\",\n    \"    err \\\"unknown mode '$mode' — expected 'internal', 'external', or 'all'\\\"\",\n    \"    exit 1\",\n    \"    ;;\",\n    \"esac\",\n    \"\",\n    'if [ ! -d \"$docs_root\" ]; then',\n    '  err \"docs root not found: $docs_root\"',\n    \"  exit 1\",\n    \"fi\",\n    \"\",\n    'if [ -z \"$site_dir\" ]; then',\n    \"  # Standard Starlight layout: <site>/src/content/docs. Walk two\",\n    \"  # parents up from the content root to recover the site dir.\",\n    '  site_dir=\"$(cd \"$docs_root/../../..\" && pwd)\"',\n    \"fi\",\n    \"\",\n    \"# `jq` is required to merge the per-tool JSON output streams. Fail\",\n    \"# fast with the dedicated tool-missing exit code if it is absent.\",\n    \"if ! command -v jq >/dev/null 2>&1; then\",\n    '  err \"jq is required but not on PATH\"',\n    \"  exit 2\",\n    \"fi\",\n    \"\",\n    'tmp_dir=\"$(mktemp -d -t check-links-XXXXXX)\"',\n    \"# shellcheck disable=SC2064\",\n    \"trap \\\"rm -rf '$tmp_dir'\\\" EXIT\",\n    \"\",\n    'internal_json=\"$tmp_dir/internal.json\"',\n    'external_json=\"$tmp_dir/external.json\"',\n    'printf \"[]\" > \"$internal_json\"',\n    'printf \"[]\" > \"$external_json\"',\n    \"\",\n    \"# ---------------------------------------------------------------\",\n    \"# Internal-link check\",\n    \"# ---------------------------------------------------------------\",\n    \"# `astro check` runs inside the Starlight project root and walks\",\n    \"# content collections to validate internal references. It exits\",\n    \"# non-zero when references are broken — that is a *finding* for\",\n    \"# this helper, not a tool failure, so we capture stderr and parse\",\n    \"# it into the normalized record shape rather than propagating the\",\n    \"# non-zero exit.\",\n    'if [ \"$mode\" = \"internal\" ] || [ \"$mode\" = \"all\" ]; then',\n    \"  if ! command -v node >/dev/null 2>&1; then\",\n    '    err \"node is required but not on PATH\"',\n    \"    exit 2\",\n    \"  fi\",\n    \"\",\n    '  if [ ! -d \"$site_dir\" ]; then',\n    '    err \"site dir not found: $site_dir\"',\n    \"    exit 1\",\n    \"  fi\",\n    \"\",\n    \"  # Locate the astro binary in the site's local node_modules first\",\n    \"  # so the version matches what `pnpm install` resolved for the\",\n    \"  # Starlight site. Fall back to a workspace-aware `pnpm exec`.\",\n    '  if [ -x \"$site_dir/node_modules/.bin/astro\" ]; then',\n    '    astro_bin=(\"$site_dir/node_modules/.bin/astro\")',\n    \"  elif command -v pnpm >/dev/null 2>&1; then\",\n    '    astro_bin=(pnpm --dir \"$site_dir\" exec astro)',\n    \"  else\",\n    '    err \"astro binary not found in $site_dir/node_modules/.bin and pnpm is unavailable\"',\n    \"    exit 2\",\n    \"  fi\",\n    \"\",\n    '  astro_log=\"$tmp_dir/astro.log\"',\n    \"  set +e\",\n    '  ( cd \"$site_dir\" && \"${astro_bin[@]}\" check ) > \"$astro_log\" 2>&1',\n    \"  astro_status=$?\",\n    \"  set -e\",\n    \"\",\n    \"  # `astro check` exits 1 on findings and >=2 on tool failure.\",\n    \"  # Translate to the normalized record stream regardless of exit.\",\n    '  if [ \"$astro_status\" -ge 2 ]; then',\n    '    err \"astro check exited with status $astro_status (tool failure)\"',\n    '    cat \"$astro_log\" >&2 || true',\n    \"    exit 3\",\n    \"  fi\",\n    \"\",\n    \"  # Parse the line-oriented log into JSON records. The `astro\",\n    \"  # check` output for a broken reference looks like:\",\n    \"  #\",\n    \"  #   src/content/docs/foo.md:42:8 - error <code>: <reason>\",\n    \"  #\",\n    \"  # The helper extracts `<docPath>`, `<line>`, and `<reason>` and\",\n    \"  # synthesises a `url` field by quoting the offending excerpt\",\n    \"  # when astro reports one (it does not always); when no excerpt\",\n    \"  # is available we fall back to an empty string so the schema\",\n    \"  # stays uniform.\",\n    '  awk -v docs_root=\"$docs_root\" -v site_dir=\"$site_dir\" \\'',\n    \"    BEGIN {\",\n    '      printf \"[\";',\n    \"      first = 1;\",\n    \"    }\",\n    '    # Match \"<path>:<line>:<col> - <severity> <code>: <message>\"',\n    \"    /^.+:[0-9]+:[0-9]+ - / {\",\n    '      split($0, head, \" - \");',\n    '      n = split(head[1], loc, \":\");',\n    \"      file = loc[1];\",\n    '      for (i = 2; i < n - 1; i++) { file = file \":\" loc[i]; }',\n    \"      line = loc[n - 1];\",\n    '      message = \"\";',\n    \"      for (i = 2; i <= length(head); i++) {\",\n    '        if (i > 2) message = message \" - \";',\n    \"        message = message head[i];\",\n    \"      }\",\n    \"      # Resolve the file relative to docs_root for stability.\",\n    \"      abs = file;\",\n    '      if (substr(abs, 1, 1) != \"/\") {',\n    '        abs = site_dir \"/\" abs;',\n    \"      }\",\n    '      sub(docs_root \"/\", \"\", abs);',\n    '      gsub(/\"/, \"\\\\\\\\\\\\\"\", message);',\n    '      gsub(/\"/, \"\\\\\\\\\\\\\"\", abs);',\n    '      if (!first) printf \",\";',\n    \"      first = 0;\",\n    '      printf \"{\\\\\"url\\\\\":\\\\\"\\\\\",\\\\\"docPath\\\\\":\\\\\"%s\\\\\",\\\\\"line\\\\\":%s,\\\\\"kind\\\\\":\\\\\"internal\\\\\",\\\\\"reason\\\\\":\\\\\"%s\\\\\"}\", abs, line, message;',\n    \"    }\",\n    \"    END {\",\n    '      printf \"]\";',\n    \"    }\",\n    '  \\' \"$astro_log\" > \"$internal_json\"',\n    \"\",\n    \"  # Validate the JSON we synthesised. Catches awk escaping bugs\",\n    \"  # before we hand the payload to the merge step.\",\n    '  if ! jq -e . \"$internal_json\" >/dev/null 2>&1; then',\n    '    err \"failed to normalize astro check output to JSON\"',\n    '    cat \"$internal_json\" >&2 || true',\n    \"    exit 3\",\n    \"  fi\",\n    \"fi\",\n    \"\",\n    \"# ---------------------------------------------------------------\",\n    \"# External-link check\",\n    \"# ---------------------------------------------------------------\",\n    \"# `lychee` walks the markdown tree and reports unreachable URLs.\",\n    \"# Its `--format json` output is structured per-link; we project\",\n    \"# only the failed entries into the normalized record shape.\",\n    'if [ \"$mode\" = \"external\" ] || [ \"$mode\" = \"all\" ]; then',\n    \"  if ! command -v lychee >/dev/null 2>&1; then\",\n    '    err \"lychee is required but not on PATH (https://github.com/lycheeverse/lychee)\"',\n    \"    exit 2\",\n    \"  fi\",\n    \"\",\n    '  lychee_json=\"$tmp_dir/lychee.json\"',\n    \"  set +e\",\n    \"  # `--no-progress` avoids interactive carriage-returns mangling\",\n    \"  # the JSON. `--format json` emits a single object whose `fail_map`\",\n    \"  # field lists the broken URLs grouped by source file.\",\n    \"  # `--exclude-mail` skips mailto: links (out of scope for this\",\n    \"  # helper).\",\n    '  lychee --no-progress --format json --exclude-mail \"$docs_root\" > \"$lychee_json\" 2>\"$tmp_dir/lychee.err\"',\n    \"  lychee_status=$?\",\n    \"  set -e\",\n    \"\",\n    \"  # lychee exits 0 when every link resolved, 2 when one or more\",\n    \"  # links failed. Anything else is a tool failure (config, IO).\",\n    '  if [ \"$lychee_status\" -ne 0 ] && [ \"$lychee_status\" -ne 2 ]; then',\n    '    err \"lychee exited with status $lychee_status (tool failure)\"',\n    '    cat \"$tmp_dir/lychee.err\" >&2 || true',\n    \"    exit 3\",\n    \"  fi\",\n    \"\",\n    \"  # Project lychee's `fail_map` into the normalized record shape.\",\n    '  # The `fail_map` is `{ \"<source-path>\": [ { url, status: { details? } }, ... ] }`.',\n    \"  # lychee does not report a line number for every match, so we\",\n    \"  # default to 0 when it is missing (downstream consumers treat\",\n    '  # 0 as \"unknown line\").',\n    '  jq --arg root \"$docs_root\" \\'',\n    \"    def trim_root($p; $r):\",\n    '      if ($p | startswith($r + \"/\")) then ($p | ltrimstr($r + \"/\"))',\n    '      elif ($p == $r) then \"\"',\n    \"      else $p end;\",\n    \"    [\",\n    \"      ( .fail_map // {} ) as $map\",\n    \"      | $map | to_entries[]\",\n    \"      | .key as $src\",\n    \"      | .value[]\",\n    \"      | {\",\n    '          url: (.url // \"\"),',\n    \"          docPath: trim_root($src; $root),\",\n    \"          line: ((.line // 0) | tonumber? // 0),\",\n    '          kind: \"external\",',\n    '          reason: ( (.status.details // .status.text // .status.code // \"broken\") | tostring )',\n    \"        }\",\n    \"    ]\",\n    '  \\' \"$lychee_json\" > \"$external_json\" 2>\"$tmp_dir/lychee.parse.err\"',\n    \"\",\n    '  if ! jq -e . \"$external_json\" >/dev/null 2>&1; then',\n    '    err \"failed to parse lychee JSON output\"',\n    '    cat \"$tmp_dir/lychee.parse.err\" >&2 || true',\n    '    cat \"$lychee_json\" >&2 || true',\n    \"    exit 3\",\n    \"  fi\",\n    \"fi\",\n    \"\",\n    \"# ---------------------------------------------------------------\",\n    \"# Merge & emit\",\n    \"# ---------------------------------------------------------------\",\n    \"# Sort records deterministically (kind, docPath, line, url) so\",\n    \"# downstream consumers can compare reports across runs without\",\n    \"# fighting platform-specific ordering noise.\",\n    \"jq -s '\",\n    \"  add\",\n    \"  | sort_by(.kind, .docPath, .line, .url)\",\n    '\\' \"$internal_json\" \"$external_json\"',\n    \"\",\n    \"exit 0\",\n  ].join(\"\\n\");\n}\n\n/**\n * `AgentProcedure` definition for `.claude/procedures/check-links.sh`.\n * Registered on the docs-sync bundle so it ships when the bundle is\n * force-included — matches the packaging of `extractApiProcedure`\n * above. Provides the link-integrity input the docs-sync scan phase\n * (#519/#520) consumes alongside API-extractor and TSDoc-coverage\n * findings.\n */\nexport const checkLinksProcedure: AgentProcedure = {\n  name: \"check-links.sh\",\n  description:\n    \"Link integrity checker that wraps `astro check` (internal links) and `lychee` (external URLs) and normalizes their output into a single JSON-array stream of { url, docPath, line, kind, reason } records. Detection is data: the helper exits 0 when a tool ran successfully regardless of how many broken links it reported. Non-zero exits are reserved for tool-level failures.\",\n  content: renderCheckLinksProcedure(),\n};\n\n/**\n * Render the shell body of the\n * `.claude/procedures/strip-tool-artifact-tags.sh` helper. Exported so\n * the docs-sync bundle can register it as an `AgentProcedure` and the\n * bundles test suite can assert on the script's contents.\n *\n * Authoring agents intermittently leak tool-call wrapper *closing*\n * tags (`</content>`, `</invoke>`, occasionally `</parameter>`) as\n * trailing whole lines in the markdown they write. `astro check` and\n * CI link checks do not catch them. This helper strips those leaked\n * EOF artifact lines on write so they never reach the committed tree.\n *\n * Behaviour, mirroring `check-links.sh`'s defensive guards:\n *\n *   - Takes a single file-path argument.\n *   - Operates only when the file exists and its path is under\n *     `docs/src/content/docs/`. Any other path (or a missing file) is\n *     a silent no-op.\n *   - Removes **trailing whole lines** that are exactly `</content>`,\n *     `</invoke>`, or `</parameter>` (trailing whitespace on the line\n *     is tolerated), plus any blank lines that become trailing once\n *     the tags are removed, then leaves a single final newline.\n *   - Only whole-line EOF tags are stripped — legitimate inline\n *     `<...>` prose or fenced code is never touched.\n *   - Idempotent: a second run on an already-clean file changes\n *     nothing.\n *   - Never edits a file it did not need to change, and **always**\n *     exits 0 so a PostToolUse hook can never fail the tool call.\n *\n * Exit code: always `0`. Diagnostics (if any) flow to stderr.\n */\nexport function renderStripToolArtifactTagsProcedure(): string {\n  return [\n    \"#!/usr/bin/env bash\",\n    \"# strip-tool-artifact-tags.sh — remove leaked tool-call wrapper\",\n    \"# closing tags from the end of an authored markdown file.\",\n    \"#\",\n    \"# Usage:\",\n    \"#   .claude/procedures/strip-tool-artifact-tags.sh <file-path>\",\n    \"#\",\n    \"# Authoring agents occasionally leak tool-call wrapper *closing*\",\n    \"# tags (</content>, </invoke>, </parameter>) as trailing whole\",\n    \"# lines in the markdown they write. astro check and CI link checks\",\n    \"# do not catch them. This helper strips those EOF artifact lines\",\n    \"# (plus any now-trailing blank lines) and rewrites the file with a\",\n    \"# single final newline.\",\n    \"#\",\n    \"# Guards (mirrors check-links.sh):\",\n    \"#   - Operates only on an existing file whose path is under\",\n    \"#     docs/src/content/docs/. Any other path, or a missing file,\",\n    \"#     is a silent no-op.\",\n    \"#   - Only WHOLE-LINE EOF tags are removed; inline `<...>` prose or\",\n    \"#     fenced code is never touched.\",\n    \"#   - Idempotent: a re-run on a clean file changes nothing.\",\n    \"#   - Never fails the tool call — always exits 0. Diagnostics go to\",\n    \"#     stderr only; the file is rewritten only when it changes.\",\n    \"\",\n    \"set -uo pipefail\",\n    \"\",\n    \"err() {\",\n    '  printf \"strip-tool-artifact-tags.sh: %s\\\\n\" \"$*\" >&2',\n    \"}\",\n    \"\",\n    \"# No file argument: nothing to do.\",\n    'if [ \"$#\" -lt 1 ]; then',\n    \"  exit 0\",\n    \"fi\",\n    \"\",\n    'file=\"$1\"',\n    \"\",\n    \"# No-op unless the file actually exists and is a regular file.\",\n    'if [ ! -f \"$file\" ]; then',\n    \"  exit 0\",\n    \"fi\",\n    \"\",\n    \"# Path guard: only touch markdown under the Starlight content tree.\",\n    \"# Match the canonical content-root segment anywhere in the path so\",\n    \"# the guard works for both absolute and repo-relative paths.\",\n    'case \"$file\" in',\n    \"  *docs/src/content/docs/*) ;;\",\n    \"  *) exit 0 ;;\",\n    \"esac\",\n    \"\",\n    \"# Rewrite the file with trailing artifact tags and trailing blank\",\n    \"# lines removed. awk buffers every line, then walks back from EOF\",\n    \"# dropping lines that are blank or exactly one of the leaked\",\n    \"# closing tags (trailing whitespace tolerated). Whatever survives\",\n    \"# is re-emitted with a single final newline. Only whole lines are\",\n    \"# considered, so inline `<...>` content is never altered.\",\n    'tmp_out=\"$(mktemp -t strip-tool-artifact-tags-XXXXXX)\" || exit 0',\n    \"# shellcheck disable=SC2064\",\n    \"trap \\\"rm -f '$tmp_out'\\\" EXIT\",\n    \"\",\n    \"awk '\",\n    \"  { lines[NR] = $0 }\",\n    \"  END {\",\n    \"    last = NR\",\n    \"    while (last > 0) {\",\n    \"      line = lines[last]\",\n    \"      # Strip trailing whitespace (spaces, tabs, CR) for the match.\",\n    \"      stripped = line\",\n    '      sub(/[ \\\\t\\\\r]+$/, \"\", stripped)',\n    '      if (stripped == \"\" \\\\',\n    '          || stripped == \"</content>\" \\\\',\n    '          || stripped == \"</invoke>\" \\\\',\n    '          || stripped == \"</parameter>\") {',\n    \"        last--\",\n    \"        continue\",\n    \"      }\",\n    \"      break\",\n    \"    }\",\n    \"    for (i = 1; i <= last; i++) {\",\n    \"      print lines[i]\",\n    \"    }\",\n    \"  }\",\n    '\\' \"$file\" > \"$tmp_out\" || exit 0',\n    \"\",\n    \"# Only write back when the content actually changed — keeps the\",\n    \"# helper a true no-op on clean files (idempotent re-runs included).\",\n    'if ! cmp -s \"$tmp_out\" \"$file\"; then',\n    '  if ! cat \"$tmp_out\" > \"$file\"; then',\n    '    err \"failed to rewrite $file\"',\n    \"  fi\",\n    \"fi\",\n    \"\",\n    \"exit 0\",\n  ].join(\"\\n\");\n}\n\n/**\n * `AgentProcedure` definition for\n * `.claude/procedures/strip-tool-artifact-tags.sh`. Registered on the\n * docs-sync bundle so it ships alongside `check-links.sh` when the\n * bundle is force-included, and chained into the base PostToolUse\n * Edit|Write hook so authored markdown is cleaned of leaked tool-call\n * artifact tags on write (#779).\n */\nexport const stripToolArtifactTagsProcedure: AgentProcedure = {\n  name: \"strip-tool-artifact-tags.sh\",\n  description:\n    \"Strips leaked tool-call wrapper closing tags (</content>, </invoke>, </parameter>) that authoring agents occasionally emit as trailing whole lines in markdown, plus any now-trailing blank lines, leaving a single final newline. Operates only on an existing file under docs/src/content/docs/; idempotent, a no-op on clean or missing files, and always exits 0 so it can never fail a PostToolUse hook.\",\n  content: renderStripToolArtifactTagsProcedure(),\n};\n\n/**\n * Render the shell body of the\n * `.claude/procedures/check-doc-samples.sh` helper. Exported so the\n * docs-sync bundle can register it as an `AgentProcedure` and the\n * bundles test suite can assert on the script's contents.\n *\n * The helper wraps the `compileFencedSamples` API exported from\n * `@codedrifters/configulator` (under `src/docs-sync/sample-compilation/`)\n * and emits a single JSON-array stream of failure records on stdout.\n * Detection is **data**, not failure: the helper exits `0` when the\n * compilation phase ran successfully, regardless of how many samples\n * failed to compile. Non-zero exits are reserved for tool-level\n * failures (missing binary, IO error, internal exception).\n *\n * Exit codes: `0` success, `1` usage error or unreadable docs root,\n * `2` a required binary is missing (`node` / `pnpm`), `3` the\n * compilation phase threw an unhandled exception.\n */\nexport function renderCheckDocSamplesProcedure(): string {\n  // Inline Node script that imports `compileFencedSamples` from the\n  // workspace `@codedrifters/configulator` package and prints the\n  // failure array as JSON. Kept terse so the embedded heredoc stays\n  // readable inside the bash render.\n  const nodeScript = [\n    \"(async () => {\",\n    \"  const { compileFencedSamples } = await import('@codedrifters/configulator');\",\n    \"  const docsRoot = process.argv[1];\",\n    \"  const failures = compileFencedSamples({ docsRoot });\",\n    \"  process.stdout.write(JSON.stringify(failures));\",\n    \"})().catch((err) => {\",\n    \"  console.error('check-doc-samples.sh: ' + (err && err.stack ? err.stack : err));\",\n    \"  process.exit(3);\",\n    \"});\",\n  ].join(\"\\n\");\n  return [\n    \"#!/usr/bin/env bash\",\n    \"# check-doc-samples.sh — Compile fenced TS/TSX samples in the Starlight docs.\",\n    \"#\",\n    \"# Usage:\",\n    \"#   .claude/procedures/check-doc-samples.sh <docs-root>\",\n    \"#\",\n    \"# Where:\",\n    \"#   <docs-root> — path to the markdown content tree\",\n    \"#                 (e.g. `docs/src/content/docs`). Walked recursively\",\n    \"#                 for `*.md` files.\",\n    \"#\",\n    \"# Wraps the `compileFencedSamples` API exported from\",\n    \"# `@codedrifters/configulator`. For every fenced ` ```ts `,\",\n    \"# ` ```typescript `, ` ```tsx `, or ` ```typescriptreact ` block in\",\n    \"# the docs, the helper writes the sample to an in-memory file,\",\n    \"# runs the TypeScript compiler against it (in-process, via the TS\",\n    \"# compiler API), and reports any compilation diagnostics.\",\n    \"#\",\n    \"# Skipped samples (fence meta `skip` / `no-check`, or first line\",\n    \"# `// @no-check`) are passed through unchecked.\",\n    \"#\",\n    \"# Output (stdout, single JSON array):\",\n    \"#\",\n    \"#   [\",\n    \"#     {\",\n    '#       \"docPath\":     \"<path relative to <docs-root>>\",',\n    '#       \"line\":        <1-indexed line number of the opening fence>,',\n    '#       \"fenceIndex\":  <0-indexed fenced-block position within the doc>,',\n    '#       \"lang\":        \"ts\" | \"typescript\" | \"tsx\" | \"typescriptreact\",',\n    '#       \"diagnostics\": [ \"<TS<code>: <message>>\", ... ]',\n    \"#     },\",\n    \"#     ...\",\n    \"#   ]\",\n    \"#\",\n    \"# An empty array (`[]`) is emitted when every sample compiled.\",\n    \"# Detection is **data**, not failure: this helper exits 0 when the\",\n    \"# compilation phase ran successfully, regardless of how many\",\n    \"# samples failed to compile. The downstream docs-sync scan phase\",\n    \"# (#520) is responsible for treating failures as one of the two\",\n    \"# hard-block cases per the parent epic.\",\n    \"#\",\n    \"# Exit codes:\",\n    \"#   0  — compilation phase ran; failures (zero or more) are on\",\n    \"#        stdout as a JSON array.\",\n    \"#   1  — usage error (missing args, unreadable docs root).\",\n    \"#   2  — a required binary is not on PATH (`node` / `pnpm`).\",\n    \"#   3  — the compilation phase threw an unhandled exception.\",\n    \"#        Stderr carries the diagnostic.\",\n    \"#\",\n    \"# Dependencies: expects `node` and `pnpm` on PATH and the workspace\",\n    \"# `@codedrifters/configulator` package to be installed (the helper\",\n    \"# resolves the API through `pnpm exec node` from the repo root).\",\n    \"\",\n    \"set -uo pipefail\",\n    \"\",\n    \"err() {\",\n    '  printf \"check-doc-samples.sh: %s\\\\n\" \"$*\" >&2',\n    \"}\",\n    \"\",\n    'if [ \"$#\" -lt 1 ]; then',\n    '  err \"usage: check-doc-samples.sh <docs-root>\"',\n    \"  exit 1\",\n    \"fi\",\n    \"\",\n    'docs_root=\"$1\"',\n    \"\",\n    'if [ ! -d \"$docs_root\" ]; then',\n    '  err \"docs root not found: $docs_root\"',\n    \"  exit 1\",\n    \"fi\",\n    \"\",\n    \"if ! command -v node >/dev/null 2>&1; then\",\n    '  err \"node is required but not on PATH\"',\n    \"  exit 2\",\n    \"fi\",\n    \"\",\n    \"if ! command -v pnpm >/dev/null 2>&1; then\",\n    '  err \"pnpm is required but not on PATH\"',\n    \"  exit 2\",\n    \"fi\",\n    \"\",\n    \"# Resolve docs_root to an absolute path so the inline node script\",\n    \"# is independent of the cwd `pnpm exec` chooses.\",\n    'docs_root_abs=\"$(cd \"$docs_root\" && pwd)\"',\n    \"\",\n    \"# Run the inline node script through `pnpm exec` so module\",\n    \"# resolution finds `@codedrifters/configulator` via the workspace\",\n    \"# even when the helper is invoked from a sub-package directory.\",\n    \"# The `--input-type=module` flag lets us use top-level `await` and\",\n    \"# `import()` cleanly. Diagnostics from the script flow to stderr;\",\n    \"# stdout carries only the JSON array.\",\n    'pnpm exec node --input-type=module -e \"' +\n      nodeScript.replace(/\"/g, '\\\\\"') +\n      '\" \"$docs_root_abs\"',\n    \"status=$?\",\n    \"\",\n    'if [ \"$status\" -ne 0 ]; then',\n    '  err \"compileFencedSamples exited with status $status\"',\n    \"  exit 3\",\n    \"fi\",\n    \"\",\n    \"exit 0\",\n  ].join(\"\\n\");\n}\n\n/**\n * `AgentProcedure` definition for\n * `.claude/procedures/check-doc-samples.sh`. Registered on the\n * docs-sync bundle so it ships when the bundle is force-included —\n * matches the packaging of `extractApiProcedure` and\n * `checkLinksProcedure` above. Provides the fenced-sample\n * compilation input the docs-sync scan phase (#520) consumes\n * alongside link integrity, API-extractor, TSDoc-coverage, and\n * doc-reference findings. Per the parent epic, fenced TS samples\n * that fail to compile are one of the two hard-block cases.\n */\nexport const checkDocSamplesProcedure: AgentProcedure = {\n  name: \"check-doc-samples.sh\",\n  description:\n    \"Fenced-sample compilation checker that wraps the `compileFencedSamples` API and emits a JSON-array stream of { docPath, line, fenceIndex, lang, diagnostics } failure records. Skipped samples (meta `skip`/`no-check`, or first-line `// @no-check`) are passed through unchecked. Detection is data: the helper exits 0 whenever compilation ran successfully regardless of failure count.\",\n  content: renderCheckDocSamplesProcedure(),\n};\n\n/**\n * Docs-sync bundle — scaffolding release.\n *\n * Opt-in via `includeBundles: [\"docs-sync\"]`. `appliesWhen` returns\n * `false` by default so the scaffold ships disabled until a\n * downstream child issue enables it across the monorepo.\n *\n * Provides the skeleton of a 2-phase drift-detection + audit pipeline\n * (scan → fix) designed for monorepos that keep documentation inside\n * a Starlight singleton. Ships a sub-agent, two user-invocable skills\n * (`/docs-sync-pr`, `/docs-sync-audit`), five new labels\n * (`type:docs-sync`, `docs-sync:scan`, `docs-sync:fix`,\n * `docs-sync:advisory`, `docs-sync:blocking`), and a\n * `Documentation Sync Workflow` rule rendered into CLAUDE.md so\n * humans reading the file see the pipeline exists even while the\n * behavior is still landing across child issues.\n */\nexport function buildDocsSyncBundle(\n  paths: ResolvedAgentPaths = DEFAULT_AGENT_PATHS,\n): AgentRuleBundle {\n  return {\n    name: \"docs-sync\",\n    description:\n      \"Documentation-sync agent bundle (scaffolding). Two-phase pipeline (scan, fix) with `docs-sync:*` phase labels for detecting code-vs-docs drift introduced by a PR diff or surfaced by a full-repo audit. Ships the skeleton only — drift-detection, mechanical fixes, and audit scoring are carried by downstream child issues of the parent docs-sync epic. Opt-in via `includeBundles: ['docs-sync']`.\",\n    appliesWhen: () => false,\n    rules: [\n      {\n        name: \"docs-sync-workflow\",\n        description:\n          \"Describes the 2-phase docs-sync pipeline (scan, fix), the `docs-sync:*` label taxonomy, the mechanical-fix write boundary, and the advisory-vs-blocking routing.\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Documentation Sync Workflow\",\n          \"\",\n          \"Use `/docs-sync-pr <branch>` to run a pre-PR drift check, or\",\n          \"`/docs-sync-audit [<scope>]` to run a full-repo audit. The pipeline\",\n          \"runs in 2 phases — scan and fix — each tracked by its own GitHub\",\n          \"issue labeled `docs-sync:scan` or `docs-sync:fix`. All issues carry\",\n          \"`type:docs-sync`.\",\n          \"\",\n          \"Two additional labels classify drift disposition on a PR:\",\n          \"\",\n          \"- `docs-sync:advisory` — drift detected, not blocking the PR.\",\n          \"- `docs-sync:blocking` — drift blocks the PR; applied together\",\n          \"  with `review:human-required` so `pr-reviewer` owns the merge\",\n          \"  gate.\",\n          \"\",\n          \"The docs-sync agent *detects drift and applies mechanical*\",\n          \"*fixes*; it does **not** rewrite conceptual prose, ADRs,\",\n          \"requirement bodies, or BCM capability models. Those go to\",\n          \"`docs:write` follow-ups routed to the appropriate writer\",\n          \"bundle or to a human.\",\n          \"\",\n          \"**Scaffolding release.** This bundle ships the skeleton only.\",\n          \"Drift-detection, mechanical fixes, advisory/blocking routing,\",\n          \"and audit-mode scoring land across downstream child issues of\",\n          \"the parent docs-sync epic. Invoking the skills today produces\",\n          \"an explanatory no-op.\",\n          \"\",\n          \"See the `docs-sync` agent definition for the intended\",\n          \"two-phase contract and the write boundaries.\",\n        ].join(\"\\n\"),\n        platforms: {\n          cursor: { exclude: true },\n        },\n        tags: [\"workflow\"],\n      },\n    ],\n    skills: [buildDocsSyncPrSkill(), buildDocsSyncAuditSkill()],\n    subAgents: [buildDocsSyncSubAgent(paths)],\n    procedures: [\n      extractApiProcedure,\n      checkLinksProcedure,\n      checkDocSamplesProcedure,\n      stripToolArtifactTagsProcedure,\n    ],\n    labels: [\n      {\n        name: \"type:docs-sync\",\n        color: \"0E8A16\",\n        description:\n          \"Work that detects or repairs documentation drift against code (docs-sync pipeline)\",\n      },\n      {\n        name: \"docs-sync:scan\",\n        color: \"C5DEF5\",\n        description:\n          \"Phase 1: scan for drift (API diff, TSDoc coverage, references, links, sample compilation)\",\n      },\n      {\n        name: \"docs-sync:fix\",\n        color: \"BFDADC\",\n        description:\n          \"Phase 2: apply mechanical fixes and file docs:write follow-ups for conceptual changes\",\n      },\n      {\n        name: \"docs-sync:advisory\",\n        color: \"FBCA04\",\n        description:\n          \"Drift detected by docs-sync but does not block the PR; surfaced as a sticky-comment note\",\n      },\n      {\n        name: \"docs-sync:blocking\",\n        color: \"B60205\",\n        description:\n          \"Drift blocks the PR; applied with review:human-required so pr-reviewer owns the merge gate\",\n      },\n    ],\n  };\n}\n\n/**\n * Default-paths instance of the docs-sync bundle, preserved for\n * parity with other path-aware bundles in this directory. The factory\n * above is the canonical entry point when a consumer supplies\n * `AgentConfigOptions.paths`.\n */\nexport const docsSyncBundle: AgentRuleBundle = buildDocsSyncBundle();\n","import { GitHub } from \"projen/lib/github\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE, AgentProcedure, AgentSkill } from \"../types\";\nimport { DEFAULT_BUILD_POLICY, ResolvedBuildPolicy } from \"./build-policy\";\nimport { checkClosingKeywordsProcedure } from \"./closing-keywords\";\nimport { renderTitlePrefixTypeBullets } from \"./issue-type\";\nimport { hasComponent } from \"./utils\";\n\n/*******************************************************************************\n *\n * set-issue-type.sh — Assign a GitHub issue type in one step.\n *\n * Wraps the two-step GraphQL flow (lookup repo issue types, then call\n * updateIssueIssueType) so callers do not have to hand-write the inline\n * queries every time an issue is created.\n *\n ******************************************************************************/\n\nconst setIssueTypeProcedure: AgentProcedure = {\n  name: \"set-issue-type.sh\",\n  description:\n    \"Assign a GitHub issue type (Feature / Task / Epic / Bug / etc.) via the updateIssueIssueType GraphQL mutation in a single step\",\n  content: [\n    \"#!/usr/bin/env bash\",\n    \"# set-issue-type.sh — Assign a GitHub issue type in one step.\",\n    \"#\",\n    \"# Wraps the two-step GraphQL flow used to set an issue's type:\",\n    \"#   1. Look up the repo's issue type node IDs.\",\n    \"#   2. Call the updateIssueIssueType mutation.\",\n    \"#\",\n    \"# Usage:\",\n    \"#   .claude/procedures/set-issue-type.sh <issue-number> <type-name>\",\n    \"#\",\n    \"# Where <type-name> is the human-readable GitHub issue type name\",\n    \"# (e.g. Feature, Task, Epic, Bug). Matching is case-insensitive.\",\n    \"#\",\n    \"# Exits 0 on success. Exits non-zero with a clear diagnostic on stderr\",\n    \"# for any validation error or API failure.\",\n    \"\",\n    \"set -uo pipefail\",\n    \"\",\n    \"# ── helpers ──────────────────────────────────────────────────────────\",\n    \"\",\n    \"err() {\",\n    '  printf \"set-issue-type.sh: %s\\\\n\" \"$*\" >&2',\n    \"}\",\n    \"\",\n    \"usage() {\",\n    \"  cat >&2 <<'USAGE'\",\n    \"Usage: set-issue-type.sh <issue-number> <type-name>\",\n    \"\",\n    \"  <issue-number>  Positive integer GitHub issue number.\",\n    \"  <type-name>     Human-readable issue type (Feature, Task, Epic, Bug,\",\n    \"                  or any type defined at the org level). Case-insensitive.\",\n    \"\",\n    \"Examples:\",\n    \"  set-issue-type.sh 123 Feature\",\n    \"  set-issue-type.sh 456 bug\",\n    \"USAGE\",\n    \"}\",\n    \"\",\n    \"# ── argument validation ──────────────────────────────────────────────\",\n    \"\",\n    \"if [[ $# -ne 2 ]]; then\",\n    '  err \"expected 2 arguments, got $#\"',\n    \"  usage\",\n    \"  exit 2\",\n    \"fi\",\n    \"\",\n    'issue_number=\"$1\"',\n    'type_name=\"$2\"',\n    \"\",\n    'if ! [[ \"$issue_number\" =~ ^[1-9][0-9]*$ ]]; then',\n    \"  err \\\"issue number must be a positive integer (got: '$issue_number')\\\"\",\n    \"  exit 2\",\n    \"fi\",\n    \"\",\n    'if [[ -z \"${type_name// /}\" ]]; then',\n    '  err \"type name must be non-empty\"',\n    \"  exit 2\",\n    \"fi\",\n    \"\",\n    \"# ── dependency checks ────────────────────────────────────────────────\",\n    \"\",\n    \"for cmd in gh jq; do\",\n    '  if ! command -v \"$cmd\" >/dev/null 2>&1; then',\n    '    err \"required command not found on PATH: $cmd\"',\n    \"    exit 3\",\n    \"  fi\",\n    \"done\",\n    \"\",\n    \"# ── resolve repo owner/name ──────────────────────────────────────────\",\n    \"\",\n    \"repo_json=$(gh repo view --json owner,name 2>/dev/null)\",\n    'if [[ -z \"$repo_json\" ]]; then',\n    \"  err \\\"could not resolve owning repo via 'gh repo view' (not a GitHub repo or gh not authenticated?)\\\"\",\n    \"  exit 4\",\n    \"fi\",\n    \"\",\n    \"owner=$(echo \\\"$repo_json\\\" | jq -r '.owner.login // empty')\",\n    \"name=$(echo \\\"$repo_json\\\" | jq -r '.name // empty')\",\n    \"\",\n    'if [[ -z \"$owner\" || -z \"$name\" ]]; then',\n    '  err \"could not parse owner/name from gh repo view output\"',\n    \"  exit 4\",\n    \"fi\",\n    \"\",\n    \"# ── look up issue type node ID ───────────────────────────────────────\",\n    \"\",\n    \"types_json=$(gh api graphql \\\\\",\n    \"  -f query='query($owner:String!,$repo:String!){repository(owner:$owner,name:$repo){issueTypes(first:50){nodes{id name}}}}' \\\\\",\n    '  -f owner=\"$owner\" -f repo=\"$name\" 2>/dev/null)',\n    \"\",\n    'if [[ -z \"$types_json\" ]]; then',\n    '  err \"failed to query repo issue types via GraphQL\"',\n    \"  exit 5\",\n    \"fi\",\n    \"\",\n    \"types_nodes=$(echo \\\"$types_json\\\" | jq -c '.data.repository.issueTypes.nodes // []')\",\n    \"\",\n    'if [[ \"$types_nodes\" == \"[]\" || \"$types_nodes\" == \"null\" ]]; then',\n    '  err \"repo ${owner}/${name} has no issue types defined\"',\n    \"  exit 5\",\n    \"fi\",\n    \"\",\n    \"# Case-insensitive match by name.\",\n    'type_id=$(echo \"$types_nodes\" | jq -r --arg n \"$type_name\" \\'',\n    \"  .[] | select((.name | ascii_downcase) == ($n | ascii_downcase)) | .id\",\n    \"' | head -n 1)\",\n    \"\",\n    'if [[ -z \"$type_id\" ]]; then',\n    \"  available=$(echo \\\"$types_nodes\\\" | jq -r '.[].name' | paste -sd ',' - | sed 's/,/, /g')\",\n    \"  err \\\"type '${type_name}' not found in ${owner}/${name}. Available types: ${available}\\\"\",\n    \"  exit 6\",\n    \"fi\",\n    \"\",\n    \"# ── look up issue node ID ────────────────────────────────────────────\",\n    \"\",\n    'issue_id=$(gh issue view \"$issue_number\" --json id -q \\'.id\\' 2>/dev/null || echo \"\")',\n    \"\",\n    'if [[ -z \"$issue_id\" ]]; then',\n    '  err \"issue #${issue_number} not found in ${owner}/${name}\"',\n    \"  exit 7\",\n    \"fi\",\n    \"\",\n    \"# ── apply the mutation ───────────────────────────────────────────────\",\n    \"\",\n    \"result=$(gh api graphql \\\\\",\n    \"  -f query='mutation($issueId:ID!,$typeId:ID!){updateIssueIssueType(input:{issueId:$issueId,issueTypeId:$typeId}){issue{number issueType{name}}}}' \\\\\",\n    '  -f issueId=\"$issue_id\" -f typeId=\"$type_id\" 2>&1)',\n    \"mutation_exit=$?\",\n    \"\",\n    \"if [[ $mutation_exit -ne 0 ]]; then\",\n    '  err \"updateIssueIssueType mutation failed: ${result}\"',\n    \"  exit 8\",\n    \"fi\",\n    \"\",\n    \"# Print the resulting {number, issueType: {name}} JSON line.\",\n    \"echo \\\"$result\\\" | jq -c '.data.updateIssueIssueType.issue'\",\n  ].join(\"\\n\"),\n};\n\n/*******************************************************************************\n *\n * clean-merged-branches.sh — Report local branches whose content is fully on\n * the base branch (analysis-only; safe to invoke non-interactively).\n *\n * Uses content equality (`git diff --name-only` against the base branch) so\n * squash-merged branches are correctly identified — `git branch -d`'s\n * commit-graph reachability check does not catch squash merges because the\n * original branch commits are replaced on the base by a single new commit\n * with a different hash.\n *\n * The procedure NEVER deletes branches; it only classifies and reports. The\n * `/clean-merged-branches` skill wraps it with the confirmation prompt and\n * the deletion loop.\n *\n ******************************************************************************/\n\nconst cleanMergedBranchesProcedure: AgentProcedure = {\n  name: \"clean-merged-branches.sh\",\n  description:\n    \"Analyse local branches and classify each as MERGED, UNMERGED, EMPTY, or SKIP_WORKTREE against a base branch (default: main). Analysis-only — never deletes branches. Handles squash merges via content equality.\",\n  content: [\n    \"#!/usr/bin/env bash\",\n    \"# clean-merged-branches.sh — Analyse local branches against a base.\",\n    \"#\",\n    \"# Reports each local branch (other than HEAD and the base branch) as\",\n    \"# MERGED, UNMERGED, EMPTY, or SKIP_WORKTREE. MERGED means every file the\",\n    \"# branch added or modified now matches the base — so the branch content\",\n    \"# is fully on the base even when the merge was a squash.\",\n    \"#\",\n    \"# This procedure is analysis-only. It never runs `git branch -D`. The\",\n    \"# /clean-merged-branches slash-command skill wraps it with the deletion\",\n    \"# prompt; the procedure itself is safe to invoke non-interactively from\",\n    \"# any agent.\",\n    \"#\",\n    \"# Usage:\",\n    \"#   .claude/procedures/clean-merged-branches.sh             # default base: main\",\n    \"#   .claude/procedures/clean-merged-branches.sh --base develop\",\n    \"#\",\n    \"# Output (one line per branch, stable format for grepping):\",\n    \"#   MERGED       <branch>  files=<n>\",\n    \"#   UNMERGED     <branch>  files=<n>  differs=<n>\",\n    \"#   EMPTY        <branch>\",\n    \"#   SKIP_WORKTREE <branch>  worktree=<path>\",\n    \"#\",\n    \"# Exit codes:\",\n    \"#   0 — analysis completed (whether or not any MERGED branches were found)\",\n    \"#   2 — argument error\",\n    \"#   3 — required command not on PATH\",\n    \"#   4 — not a git repository\",\n    \"\",\n    \"set -uo pipefail\",\n    \"\",\n    \"# ── helpers ──────────────────────────────────────────────────────────\",\n    \"\",\n    \"err() {\",\n    '  printf \"clean-merged-branches.sh: %s\\\\n\" \"$*\" >&2',\n    \"}\",\n    \"\",\n    \"usage() {\",\n    \"  cat >&2 <<'USAGE'\",\n    \"Usage: clean-merged-branches.sh [--base <name>]\",\n    \"\",\n    \"  --base <name>   Base branch to compare against (default: main; falls\",\n    \"                  back to whatever origin/HEAD points at if main is\",\n    \"                  not present locally).\",\n    \"\",\n    \"Reports MERGED / UNMERGED / EMPTY / SKIP_WORKTREE for every local\",\n    \"branch other than HEAD and the base branch. Does not delete anything.\",\n    \"USAGE\",\n    \"}\",\n    \"\",\n    \"# ── argument parsing ─────────────────────────────────────────────────\",\n    \"\",\n    'base=\"\"',\n    \"while [[ $# -gt 0 ]]; do\",\n    '  case \"$1\" in',\n    \"    --base)\",\n    '      if [[ $# -lt 2 || -z \"${2:-}\" ]]; then',\n    '        err \"--base requires a value\"',\n    \"        usage\",\n    \"        exit 2\",\n    \"      fi\",\n    '      base=\"$2\"',\n    \"      shift 2\",\n    \"      ;;\",\n    \"    -h|--help)\",\n    \"      usage\",\n    \"      exit 0\",\n    \"      ;;\",\n    \"    *)\",\n    '      err \"unknown argument: $1\"',\n    \"      usage\",\n    \"      exit 2\",\n    \"      ;;\",\n    \"  esac\",\n    \"done\",\n    \"\",\n    \"# ── dependency checks ────────────────────────────────────────────────\",\n    \"\",\n    \"for cmd in git; do\",\n    '  if ! command -v \"$cmd\" >/dev/null 2>&1; then',\n    '    err \"required command not found on PATH: $cmd\"',\n    \"    exit 3\",\n    \"  fi\",\n    \"done\",\n    \"\",\n    \"# ── repo + base resolution ───────────────────────────────────────────\",\n    \"\",\n    \"if ! git rev-parse --git-dir >/dev/null 2>&1; then\",\n    '  err \"not inside a git repository\"',\n    \"  exit 4\",\n    \"fi\",\n    \"\",\n    \"# Default base = main if it exists locally, otherwise whatever\",\n    \"# origin/HEAD points at (e.g. master, trunk, develop).\",\n    'if [[ -z \"$base\" ]]; then',\n    '  if git show-ref --verify --quiet \"refs/heads/main\"; then',\n    '    base=\"main\"',\n    \"  else\",\n    \"    origin_head=$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null || true)\",\n    '    if [[ -n \"$origin_head\" ]]; then',\n    '      base=\"${origin_head#origin/}\"',\n    \"    else\",\n    '      base=\"main\"',\n    \"    fi\",\n    \"  fi\",\n    \"fi\",\n    \"\",\n    \"# Verify the chosen base actually exists as a local branch.\",\n    'if ! git show-ref --verify --quiet \"refs/heads/$base\"; then',\n    \"  err \\\"base branch '$base' does not exist locally\\\"\",\n    \"  exit 4\",\n    \"fi\",\n    \"\",\n    \"# Refresh remote-tracking refs and prune deleted upstream branches\",\n    \"# so the gone-upstream signal is fresh (best effort — never fatal).\",\n    \"git fetch --prune origin >/dev/null 2>&1 || true\",\n    \"\",\n    'current=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo \"\")',\n    \"\",\n    \"# ── worktree map (branch -> worktree path, excluding the current) ───\",\n    \"\",\n    \"# Use git worktree list --porcelain to detect any branch checked out in\",\n    \"# a separate worktree. We must skip those because `git branch -D` would\",\n    \"# refuse to delete a branch that is checked out elsewhere.\",\n    \"#\",\n    \"# We use parallel arrays (not an associative array) to stay compatible\",\n    \"# with bash 3 — macOS still ships bash 3.2 as /bin/bash, and the script\",\n    \"# is invoked via #!/usr/bin/env bash which picks whichever bash is\",\n    \"# first on PATH. Lookups are O(n) but n is tiny (worktree count).\",\n    \"worktree_branches=()\",\n    \"worktree_paths=()\",\n    'cwd_top=$(git rev-parse --show-toplevel 2>/dev/null || echo \"\")',\n    'wt_path=\"\"',\n    \"while IFS= read -r line; do\",\n    '  case \"$line\" in',\n    \"    worktree\\\\ *)\",\n    '      wt_path=\"${line#worktree }\"',\n    \"      ;;\",\n    \"    branch\\\\ *)\",\n    '      wt_branch=\"${line#branch refs/heads/}\"',\n    \"      # Skip the worktree that matches the current top-level — that one\",\n    \"      # is the *current* checkout; skipping HEAD is handled separately.\",\n    '      if [[ -n \"$wt_path\" && \"$wt_path\" != \"$cwd_top\" ]]; then',\n    '        worktree_branches+=(\"$wt_branch\")',\n    '        worktree_paths+=(\"$wt_path\")',\n    \"      fi\",\n    '      wt_path=\"\"',\n    \"      ;;\",\n    '    \"\")',\n    '      wt_path=\"\"',\n    \"      ;;\",\n    \"  esac\",\n    \"done < <(git worktree list --porcelain 2>/dev/null)\",\n    \"\",\n    \"# Echo the worktree path for the given branch, or empty string if the\",\n    \"# branch is not checked out in another worktree.\",\n    \"lookup_worktree() {\",\n    '  local needle=\"$1\"',\n    \"  local i\",\n    '  for i in \"${!worktree_branches[@]}\"; do',\n    '    if [[ \"${worktree_branches[$i]}\" == \"$needle\" ]]; then',\n    \"      printf '%s\\\\n' \\\"${worktree_paths[$i]}\\\"\",\n    \"      return 0\",\n    \"    fi\",\n    \"  done\",\n    \"  return 0\",\n    \"}\",\n    \"\",\n    \"# ── walk local branches ──────────────────────────────────────────────\",\n    \"\",\n    'echo \"Analysing local branches against ${base}…\"',\n    \"echo\",\n    \"\",\n    \"while IFS= read -r branch; do\",\n    '  [[ -z \"$branch\" ]] && continue',\n    '  [[ \"$branch\" == \"$base\" ]] && continue',\n    '  [[ \"$branch\" == \"$current\" ]] && continue',\n    \"\",\n    '  wt=$(lookup_worktree \"$branch\")',\n    '  if [[ -n \"$wt\" ]]; then',\n    '    printf \\'SKIP_WORKTREE %s  worktree=%s\\\\n\\' \"$branch\" \"$wt\"',\n    \"    continue\",\n    \"  fi\",\n    \"\",\n    '  mb=$(git merge-base \"$base\" \"$branch\" 2>/dev/null || true)',\n    '  if [[ -z \"$mb\" ]]; then',\n    \"    # No common ancestor with base — treat as UNMERGED (don't risk it).\",\n    \"    printf 'UNMERGED     %s  files=?  differs=?\\\\n' \\\"$branch\\\"\",\n    \"    continue\",\n    \"  fi\",\n    \"\",\n    '  files=$(git diff --name-only \"$mb\" \"$branch\" 2>/dev/null || true)',\n    '  if [[ -z \"$files\" ]]; then',\n    \"    printf 'EMPTY        %s\\\\n' \\\"$branch\\\"\",\n    \"    continue\",\n    \"  fi\",\n    \"\",\n    \"  # Count how many of those files still differ from the base today.\",\n    \"  # We use NUL-delimited git output to survive filenames with spaces.\",\n    \"  diff_count=0\",\n    \"  while IFS= read -r -d '' f; do\",\n    \"    diff_count=$((diff_count + 1))\",\n    '  done < <(git diff -z --name-only \"$branch\" \"$base\" -- $files 2>/dev/null)',\n    \"\",\n    \"  total=$(echo \\\"$files\\\" | wc -l | tr -d ' ')\",\n    \"\",\n    '  if [[ \"$diff_count\" -eq 0 ]]; then',\n    '    printf \\'MERGED       %s  files=%s\\\\n\\' \"$branch\" \"$total\"',\n    \"  else\",\n    '    printf \\'UNMERGED     %s  files=%s  differs=%s\\\\n\\' \"$branch\" \"$total\" \"$diff_count\"',\n    \"  fi\",\n    \"done < <(git branch --format='%(refname:short)')\",\n    \"\",\n    \"exit 0\",\n  ].join(\"\\n\"),\n};\n\n/*******************************************************************************\n *\n * /clean-merged-branches skill — wraps the procedure with the\n * report-confirm-delete UX.\n *\n ******************************************************************************/\n\nconst cleanMergedBranchesSkill: AgentSkill = {\n  name: \"clean-merged-branches\",\n  description:\n    \"Report every local branch as MERGED or UNMERGED against the base (handles squash merges via content equality), then prompt the user to force-delete the MERGED list. Defaults base to main; --base overrides. Skips current branch, base branch, and any branch checked out in another worktree.\",\n  disableModelInvocation: true,\n  userInvocable: true,\n  platforms: { cursor: { exclude: true } },\n  instructions: [\n    \"# Clean Merged Branches\",\n    \"\",\n    \"Identify local branches whose content is fully on the base branch —\",\n    \"including branches that were squash-merged (where `git branch -d`\",\n    \"refuses because the branch commits are not ancestors of the base) —\",\n    \"report them to the user, and force-delete them after explicit\",\n    \"confirmation.\",\n    \"\",\n    \"## Usage\",\n    \"\",\n    \"```\",\n    \"/clean-merged-branches                # default base: main\",\n    \"/clean-merged-branches --base develop # custom base branch\",\n    \"```\",\n    \"\",\n    \"### Flags\",\n    \"\",\n    \"- **`--base <name>`** — base branch to compare against. Defaults to\",\n    \"  `main`; falls back to whatever `origin/HEAD` points at if `main`\",\n    \"  does not exist locally.\",\n    \"\",\n    \"## What This Skill Does\",\n    \"\",\n    \"1. **Analyse.** Runs `.claude/procedures/clean-merged-branches.sh`\",\n    \"   (passing through any `--base` flag). The procedure walks every\",\n    \"   local branch and prints one stable log line per branch:\",\n    \"   - `MERGED       <branch>  files=<n>` — every file the branch added\",\n    \"     or modified now matches the base. Safe to delete.\",\n    \"   - `UNMERGED     <branch>  files=<n>  differs=<n>` — branch content\",\n    \"     still differs from the base. Do NOT delete.\",\n    \"   - `EMPTY        <branch>` — branch has no file changes vs. its\",\n    \"     merge-base. Safe to delete.\",\n    \"   - `SKIP_WORKTREE <branch>  worktree=<path>` — branch is checked\",\n    \"     out in another worktree. Skipped (cannot be deleted while it's\",\n    \"     in use).\",\n    \"\",\n    \"2. **Confirm.** If the report turns up at least one `MERGED` (or\",\n    \"   `EMPTY`) branch, print the exact deletion list and a single\",\n    \"   `[y/N]` prompt. Empty input defaults to **no** and aborts.\",\n    \"\",\n    \"3. **Delete.** On explicit `y` / `Y`, run `git branch -D <branch>`\",\n    \"   for each confirmed branch and emit one `DELETED <branch>` line\",\n    \"   per success. On any other answer (including empty input),\",\n    \"   abort with `Aborted. No branches deleted.` and exit cleanly.\",\n    \"\",\n    \"If the report finds zero deletable branches, exit cleanly without\",\n    \"prompting — there is nothing to confirm.\",\n    \"\",\n    \"## Behaviour Guarantees\",\n    \"\",\n    \"- **Always skip the current branch and the base branch.** The\",\n    \"  procedure enforces this; the skill never needs to filter again.\",\n    \"- **Never delete without an explicit `y`.** The default on empty\",\n    \"  input is no. The skill never runs `git branch -D` until after\",\n    \"  the prompt returns `y` or `Y`.\",\n    \"- **Content equality is the proof.** A branch classifies as\",\n    \"  `MERGED` when every file it added or modified matches the base\",\n    \"  today — handles squash merges, file deletions, and renames.\",\n    \"  The `[origin/<branch>: gone]` indicator is a useful secondary\",\n    \"  signal but is NOT the deletion gate.\",\n    \"- **Safe across worktrees.** Branches checked out in another\",\n    \"  worktree are logged as `SKIP_WORKTREE` and excluded from the\",\n    \"  deletion list.\",\n    \"\",\n    \"## Output\",\n    \"\",\n    \"The procedure's per-branch log lines first, then (if any deletable\",\n    \"branches exist) the confirmation prompt, then one `DELETED <branch>`\",\n    \"line per successful deletion or `Aborted. No branches deleted.`\",\n    \"on abort.\",\n    \"\",\n    \"## Implementation Recipe\",\n    \"\",\n    \"```bash\",\n    \"# 1. Run the analysis-only procedure and capture its output.\",\n    'report=$(.claude/procedures/clean-merged-branches.sh \"$@\")',\n    'printf \"%s\\\\n\" \"$report\"',\n    \"\",\n    \"# 2. Extract the MERGED + EMPTY branch names from the report.\",\n    \"mergeable=()\",\n    \"while IFS= read -r line; do\",\n    '  case \"$line\" in',\n    '    \"MERGED \"*|\"EMPTY \"*)',\n    \"      # The branch name is the second whitespace-delimited token.\",\n    \"      branch=$(echo \\\"$line\\\" | awk '{print $2}')\",\n    '      [[ -n \"$branch\" ]] && mergeable+=(\"$branch\")',\n    \"      ;;\",\n    \"  esac\",\n    'done <<< \"$report\"',\n    \"\",\n    \"# 3. If nothing to delete, exit cleanly without prompting.\",\n    \"if [[ ${#mergeable[@]} -eq 0 ]]; then\",\n    \"  echo\",\n    '  echo \"No merged branches to delete.\"',\n    \"  exit 0\",\n    \"fi\",\n    \"\",\n    \"# 4. Show the list and prompt the user once.\",\n    \"echo\",\n    'echo \"The following ${#mergeable[@]} branches are safe to delete:\"',\n    \"printf '  %s\\\\n' \\\"${mergeable[@]}\\\"\",\n    \"echo\",\n    'read -r -p \"Force-delete all ${#mergeable[@]} with git branch -D? [y/N] \" answer',\n    \"\",\n    \"# 5. On explicit y/Y only, delete each branch.\",\n    'if [[ \"$answer\" == \"y\" || \"$answer\" == \"Y\" ]]; then',\n    '  for b in \"${mergeable[@]}\"; do',\n    '    if git branch -D \"$b\" >/dev/null 2>&1; then',\n    '      echo \"DELETED      $b\"',\n    \"    else\",\n    '      echo \"DELETE_FAILED $b\" >&2',\n    \"    fi\",\n    \"  done\",\n    \"else\",\n    '  echo \"Aborted. No branches deleted.\"',\n    \"fi\",\n    \"```\",\n    \"\",\n    \"## Composability\",\n    \"\",\n    \"The procedure (`.claude/procedures/clean-merged-branches.sh`) is\",\n    \"analysis-only and safe to invoke from any agent. The skill is the\",\n    \"interactive entry point — use it when a human is at the keyboard.\",\n    \"Background workers (orchestrator, maintenance-audit) should call\",\n    \"the procedure directly and report its output without acting on it.\",\n  ].join(\"\\n\"),\n  referenceFiles: [\n    {\n      path: \"evals/evals.json\",\n      content: JSON.stringify(\n        {\n          skill_name: \"clean-merged-branches\",\n          evals: [\n            {\n              id: 1,\n              prompt: \"/clean-merged-branches\",\n              expected_output:\n                \"The skill runs the analysis-only `clean-merged-branches.sh` procedure against the current checkout's base branch (default: `main`). Each local branch other than HEAD and `main` is reported on one stable line as `MERGED`, `UNMERGED`, `EMPTY`, or `SKIP_WORKTREE` with a file count. When at least one branch classifies as `MERGED` or `EMPTY`, the skill prints the exact deletion list and prompts `Force-delete all <n> with git branch -D? [y/N]`. On explicit `y` / `Y` it force-deletes each branch with `git branch -D` and emits one `DELETED <branch>` line per success. Empty input or any other answer aborts with `Aborted. No branches deleted.` and no branches are deleted. When zero branches are deletable, the skill exits cleanly without prompting.\",\n              files: [],\n              product_context_refs: [],\n            },\n            {\n              id: 2,\n              prompt: \"/clean-merged-branches --base develop\",\n              expected_output:\n                \"The skill forwards `--base develop` to the procedure, which compares every local branch (other than HEAD and `develop`) against `develop` instead of `main`. Branches whose content matches `develop` classify as `MERGED`; others as `UNMERGED`. The base-branch override is also reflected in the deletion prompt (`...with git branch -D?`), and the skill never deletes `develop` itself or the current HEAD. If `develop` does not exist as a local branch, the procedure exits non-zero with a clear diagnostic and the skill aborts without prompting.\",\n              files: [],\n              product_context_refs: [],\n            },\n            {\n              id: 3,\n              prompt:\n                \"/clean-merged-branches — I have a branch called feat/old-feature that I checked out in a sibling worktree under /tmp/work. Confirm it's skipped.\",\n              expected_output:\n                \"The procedure detects `feat/old-feature` via `git worktree list --porcelain` and reports `SKIP_WORKTREE feat/old-feature  worktree=/tmp/work` instead of classifying it. The branch is excluded from the deletion list shown at the confirmation prompt. Even if the user answers `y`, the skill never runs `git branch -D feat/old-feature` because the branch is not in the mergeable list.\",\n              files: [],\n              product_context_refs: [],\n            },\n          ],\n        },\n        null,\n        2,\n      ),\n    },\n  ],\n};\n\n/**\n * Renders step 2 (\"run the build\") of the `pr-workflow` rule.\n *\n * The step is policy-aware on two axes:\n *\n *   - **Scope.** A full `pnpm build:all` is mandated only for changes\n *     that touch build inputs. Documentation-only diffs skip it — CI\n *     is the authoritative content gate, and mandating a slow build\n *     for a markdown edit is what pushed autonomous workers into the\n *     background-build-then-end-turn failure mode below.\n *   - **Remote cache.** The AWS-authentication sentence is emitted\n *     only when the project actually configures a Turborepo remote\n *     cache, and names that project's own profile rather than a\n *     hard-coded one.\n *\n * @see ResolvedBuildPolicy\n */\nfunction renderPrWorkflowBuildStep(\n  policy: ResolvedBuildPolicy,\n): ReadonlyArray<string> {\n  const lines: Array<string> = [\n    \"2. **Run the build — scoped to what changed.**\",\n    \"\",\n    \"   - **Documentation-only changes** — a diff confined to documentation content (markdown pages, no source, config, or projen inputs) does **not** require `pnpm build:all`. There is nothing to compile, and CI is the authoritative content gate. Commit the content and proceed to the next step.\",\n    \"   - **Everything else** — when the change touches build inputs (source code, `.projenrc.ts`, `projenrc/**`, or any other projen-generated config), run `pnpm build:all` to compile, lint, and test all packages (mirrors the CI pipeline). If the build produces changes to turbo inputs (typically snapshot files or ESLint auto-fixes), commit those changes and run `pnpm build:all` again — the build must complete cleanly with no uncommitted changes.\",\n  ];\n\n  /**\n   * Only assert the credential requirement when it is real. With no\n   * remote cache configured, `pnpm build:all` reads and writes a local\n   * cache directory only and needs no AWS credentials — emitting the\n   * sentence anyway sends agents chasing an authentication step that\n   * does not exist.\n   */\n  if (policy.remoteCacheEnabled && policy.awsProfileName) {\n    lines.push(\n      \"\",\n      `   \\`pnpm build:all\\` uses the Turborepo **remote cache**, which requires the user to be authenticated to AWS on the \\`${policy.awsProfileName}\\` profile. If the command fails due to AWS credentials, ask the user to authenticate first.`,\n    );\n  }\n\n  lines.push(\n    \"\",\n    \"   **Never background a long build and end the turn.** If you run a build, run it in the **foreground** to completion before committing, pushing, or opening the PR. Launching `pnpm build:all` as a background process and ending your turn while it is still running strands the deliverable uncommitted — that work is lost. This is the documented root cause of autonomous worker-stall incidents.\",\n  );\n\n  return lines;\n}\n\n/**\n * Builds the GitHub workflow bundle — auto-detected when the project\n * has a GitHub component.\n *\n * The `build` policy conditions the PR-workflow build guidance on the\n * consuming project's Turborepo remote-cache configuration. When\n * omitted, the bundle ships the zero-remote-cache defaults\n * ({@link DEFAULT_BUILD_POLICY}), which emit no AWS-authentication\n * guidance at all.\n */\nexport function buildGithubWorkflowBundle(\n  buildPolicy: ResolvedBuildPolicy = DEFAULT_BUILD_POLICY,\n): AgentRuleBundle {\n  return {\n    name: \"github-workflow\",\n    description: \"GitHub issue and PR workflow automation patterns\",\n    appliesWhen: (project) => hasComponent(project, GitHub),\n    rules: [\n      {\n        name: \"issue-workflow\",\n        description: \"Automated workflow for starting work on a GitHub issue\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Issue Workflow\",\n          \"\",\n          '## \"Work on issue X\" Automation',\n          \"\",\n          \"When the user says **work on issue X** (or similar), invoke the `issue-worker` agent in interactive mode, passing the issue number in the prompt. Do not perform the branch creation, issue fetching, or planning steps yourself — the agent handles the full workflow (claim, branch, plan, implement, PR) and will pause for your approval at the appropriate checkpoints.\",\n        ].join(\"\\n\"),\n        tags: [\"workflow\"],\n      },\n      {\n        name: \"create-issue-workflow\",\n        description: \"Automated workflow for creating a new GitHub issue\",\n        // ALWAYS scope: users invoke \"create an issue\" from any\n        // context, not only when editing agent / skill / bundle source.\n        // Consumers that want to narrow the load can override via\n        // `agentConfig.additionalRulePaths` or `excludeRules`.\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Create Issue Workflow\",\n          \"\",\n          '## \"Create an issue\" Automation',\n          \"\",\n          \"When the user says **create an issue** (or similar), follow these steps exactly:\",\n          \"\",\n          \"1. **Determine the issue type prefix** from the user's description:\",\n          \"   - `epic:` — Large initiatives spanning multiple child issues\",\n          \"   - `feat:` — New features or functionality\",\n          \"   - `fix:` — Bug fixes\",\n          \"   - `chore:` — Maintenance: deps, tooling, config\",\n          \"   - `docs:` — Documentation-only work\",\n          \"   - `refactor:` — Code restructure, no behavior change\",\n          \"   - `release:` — Release preparation, version bumps\",\n          \"   - `hotfix:` — Urgent production fixes\",\n          \"   - If unclear, ask the user which type applies\",\n          \"2. **Compose the issue title** in the format: `<type>: <short description>`\",\n          \"3. **Determine the GitHub issue type** based on the prefix:\",\n          ...renderTitlePrefixTypeBullets(),\n          \"4. **Identify prerequisite issues** — if the user mentions dependencies or blockers, include a **Dependencies** section in the body with `Depends on: #<issue-number>`\",\n          \"5. **Determine labels** — every issue must be created with the following labels:\",\n          \"   - **`type:*`** — derived from the issue title prefix:\",\n          \"     - `epic:` → `type:feat`\",\n          \"     - `feat:` → `type:feat`\",\n          \"     - `fix:` → `type:fix`\",\n          \"     - `chore:` → `type:chore`\",\n          \"     - `docs:` → `type:docs`\",\n          \"     - `refactor:` → `type:refactor`\",\n          \"     - `release:` → `type:release`\",\n          \"     - `hotfix:` → `type:hotfix`\",\n          '   - **`priority:*`** — infer from the user\\'s description when possible (e.g., \"urgent\"/\"critical\" → `priority:critical`, \"important\" → `priority:high`, \"minor\"/\"low priority\" → `priority:low`). If the priority is unclear, ask the user before creating the issue. Valid values: `priority:critical`, `priority:high`, `priority:medium`, `priority:low`, `priority:trivial`',\n          \"   - **`status:ready`** — always add unless the issue has dependencies or blockers, in which case use `status:blocked`\",\n          \"6. **Create the issue** using `gh issue create`:\",\n          \"   - `--title '<type>: <description>'`\",\n          \"   - `--body '<issue body>'`\",\n          \"   - `--label '<type-label>' --label '<priority-label>' --label '<status-label>'`\",\n          \"7. **Set the GitHub issue type** by invoking the `set-issue-type.sh` helper (shipped with this bundle):\",\n          \"\",\n          \"   ```sh\",\n          \"   .claude/procedures/set-issue-type.sh <issue-number> <Feature|Task|Epic|Bug>\",\n          \"   ```\",\n          \"\",\n          \"   The helper resolves owner/repo, looks up the issue type node ID, looks up the issue node ID, and applies the `updateIssueIssueType` mutation in one step. It exits non-zero with a clear diagnostic on any error and lists available types if the type name is not recognised.\",\n          \"\",\n          \"   **Under the hood** (documented fallback if the helper is unavailable): the helper performs a two-step GraphQL flow — first a `repository(...).issueTypes` query to map the human-readable type name to a node ID, then the `updateIssueIssueType` mutation. The canonical queries are:\",\n          \"\",\n          \"   ```sh\",\n          \"   gh api graphql -f query='query($owner:String!,$repo:String!){repository(owner:$owner,name:$repo){issueTypes(first:50){nodes{id name}}}}' -f owner=<owner> -f repo=<repo>\",\n          \"   gh api graphql -f query='mutation($issueId:ID!,$typeId:ID!){updateIssueIssueType(input:{issueId:$issueId,issueTypeId:$typeId}){issue{number issueType{name}}}}' -f issueId=<issue-node-id> -f typeId=<issue-type-node-id>\",\n          \"   ```\",\n          \"\",\n          \"### Issue Body Template\",\n          \"\",\n          \"```markdown\",\n          \"## Summary\",\n          \"\",\n          \"<1-3 sentences describing the issue>\",\n          \"\",\n          \"## Details\",\n          \"\",\n          \"<Detailed description, acceptance criteria, or reproduction steps as appropriate>\",\n          \"\",\n          \"## Dependencies\",\n          \"\",\n          \"Depends on: #<issue-number> (if any, otherwise omit this section)\",\n          \"```\",\n          \"\",\n          \"### Important\",\n          \"\",\n          \"- Always use the conventional prefix in the issue title\",\n          \"- Always assign the correct GitHub issue type via the `set-issue-type.sh` helper (step 7) — never via `gh issue create --type`\",\n          \"- Always include `type:*`, `priority:*`, and `status:*` labels\",\n          \"- If the user does not specify a type, ask before creating the issue\",\n          \"- If the priority cannot be inferred from the description, ask the user before creating the issue\",\n          \"- Keep titles concise and descriptive\",\n        ].join(\"\\n\"),\n        tags: [\"workflow\"],\n      },\n      {\n        name: \"pr-workflow\",\n        description: \"Automated workflow for opening a pull request\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# PR Workflow\",\n          \"\",\n          '## \"Open a PR\" Automation',\n          \"\",\n          \"When the user says **open a PR** (or similar), follow these steps exactly:\",\n          \"\",\n          \"1. **Regenerate project files** — run the three-step regen sequence (`pnpm i`, then `pnpm exec projen`, then `pnpm i` again) to ensure all generated files are up to date. The leading `pnpm i` is required because `pnpm exec projen` synthesises against whatever version of configulator (and projen, and any projen plugins) is currently resolved in `node_modules`; if the lockfile has moved past `node_modules` (typically right after `git pull` lands a dependency upgrade, or on a fresh checkout), synth runs against stale templates and produces phantom drift in `.claude/`, `.github/labels.yml`, `CLAUDE.md`, and other generated files. The trailing `pnpm i` picks up any dependency changes projen wrote into `package.json` during synth. Check `git diff` after the third step — if there are changes, commit them before proceeding.\",\n          ...renderPrWorkflowBuildStep(buildPolicy),\n          \"3. **Check for uncommitted changes** — if any exist, commit them with a conventional commit message\",\n          \"4. **Pull and rebase from the default branch** — run `git pull origin {{repository.defaultBranch}} --rebase` to incorporate the latest changes and resolve any conflicts before pushing\",\n          \"5. **Push the branch** to origin: `git push -u origin <branch>`\",\n          \"6. **Create the PR** using `gh pr create`:\",\n          \"   - **Title**: use a conventional commit style title (e.g., `feat(scope): short description`)\",\n          \"   - **Body**: include one `Closes #<issue-number>` line per issue the PR closes (derived from the branch name and any additional issues in scope) and a brief summary of changes. See **Closing Keywords** below — never list several issues after a single keyword.\",\n          \"7. **Verify the closing keywords** with `.claude/procedures/check-closing-keywords.sh --body-file <path>` on the body you are about to post, then `.claude/procedures/check-closing-keywords.sh <pr-number>` on the body that landed. Exit `0` means every referenced issue will auto-close; exit `1` prints a `STRANDED #<n>` line per issue GitHub would silently leave open — fix the body with `gh pr edit <pr-number> --body-file <path>` and re-run until it exits `0`.\",\n          \"8. **Delegate review and merge to the `pr-reviewer` sub-agent.** After the PR is created, invoke the `/review-pr <pr-number>` skill (or otherwise hand the new PR number to the `pr-reviewer` sub-agent). The reviewer verifies the diff against the linked issue's acceptance criteria and enables squash auto-merge when all checks pass. Do **not** run `gh pr merge --auto` yourself — review/merge policy lives solely in the `pr-reviewer` agent.\",\n          \"\",\n          \"### Closing Keywords\",\n          \"\",\n          \"**GitHub honours exactly ONE issue reference per closing keyword.** `Closes #593, #594, #595` closes **#593 only** — #594 and #595 stay open forever with no warning anywhere. `Closes #821 / #837` and `Closes #821 and #837` strand the second issue the same way. Give every issue its own keyword, one per line:\",\n          \"\",\n          \"```markdown\",\n          \"Closes #593        <- correct: repeat the keyword, one issue each\",\n          \"Closes #594\",\n          \"\",\n          \"Closes #593, #594  <- WRONG: closes #593, strands #594\",\n          \"Closes #821 / #837 <- WRONG: closes #821, strands #837\",\n          \"Closes #821 and #837  <- WRONG: closes #821, strands #837\",\n          \"```\",\n          \"\",\n          \"`Fixes` and `Resolves` behave identically — the rule is the keyword-to-issue ratio, not the verb. Non-closing references (`Refs #849`, `Related to #607`) are unaffected. `.claude/procedures/check-closing-keywords.sh` is the mechanical check; it skips fenced code blocks, blockquotes, and inline code spans, so a body that *discusses* the malformed form does not trip it.\",\n          \"\",\n          \"### PR Body Template\",\n          \"\",\n          \"```markdown\",\n          \"## Summary\",\n          \"\",\n          \"<1-3 bullet points describing what changed and why>\",\n          \"\",\n          \"Closes #<issue-number>\",\n          \"\",\n          \"## Test Plan\",\n          \"\",\n          \"- [ ] Tests pass locally\",\n          \"- [ ] Relevant changes have been reviewed\",\n          \"```\",\n          \"\",\n          \"When the PR closes more than one issue, the closing block expands to one keyword per issue — it never becomes a list:\",\n          \"\",\n          \"```markdown\",\n          \"Closes #<first-issue-number>\",\n          \"Closes #<second-issue-number>\",\n          \"```\",\n          \"\",\n          \"### Important\",\n          \"\",\n          \"- Always derive the issue number from the branch name (e.g., `feat/42-add-login` → `#42`)\",\n          \"- Use conventional commit format for the PR title\",\n          \"- **One closing keyword per issue, each on its own line.** Never `Closes #A, #B` — GitHub closes only `#A`. Run `.claude/procedures/check-closing-keywords.sh` before and after `gh pr create`; a non-zero exit means the PR would strand an issue\",\n          \"- Delegate merge to the `pr-reviewer` sub-agent — do not merge manually and do not enable auto-merge directly\",\n        ].join(\"\\n\"),\n        tags: [\"workflow\"],\n      },\n      {\n        name: \"branch-cleanup\",\n        description:\n          \"Local-branch hygiene helpers shipped with the github-workflow bundle, including the /clean-merged-branches skill for safely force-deleting branches whose content has already merged into the base (handles squash merges).\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Branch Cleanup\",\n          \"\",\n          \"Local branches accumulate after every merged PR. In squash-merge\",\n          \"repositories `git branch -d` refuses to delete them because the\",\n          \"commit hash on the base differs, even when the branch content is\",\n          \"fully merged. The `github-workflow` bundle ships two affordances\",\n          \"that use content-equality (not commit-graph reachability) to\",\n          \"identify branches safe to force-delete:\",\n          \"\",\n          \"- `/clean-merged-branches` — interactive slash-command skill that\",\n          \"  classifies every local branch, prompts for confirmation, then\",\n          \"  runs `git branch -D` on the confirmed list. See\",\n          \"  `.claude/skills/clean-merged-branches/SKILL.md` for usage,\",\n          \"  output format, and the squash-merge verification algorithm.\",\n          \"- `.claude/procedures/clean-merged-branches.sh` — analysis-only\",\n          \"  procedure for non-interactive agent use (orchestrator,\",\n          \"  maintenance-audit). NEVER deletes — only reports `MERGED` /\",\n          \"  `UNMERGED` / `EMPTY` / `SKIP_WORKTREE` lines.\",\n        ].join(\"\\n\"),\n        tags: [\"workflow\"],\n      },\n    ],\n    skills: [cleanMergedBranchesSkill],\n    procedures: [\n      setIssueTypeProcedure,\n      cleanMergedBranchesProcedure,\n      checkClosingKeywordsProcedure,\n    ],\n  };\n}\n\n/**\n * `github-workflow` bundle built with the default (no remote cache)\n * build policy. Preserved for backward compatibility with tests and\n * consumers that import the const directly. Prefer\n * `buildGithubWorkflowBundle(buildPolicy)` when the consuming\n * project's Turborepo configuration is in scope.\n */\nexport const githubWorkflowBundle: AgentRuleBundle =\n  buildGithubWorkflowBundle();\n","import { AgentProcedure } from \"../types\";\n\n/*******************************************************************************\n *\n * check-closing-keywords.sh — Detect PR bodies that strand issues.\n *\n * GitHub honours exactly ONE issue reference per closing keyword. A body\n * that writes `Closes #593, #594, #595` closes #593 and silently leaves\n * #594 and #595 open forever; `Closes #821 / #837` strands #837. The\n * only correct form is one keyword per issue:\n *\n *   Closes #593\n *   Closes #594\n *\n * The procedure is the single source of truth for closing-keyword\n * parsing across the pipeline. The `pr-workflow` rule calls it before\n * `gh pr create`; the `pr-reviewer` calls it to enumerate every linked\n * issue (pre-merge) and to verify each one actually closed (post-merge).\n *\n ******************************************************************************/\n\n/**\n * Renders the `check-closing-keywords.sh` body.\n *\n * Split into its own module so the scanner's parsing contract — fence\n * skipping, blockquote skipping, inline-code stripping, and the\n * chained-reference walk that distinguishes a malformed keyword from\n * prose that merely mentions issue numbers — stays readable next to the\n * tests that lock it, rather than buried inside the github-workflow\n * bundle definition.\n */\nexport function renderCheckClosingKeywordsScript(): string {\n  return [\n    \"#!/usr/bin/env bash\",\n    \"# check-closing-keywords.sh — Detect PR bodies that strand issues.\",\n    \"#\",\n    \"# GitHub honours exactly ONE issue reference per closing keyword. A\",\n    \"# body that writes `Closes #593, #594, #595` closes #593 and leaves\",\n    \"# #594 and #595 open forever. The only correct form is one keyword\",\n    \"# per issue, each on its own line:\",\n    \"#\",\n    \"#   Closes #593\",\n    \"#   Closes #594\",\n    \"#\",\n    \"# Usage:\",\n    \"#   .claude/procedures/check-closing-keywords.sh <pr-number>\",\n    \"#   .claude/procedures/check-closing-keywords.sh --body-file <path>\",\n    \"#\",\n    \"# Output (one stable line per reference, then a summary line):\",\n    \"#   CLOSES #<n> line=<L>\",\n    \"#       A reference GitHub WILL honour (the first one after a keyword).\",\n    \"#   STRANDED #<n> line=<L> keyword=<kw> first=#<n>\",\n    \"#       A reference chained onto an earlier one. GitHub will NOT\",\n    \"#       close it — the issue is stranded.\",\n    \"#   CLOSING_KEYWORDS_OK closes=<K>\",\n    \"#   CLOSING_KEYWORDS_MALFORMED closes=<K> stranded=<S>\",\n    \"#   NO_CLOSING_KEYWORD\",\n    \"#\",\n    \"# Exit codes:\",\n    \"#   0 — at least one closing keyword, every one well-formed\",\n    \"#   1 — at least one stranded reference (malformed body)\",\n    \"#   2 — argument error\",\n    \"#   3 — required command not on PATH\",\n    \"#   4 — could not read the PR body\",\n    \"#   5 — no closing keyword found at all\",\n    \"\",\n    \"set -uo pipefail\",\n    \"\",\n    \"# ── helpers ──────────────────────────────────────────────────────────\",\n    \"\",\n    \"err() {\",\n    '  printf \"check-closing-keywords.sh: %s\\\\n\" \"$*\" >&2',\n    \"}\",\n    \"\",\n    \"usage() {\",\n    \"  cat >&2 <<'USAGE'\",\n    \"Usage: check-closing-keywords.sh <pr-number>\",\n    \"       check-closing-keywords.sh --body-file <path>\",\n    \"\",\n    \"  <pr-number>          Positive integer PR number; the body is read\",\n    \"                       via `gh pr view <n> --json body`.\",\n    \"  --body-file <path>   Read the body from a file instead. Use this to\",\n    \"                       check a drafted body BEFORE `gh pr create`.\",\n    \"\",\n    \"Emits one CLOSES / STRANDED line per issue reference, then a summary.\",\n    \"Exits 1 when any reference is stranded by a multi-issue keyword.\",\n    \"USAGE\",\n    \"}\",\n    \"\",\n    \"# ── argument parsing ─────────────────────────────────────────────────\",\n    \"\",\n    'mode=\"\"',\n    'arg=\"\"',\n    \"\",\n    \"while [[ $# -gt 0 ]]; do\",\n    '  case \"$1\" in',\n    \"    --body-file)\",\n    '      if [[ $# -lt 2 || -z \"${2:-}\" ]]; then',\n    '        err \"--body-file requires a value\"',\n    \"        usage\",\n    \"        exit 2\",\n    \"      fi\",\n    '      if [[ -n \"$mode\" ]]; then',\n    '        err \"specify either a PR number or --body-file, not both\"',\n    \"        exit 2\",\n    \"      fi\",\n    '      mode=\"file\"',\n    '      arg=\"$2\"',\n    \"      shift 2\",\n    \"      ;;\",\n    \"    -h|--help)\",\n    \"      usage\",\n    \"      exit 0\",\n    \"      ;;\",\n    \"    -*)\",\n    '      err \"unknown option: $1\"',\n    \"      usage\",\n    \"      exit 2\",\n    \"      ;;\",\n    \"    *)\",\n    '      if [[ -n \"$mode\" ]]; then',\n    '        err \"unexpected extra argument: $1\"',\n    \"        usage\",\n    \"        exit 2\",\n    \"      fi\",\n    '      mode=\"pr\"',\n    '      arg=\"$1\"',\n    \"      shift\",\n    \"      ;;\",\n    \"  esac\",\n    \"done\",\n    \"\",\n    'if [[ -z \"$mode\" ]]; then',\n    '  err \"expected a PR number or --body-file <path>\"',\n    \"  usage\",\n    \"  exit 2\",\n    \"fi\",\n    \"\",\n    \"# ── read the body ────────────────────────────────────────────────────\",\n    \"\",\n    'body=\"\"',\n    \"\",\n    'if [[ \"$mode\" == \"file\" ]]; then',\n    '  if [[ ! -r \"$arg\" ]]; then',\n    '    err \"body file not readable: $arg\"',\n    \"    exit 4\",\n    \"  fi\",\n    '  body=$(cat \"$arg\")',\n    \"else\",\n    '  if ! [[ \"$arg\" =~ ^[1-9][0-9]*$ ]]; then',\n    \"    err \\\"PR number must be a positive integer (got: '$arg')\\\"\",\n    \"    exit 2\",\n    \"  fi\",\n    \"  if ! command -v gh >/dev/null 2>&1; then\",\n    '    err \"required command not found on PATH: gh\"',\n    \"    exit 3\",\n    \"  fi\",\n    \"  if ! body=$(gh pr view \\\"$arg\\\" --json body -q '.body' 2>/dev/null); then\",\n    '    err \"could not read the body of PR #${arg} via gh\"',\n    \"    exit 4\",\n    \"  fi\",\n    \"fi\",\n    \"\",\n    \"# ── parsing contract ─────────────────────────────────────────────────\",\n    \"#\",\n    \"# Regexes live in single-quoted variables so backticks and other shell\",\n    \"# metacharacters inside them are never expanded by [[ ]].\",\n    \"#\",\n    \"# kw_re matches a closing keyword plus its FIRST issue reference. The\",\n    \"# leading (^|[^[:alnum:]_]) is a word boundary so `prefixes #1` is not\",\n    \"# read as `fixes #1`.\",\n    \"#\",\n    \"# sep_re / ws_re walk the tail AFTER that first reference, matching\",\n    \"# only references CHAINED directly onto it by a separator a human\",\n    \"# would mistake for a list: `,`  `/`  `&`  `+`  `and`  `, and`, or\",\n    \"# bare whitespace. Anything else — a period, a dash, a word, an\",\n    \"# opening paren — terminates the chain. That is what keeps prose like\",\n    \"# `Closes #893. See #607 and #860 for context.` from false-positiving:\",\n    \"# the `.` after #893 ends the chain before `#607` is ever considered.\",\n    \"\",\n    \"fence_re='^[[:space:]]{0,3}(```+|~~~+)'\",\n    \"quote_re='^[[:space:]]*>'\",\n    \"kw_re='(^|[^[:alnum:]_])(closes|closed|close|fixes|fixed|fix|resolves|resolved|resolve)[[:space:]]*:?[[:space:]]*#([0-9]+)(.*)$'\",\n    \"sep_re='^[[:space:]]*(,[[:space:]]*and|,|/|&|[+]|and)[[:space:]]*#([0-9]+)(.*)$'\",\n    \"ws_re='^[[:space:]]+#([0-9]+)(.*)$'\",\n    \"\",\n    \"# Keywords are case-insensitive on GitHub, so the scan is too.\",\n    \"shopt -s nocasematch\",\n    \"\",\n    \"# A single backtick, held in a variable so the code-span stripper\",\n    \"# never has to quote one inline.\",\n    \"bt='`'\",\n    \"\",\n    \"# Remove inline code spans (`...`) from a line. A PR body that\",\n    \"# DISCUSSES the malformed form — writing `Closes #593, #594` inside\",\n    \"# backticks — must not trip the detector.\",\n    \"strip_code_spans() {\",\n    '  local s=\"$1\"',\n    '  local out=\"\"',\n    '  while [[ \"$s\" == *\"$bt\"*\"$bt\"* ]]; do',\n    '    out=\"$out${s%%$bt*}\"',\n    '    s=\"${s#*$bt}\"',\n    '    s=\"${s#*$bt}\"',\n    \"  done\",\n    '  printf \\'%s%s\\' \"$out\" \"$s\"',\n    \"}\",\n    \"\",\n    \"# ── scan ─────────────────────────────────────────────────────────────\",\n    \"\",\n    \"line_no=0\",\n    \"in_fence=0\",\n    'fence_marker=\"\"',\n    \"closes_count=0\",\n    \"stranded_count=0\",\n    \"\",\n    'while IFS= read -r raw || [[ -n \"$raw\" ]]; do',\n    \"  line_no=$((line_no + 1))\",\n    \"  # gh returns CRLF bodies; strip the CR so end-of-line matching works.\",\n    \"  raw=\\\"${raw//$'\\\\r'/}\\\"\",\n    \"\",\n    \"  # Fenced code blocks are quoted content, never the PR's own intent.\",\n    '  if [[ \"$raw\" =~ $fence_re ]]; then',\n    '    marker=\"${BASH_REMATCH[1]:0:1}\"',\n    \"    if [[ $in_fence -eq 0 ]]; then\",\n    \"      in_fence=1\",\n    '      fence_marker=\"$marker\"',\n    '    elif [[ \"$marker\" == \"$fence_marker\" ]]; then',\n    \"      in_fence=0\",\n    '      fence_marker=\"\"',\n    \"    fi\",\n    \"    continue\",\n    \"  fi\",\n    \"  if [[ $in_fence -eq 1 ]]; then\",\n    \"    continue\",\n    \"  fi\",\n    \"\",\n    \"  # Blockquoted text is someone else's words being cited.\",\n    '  if [[ \"$raw\" =~ $quote_re ]]; then',\n    \"    continue\",\n    \"  fi\",\n    \"\",\n    '  line=$(strip_code_spans \"$raw\")',\n    \"\",\n    '  rest=\"$line\"',\n    '  while [[ \"$rest\" =~ $kw_re ]]; do',\n    '    kw=\"${BASH_REMATCH[2]}\"',\n    '    first=\"${BASH_REMATCH[3]}\"',\n    '    tail=\"${BASH_REMATCH[4]}\"',\n    \"\",\n    '    printf \\'CLOSES #%s line=%s\\\\n\\' \"$first\" \"$line_no\"',\n    \"    closes_count=$((closes_count + 1))\",\n    \"\",\n    \"    # Walk every reference chained onto this keyword's first one.\",\n    '    t=\"$tail\"',\n    \"    while :; do\",\n    '      if [[ \"$t\" =~ $sep_re ]]; then',\n    '        extra=\"${BASH_REMATCH[2]}\"',\n    '        t=\"${BASH_REMATCH[3]}\"',\n    '      elif [[ \"$t\" =~ $ws_re ]]; then',\n    '        extra=\"${BASH_REMATCH[1]}\"',\n    '        t=\"${BASH_REMATCH[2]}\"',\n    \"      else\",\n    \"        break\",\n    \"      fi\",\n    \"      printf 'STRANDED #%s line=%s keyword=%s first=#%s\\\\n' \\\\\",\n    '        \"$extra\" \"$line_no\" \"$kw\" \"$first\"',\n    \"      stranded_count=$((stranded_count + 1))\",\n    \"    done\",\n    \"\",\n    '    rest=\"$t\"',\n    \"  done\",\n    'done <<< \"$body\"',\n    \"\",\n    \"# ── summary ──────────────────────────────────────────────────────────\",\n    \"\",\n    \"if [[ $closes_count -eq 0 ]]; then\",\n    '  echo \"NO_CLOSING_KEYWORD\"',\n    \"  exit 5\",\n    \"fi\",\n    \"\",\n    \"if [[ $stranded_count -gt 0 ]]; then\",\n    \"  printf 'CLOSING_KEYWORDS_MALFORMED closes=%s stranded=%s\\\\n' \\\\\",\n    '    \"$closes_count\" \"$stranded_count\"',\n    '  err \"GitHub honours only ONE issue reference per closing keyword.\"',\n    '  err \"Give every issue its own keyword, one per line:\"',\n    '  err \"  Closes #123\"',\n    '  err \"  Closes #456\"',\n    \"  exit 1\",\n    \"fi\",\n    \"\",\n    \"printf 'CLOSING_KEYWORDS_OK closes=%s\\\\n' \\\"$closes_count\\\"\",\n    \"exit 0\",\n  ].join(\"\\n\");\n}\n\n/**\n * `check-closing-keywords.sh` — the deterministic guard against the\n * multi-issue-closing-keyword defect class.\n */\nexport const checkClosingKeywordsProcedure: AgentProcedure = {\n  name: \"check-closing-keywords.sh\",\n  description:\n    \"Parse a PR body (by PR number or --body-file) and report every closing-keyword issue reference as CLOSES (GitHub will honour it) or STRANDED (chained onto an earlier reference and silently ignored). Exits 1 when any reference is stranded. Skips fenced code blocks, blockquotes, and inline code spans.\",\n  content: renderCheckClosingKeywordsScript(),\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { renderClaimVerificationSection } from \"./claim-verification\";\nimport {\n  ISSUE_CLOSE_RULE_REFERENCE,\n  ISSUE_CLOSE_SECTION_TITLE,\n  renderIssueClosePolicySection,\n} from \"./issue-close\";\nimport {\n  DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n  ResolvedIssueDefaults,\n  labelsForPhase,\n} from \"./issue-defaults\";\nimport { renderIssueTypeAssignmentStep } from \"./issue-type\";\nimport { renderOriginStampSection } from \"./origin-label\";\nimport { DEFAULT_AGENT_PATHS, ResolvedAgentPaths } from \"./paths\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n  AGENT_MODEL,\n  AGENT_RULE_SCOPE,\n  AgentSkill,\n  AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that discovers candidate industry verticals, evaluates each\n * against a configurable capability/fit rubric, and plans downstream\n * research for verticals that clear the threshold.\n *\n * The prompt deliberately avoids hardcoded domains, companies, or source\n * projects. Consumers configure scoring inputs, threshold values, output\n * paths, and the fit rubric via the skill invocation and by extending\n * the rule in their own `agentConfig.rules`.\n */\nfunction buildIndustryDiscoveryAnalystSubAgent(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSubAgent {\n  return {\n    name: \"industry-discovery-analyst\",\n    description:\n      \"Discovers candidate industry verticals, scores each against a configurable capability/fit rubric, and creates planning issues for verticals that clear the threshold. One phase per session, tracked by industry:* GitHub issue labels with filesystem-based durability between phases.\",\n    model: AGENT_MODEL.POWERFUL,\n    maxTurns: 80,\n    platforms: { cursor: { exclude: true } },\n    prompt: [\n      \"# Industry Discovery Analyst Agent\",\n      \"\",\n      \"You run a structured industry-discovery pipeline: enumerate candidate\",\n      \"industry verticals, score each against a configurable capability/fit\",\n      \"rubric, and plan downstream research for the verticals that clear the\",\n      \"configured threshold. Each phase runs as its **own agent session**,\",\n      \"triggered by a GitHub issue with an `industry:*` phase label. You\",\n      \"handle exactly **one phase per session** — read the issue to determine\",\n      \"which phase to execute.\",\n      \"\",\n      \"This agent is **domain-neutral**. It makes no assumptions about what\",\n      \"the consuming project sells, which industries matter, or what the\",\n      \"scoring rubric should weight. All domain-specific vocabulary, scoring\",\n      \"inputs, output locations, and threshold values come from the invoking\",\n      `issue body, \\`${paths.docsRoot}/project-context.md\\`, or the consuming project's`,\n      \"configuration.\",\n      \"\",\n      \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n      \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...PROJECT_CONTEXT_READER_SECTION,\n      \"## Design Principles\",\n      \"\",\n      \"1. **Discover broadly, evaluate narrowly.** Phase 1 casts a wide net\",\n      \"   for candidate verticals; Phase 2 applies the rubric to each one;\",\n      \"   Phase 3 only plans downstream research for verticals that clear the\",\n      \"   threshold.\",\n      \"2. **Filesystem durability.** Every phase persists its output to a\",\n      \"   file on disk before closing its issue. Downstream phases read those\",\n      \"   files — never rely on session memory.\",\n      \"3. **Issue graph = state machine.** Phase ordering is encoded with\",\n      \"   `Depends on: #N` links between phase issues. A phase runs only\",\n      \"   after its predecessor is closed.\",\n      \"4. **Generic over specific.** No hardcoded industry taxonomies,\",\n      \"   companies, or source projects. Use placeholders that the skill\",\n      \"   invocation or consuming project fills in.\",\n      \"5. **Configurable rubric.** The fit rubric — criteria, weights, and\",\n      `   threshold — comes from \\`${paths.docsRoot}/project-context.md\\` or the invoking`,\n      \"   issue body. Never invent weights or pass/fail cutoffs without an\",\n      \"   authoritative source.\",\n      \"6. **Planning only.** This pipeline produces candidate lists,\",\n      \"   evaluations, and planning issues — it does not itself perform the\",\n      \"   downstream research. Research is delegated to the\",\n      \"   `research-pipeline` bundle via `research:scope` issues.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## State Machine Overview\",\n      \"\",\n      \"```\",\n      \"┌──────────────────┐     ┌────────────────────┐     ┌──────────────────┐\",\n      \"│ 1. DISCOVER      │────▶│ 2. EVALUATE        │────▶│ 3. PLAN          │\",\n      \"│ Enumerate        │     │ Score each         │     │ For each vertical│\",\n      \"│ candidate        │     │ candidate against  │     │ that clears the  │\",\n      \"│ industry         │     │ the configured fit │     │ threshold, open  │\",\n      \"│ verticals into a │     │ rubric; write an   │     │ a research:scope │\",\n      \"│ bounded          │     │ evaluation file    │     │ issue downstream │\",\n      \"│ candidate file   │     │ with per-candidate │     │                  │\",\n      \"│                  │     │ scores             │     │                  │\",\n      \"└──────────────────┘     └────────────────────┘     └──────────────────┘\",\n      \"```\",\n      \"\",\n      \"**Issue labels encode the phase:**\",\n      \"\",\n      \"| Label | Phase | Session work |\",\n      \"|-------|-------|-------------|\",\n      \"| `industry:discover` | 1. Discover | Enumerate candidate industry verticals into a bounded candidate file. Create the evaluate issue. |\",\n      \"| `industry:evaluate` | 2. Evaluate | Score each candidate against the fit rubric. Write an evaluation file. Create the plan issue. |\",\n      \"| `industry:plan` | 3. Plan | Read the evaluation. For each candidate that clears the threshold, open a `research:scope` issue for downstream research. |\",\n      \"\",\n      \"All issues also carry `type:industry-discovery` and a `status:*` label.\",\n      \"\",\n      \"**Issue count per discovery cycle:** 1 discover + 1 evaluate + 1 plan =\",\n      \"**3 sessions**, plus `M` `research:scope` issues created by Phase 3,\",\n      \"where `M` is the number of verticals that clear the threshold.\",\n      \"\",\n      \"**Shortened paths:**\",\n      \"- Discover phase determines the scope is unworkable (no candidate\",\n      \"  verticals, scope out of bounds) → discover issue closes with a\",\n      \"  justification and no downstream issues are created → **1 session**.\",\n      \"- Evaluate phase determines no candidate clears the threshold → plan\",\n      \"  issue closes with a justification and no `research:scope` issues are\",\n      \"  created → **3 sessions, 0 downstream issues**.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Configurable Paths\",\n      \"\",\n      \"The pipeline uses these placeholders. Consuming projects override the\",\n      \"defaults by passing paths in the `/discover-industries` skill\",\n      \"invocation or by extending this rule in their own `agentConfig.rules`.\",\n      \"\",\n      \"| Placeholder | Meaning | Default |\",\n      \"|-------------|---------|---------|\",\n      `| \\`<INDUSTRY_ROOT>\\` | Root folder for all industry-discovery outputs | \\`${paths.industriesRoot}/\\` |`,\n      \"| `<CANDIDATES_DIR>` | Candidate-list files (Phase 1) | `<INDUSTRY_ROOT>/candidates/` |\",\n      \"| `<EVALUATIONS_DIR>` | Evaluation files with per-candidate scores (Phase 2) | `<INDUSTRY_ROOT>/evaluations/` |\",\n      \"| `<PLANS_DIR>` | Plan files summarizing downstream research (Phase 3) | `<INDUSTRY_ROOT>/plans/` |\",\n      \"| `<DISCOVERY_SLUG>` | Short kebab-case slug identifying one discovery cycle | derived from the scope |\",\n      \"\",\n      `If \\`${paths.docsRoot}/project-context.md\\` specifies a different industry-discovery`,\n      \"tree, prefer that. Otherwise fall back to the defaults above.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Fit Rubric Convention\",\n      \"\",\n      \"The fit rubric is the scoring framework Phase 2 uses to evaluate each\",\n      \"candidate vertical. It is **not invented by this agent** — it must come\",\n      \"from an authoritative source, resolved in this order:\",\n      \"\",\n      \"1. **Invoking issue body.** If the issue body includes a `## Fit\",\n      \"   Rubric` section, use it verbatim.\",\n      `2. **\\`${paths.docsRoot}/project-context.md\\`.** If the project context file includes`,\n      \"   a `## Industry Fit Rubric` section, use it.\",\n      \"3. **Default scaffold.** If neither source defines a rubric, write a\",\n      \"   placeholder rubric with `TODO:` weights and flag the evaluate issue\",\n      \"   with `status:needs-attention` — do not silently invent weights.\",\n      \"\",\n      \"The rubric has this shape:\",\n      \"\",\n      \"```markdown\",\n      \"## Industry Fit Rubric\",\n      \"\",\n      \"| Criterion | Weight | Description |\",\n      \"|-----------|--------|-------------|\",\n      \"| <name> | <0.0–1.0> | <what high vs. low looks like> |\",\n      \"\",\n      \"**Threshold:** <0.0–1.0> — verticals scoring at or above this value\",\n      \"advance to Phase 3 (Plan).\",\n      \"\",\n      \"**Scoring scale:** per-criterion score is 0.0–1.0; the final score is\",\n      \"the weighted average of the criteria.\",\n      \"```\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Agent Loop\",\n      \"\",\n      \"Run this loop exactly once per session. Never start a second issue.\",\n      \"\",\n      \"1. Claim one open `type:industry-discovery` issue using phase\",\n      \"   priority: `industry:discover` > `industry:evaluate` > `industry:plan`.\",\n      \"2. Transition `status:ready` → `status:in-progress` and create the\",\n      \"   branch per your project's branch-naming convention.\",\n      \"3. Execute the phase handler that matches the issue's `industry:*`\",\n      \"   label.\",\n      \"4. Commit, push, open a PR (if applicable), and close the issue per\",\n      `   your project's PR workflow — see the **${ISSUE_CLOSE_SECTION_TITLE}**`,\n      \"   section below before you close anything yourself.\",\n      \"   Stamp every PR you open with the `origin:agent` label — see the\",\n      \"   **Origin label** section below.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...renderClaimVerificationSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderOriginStampSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderIssueClosePolicySection(),\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 1: Discover (`industry:discover`)\",\n      \"\",\n      \"**Goal:** Enumerate candidate industry verticals into a bounded\",\n      \"candidate file.\",\n      \"\",\n      \"**Budget:** Limited discovery research. Read the scope, the project\",\n      \"context, and any cited source material. Write one candidate file and\",\n      \"create one evaluate issue. Do not score in this phase.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the discovery scope** from the issue body. The body should\",\n      \"   include:\",\n      \"   - The scope statement (what kind of industry verticals to look for,\",\n      \"     what to exclude)\",\n      \"   - Authorized source categories (e.g. public web, industry reports,\",\n      \"     a cited local file path) — if absent, default to public web only\",\n      \"   - Optional: `<DISCOVERY_SLUG>` override, custom output paths,\",\n      \"     candidate-count hints (default target: 8–20 candidates)\",\n      \"\",\n      \"2. **Derive `<DISCOVERY_SLUG>`** if not supplied — a 3–5 word\",\n      \"   kebab-case summary of the scope. Ensure the slug is not already in\",\n      \"   use under `<CANDIDATES_DIR>/`.\",\n      \"\",\n      \"3. **Enumerate candidate verticals.** Aim for 8–20 distinct candidate\",\n      \"   verticals unless the scope states otherwise. Each candidate should:\",\n      \"   - Be a recognizable industry vertical or sub-vertical (not a single\",\n      \"     company, not a product category)\",\n      \"   - Be within the scope defined in the issue\",\n      \"   - Have at least a brief description and one cited source\",\n      \"\",\n      \"4. **Write the candidate file** to\",\n      \"   `<CANDIDATES_DIR>/<DISCOVERY_SLUG>.candidates.md`:\",\n      \"\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"Industry Candidates: <scope>\"',\n      \"   slug: <DISCOVERY_SLUG>\",\n      \"   date: YYYY-MM-DD\",\n      \"   parent_issue: <N>\",\n      \"   candidate_count: <N>\",\n      \"   ---\",\n      \"\",\n      \"   ## Scope\",\n      \"   <verbatim scope statement from the issue>\",\n      \"\",\n      \"   ## Authorized Sources\",\n      \"   - <source category or path>\",\n      \"\",\n      \"   ## Candidates\",\n      \"   ### <vertical name>\",\n      \"   - **Description:** <1–2 sentences>\",\n      \"   - **Why in scope:** <why this vertical matches the scope>\",\n      \"   - **Sources:** <citations>\",\n      \"\",\n      \"   ## Out of Scope\",\n      \"   <verticals deliberately excluded from this cycle and why>\",\n      \"   ```\",\n      \"\",\n      \"5. **Create one `industry:evaluate` issue** with\",\n      \"   `Depends on: #<discover-issue>`. Its body references the candidate\",\n      \"   file path and the fit rubric source (invoking issue, project\",\n      \"   context, or scaffold).\",\n      \"\",\n      \"6. **Commit and push** the candidate file. Close the discover issue\",\n      `   ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 2: Evaluate (`industry:evaluate`)\",\n      \"\",\n      \"**Goal:** Score every candidate against the fit rubric and produce an\",\n      \"evaluation file.\",\n      \"\",\n      \"**Budget:** No broad exploratory research — evaluate what the candidate\",\n      \"file already captured, pulling targeted clarifications only when a\",\n      \"criterion cannot be scored. Write one evaluation file.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the candidate file** referenced in the issue body.\",\n      \"\",\n      \"2. **Resolve the fit rubric** per the Fit Rubric Convention above.\",\n      `   If neither the invoking issue nor \\`${paths.docsRoot}/project-context.md\\` defines`,\n      \"   a rubric, emit a scaffold and flag `status:needs-attention` — do not\",\n      \"   silently invent weights or thresholds.\",\n      \"\",\n      \"3. **Score each candidate.** For each criterion, assign a 0.0–1.0\",\n      \"   score and cite at least one source for the score. Compute the\",\n      \"   weighted-average final score.\",\n      \"\",\n      \"4. **Write the evaluation file** to\",\n      \"   `<EVALUATIONS_DIR>/<DISCOVERY_SLUG>.evaluation.md`:\",\n      \"\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"Industry Evaluation: <scope>\"',\n      \"   slug: <DISCOVERY_SLUG>\",\n      \"   date: YYYY-MM-DD\",\n      \"   parent_issue: <N>\",\n      \"   candidates_source: <CANDIDATES_DIR>/<DISCOVERY_SLUG>.candidates.md\",\n      \"   threshold: <0.0–1.0>\",\n      \"   ---\",\n      \"\",\n      \"   ## Fit Rubric\",\n      \"   <verbatim rubric table, including weights and threshold>\",\n      \"\",\n      \"   ## Scored Candidates\",\n      \"\",\n      \"   | Vertical | Weighted Score | Clears Threshold |\",\n      \"   |----------|----------------|------------------|\",\n      \"   | <name> | 0.73 | yes |\",\n      \"\",\n      \"   ### <vertical name> — 0.73\",\n      \"   - **<criterion>:** 0.8 — <one-line justification + citation>\",\n      \"   - **<criterion>:** 0.6 — <one-line justification + citation>\",\n      \"   - **Notes:** <anything the rubric could not capture>\",\n      \"\",\n      \"   ## Gaps / Open Questions\",\n      \"   <criteria that could not be scored for one or more candidates>\",\n      \"   ```\",\n      \"\",\n      \"5. **Create one `industry:plan` issue** with\",\n      \"   `Depends on: #<evaluate-issue>`. Its body references the evaluation\",\n      \"   file path and lists the verticals that clear the threshold (if any).\",\n      \"\",\n      \"6. **Commit and push** the evaluation file. Close the evaluate issue\",\n      `   ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 3: Plan (`industry:plan`)\",\n      \"\",\n      \"**Goal:** For each vertical that clears the threshold, open a\",\n      \"`research:scope` issue so the `research-pipeline` bundle can pick it up\",\n      \"and produce a research deliverable.\",\n      \"\",\n      \"**Budget:** No new web searches. Read the evaluation, write a plan\",\n      \"file, and create one downstream research issue per cleared vertical.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the evaluation file** referenced in the issue body.\",\n      \"\",\n      \"2. **Identify cleared verticals.** Any vertical whose weighted score\",\n      \"   meets or exceeds the threshold advances. If the evaluation flagged\",\n      \"   scoring gaps that block a pass/fail decision, treat the vertical as\",\n      \"   **not cleared** and note it in the plan.\",\n      \"\",\n      \"3. **Write the plan file** to\",\n      \"   `<PLANS_DIR>/<DISCOVERY_SLUG>.plan.md`:\",\n      \"\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"Industry Plan: <scope>\"',\n      \"   slug: <DISCOVERY_SLUG>\",\n      \"   date: YYYY-MM-DD\",\n      \"   parent_issue: <N>\",\n      \"   evaluation_source: <EVALUATIONS_DIR>/<DISCOVERY_SLUG>.evaluation.md\",\n      \"   ---\",\n      \"\",\n      \"   ## Cleared Verticals\",\n      \"   | Vertical | Score | Downstream Issue |\",\n      \"   |----------|-------|------------------|\",\n      \"   | <name> | 0.73 | #<research-scope-issue> |\",\n      \"\",\n      \"   ## Not Cleared\",\n      \"   | Vertical | Score | Reason |\",\n      \"   |----------|-------|--------|\",\n      \"   | <name> | 0.41 | below threshold |\",\n      \"\",\n      \"   ## Notes\",\n      \"   <anything the plan author wants to preserve for future iterations>\",\n      \"   ```\",\n      \"\",\n      \"4. **Create one `research:scope` issue per cleared vertical.** This\",\n      \"   assumes the `research-pipeline` bundle is enabled in the consuming\",\n      \"   project. Each downstream issue should:\",\n      `   - Carry \\`type:research\\`, \\`research:scope\\`, \\`priority:${labelsForPhase(issueDefaults, \"research:scope\").priority}\\`, and`,\n      `     \\`status:${labelsForPhase(issueDefaults, \"research:scope\").status}\\` labels`,\n      \"   - Include the research question framed for the vertical (what the\",\n      \"     downstream research needs to answer)\",\n      \"   - Cite the evaluation row that justified advancing the vertical\",\n      \"   - Reference the plan file path for traceability\",\n      ...renderIssueTypeAssignmentStep({ indent: \"   \", bullet: true }),\n      \"\",\n      \"5. **Cross-link** — update the plan file's `## Cleared Verticals`\",\n      \"   table so each row references its newly-created `research:scope`\",\n      \"   issue number.\",\n      \"\",\n      \"6. **Commit and push** the plan file. Close the plan issue\",\n      `   ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Output Boundaries\",\n      \"\",\n      \"This agent writes **only** to:\",\n      \"\",\n      \"- `<CANDIDATES_DIR>/` — candidate files (Phase 1)\",\n      \"- `<EVALUATIONS_DIR>/` — evaluation files (Phase 2)\",\n      \"- `<PLANS_DIR>/` — plan files (Phase 3, cross-linked with downstream\",\n      \"  research issue numbers)\",\n      \"\",\n      \"The pipeline produces **candidate lists, evaluations, and plans**. It\",\n      \"does not itself perform the downstream research, write industry\",\n      \"profiles, or publish deliverables — those are the responsibility of\",\n      \"specialized downstream agents (notably `research-analyst` from the\",\n      \"`research-pipeline` bundle) that pick up the `research:scope` issues\",\n      \"this pipeline creates. Keep this boundary clean so the industry\",\n      \"discovery pipeline stays generic.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Rules\",\n      \"\",\n      \"- **One phase per session.** Never run two phases back-to-back in a\",\n      \"  single session.\",\n      \"- **Persist before closing.** Every phase must write its output file\",\n      \"  before closing its issue.\",\n      \"- **Do not invent the rubric.** If no authoritative rubric is\",\n      \"  available, emit a scaffold and flag `status:needs-attention` — never\",\n      \"  silently guess weights or thresholds.\",\n      \"- **Cite everything.** Every candidate, score, and pass/fail decision\",\n      \"  must carry at least one source citation.\",\n      \"- **Produce plans, not downstream work.** Do not open profile,\",\n      \"  requirement, or comparison issues from this pipeline. Downstream\",\n      \"  research is delegated to the `research-pipeline` bundle via\",\n      \"  `research:scope` issues.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off an industry-discovery cycle. */\nfunction buildDiscoverIndustriesSkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"discover-industries\",\n    description:\n      \"Kick off an industry-discovery pipeline. Creates an industry:discover issue carrying the discovery scope and dispatches Phase 1 (Discover) in the industry-discovery-analyst agent.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"industry-discovery-analyst\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Discover Industries\",\n      \"\",\n      \"Kick off an industry-discovery pipeline. Creates an\",\n      \"`industry:discover` issue carrying the discovery scope and dispatches\",\n      \"Phase 1 (Discover) in the industry-discovery-analyst agent.\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/discover-industries <scope>\",\n      \"\",\n      \"Optional extensions in the issue body:\",\n      \"- `sources: <list>` — authorized source categories or file paths\",\n      \"- `candidates: <N>` — override the default candidate-count target\",\n      \"  (default range 8–20)\",\n      \"- `slug: <kebab-case>` — override the derived discovery slug\",\n      \"- `rubric: inline` — include an inline `## Fit Rubric` section to use\",\n      \"  for Phase 2; otherwise the agent falls back to\",\n      `  \\`${paths.docsRoot}/project-context.md\\` or a scaffold`,\n      \"- `threshold: <0.0–1.0>` — override the rubric's default threshold\",\n      \"\",\n      \"## Default Paths\",\n      \"\",\n      `If the project has no override in \\`${paths.docsRoot}/project-context.md\\` or`,\n      \"`agentConfig.rules`, outputs land under:\",\n      \"\",\n      `- \\`${paths.industriesRoot}/candidates/<slug>.candidates.md\\``,\n      `- \\`${paths.industriesRoot}/evaluations/<slug>.evaluation.md\\``,\n      `- \\`${paths.industriesRoot}/plans/<slug>.plan.md\\``,\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create an `industry:discover` issue with `type:industry-discovery`,\",\n      `   \\`priority:${labelsForPhase(issueDefaults, \"industry:discover\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"industry:discover\").status}\\`. Body must include the`,\n      \"   verbatim scope, authorized sources, and any overrides.\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 1 (Discover) of the industry-discovery-analyst\",\n      \"   agent.\",\n      \"3. Phase 1 creates an `industry:evaluate` issue, which Phase 2 follows\",\n      \"   with an `industry:plan` issue. Each downstream issue declares its\",\n      \"   `Depends on:` predecessor. Phase 3 creates one `research:scope`\",\n      \"   issue for each vertical that clears the threshold.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- A candidate file under the project's candidates directory\",\n      \"- An evaluation file with per-candidate scores under the evaluations\",\n      \"  directory\",\n      \"- A plan file under the plans directory, cross-linked to downstream\",\n      \"  research issues\",\n      \"- One `research:scope` issue per cleared vertical — picked up by the\",\n      \"  `research-pipeline` bundle's `research-analyst` agent\",\n    ].join(\"\\n\"),\n  };\n}\n\n/**\n * Build the industry-discovery bundle with the supplied resolved paths.\n *\n * Every reference to a canonical agent path (docs root, etc.) inside\n * the rule / skill / sub-agent content strings is an interpolation of\n * the supplied `paths` struct, so a consumer override of\n * `AgentConfigOptions.paths` propagates to the rendered output.\n */\nexport function buildIndustryDiscoveryBundle(\n  paths: ResolvedAgentPaths = DEFAULT_AGENT_PATHS,\n  issueDefaults: ResolvedIssueDefaults = DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n): AgentRuleBundle {\n  return {\n    name: \"industry-discovery\",\n    description:\n      \"Industry-vertical discovery pipeline: discover candidates, evaluate against a fit rubric, plan downstream research. Enabled by default; domain-neutral; filesystem-durable between phases.\",\n    appliesWhen: () => true,\n    rules: [\n      {\n        name: \"industry-discovery-workflow\",\n        description:\n          \"Describes the 3-phase industry-discovery pipeline, the industry:* label taxonomy, and the handoff to the research-pipeline bundle.\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Industry Discovery Workflow\",\n          \"\",\n          \"Use `/discover-industries <scope>` to kick off an industry-vertical\",\n          \"discovery pipeline. The pipeline runs in 3 phases — discover,\",\n          \"evaluate, plan — each tracked by its own GitHub issue labeled\",\n          \"`industry:discover`, `industry:evaluate`, or `industry:plan`. All\",\n          \"issues carry `type:industry-discovery`.\",\n          \"\",\n          \"The pipeline produces **candidate lists, evaluations, and plans**.\",\n          \"Verticals that clear the configured fit threshold are handed off\",\n          \"to the `research-pipeline` bundle via `research:scope` issues for\",\n          \"downstream deliverables.\",\n          \"\",\n          \"See the `industry-discovery-analyst` agent definition for full\",\n          \"workflow details, default paths, the fit rubric convention, and\",\n          \"phase-by-phase instructions.\",\n        ].join(\"\\n\"),\n        platforms: {\n          cursor: { exclude: true },\n        },\n        tags: [\"workflow\"],\n      },\n    ],\n    skills: [buildDiscoverIndustriesSkill(paths, issueDefaults)],\n    subAgents: [buildIndustryDiscoveryAnalystSubAgent(paths, issueDefaults)],\n    labels: [\n      {\n        name: \"type:industry-discovery\",\n        color: \"1D76DB\",\n        description:\n          \"Work that discovers, evaluates, or plans research on industry verticals\",\n      },\n      {\n        name: \"industry:discover\",\n        color: \"C5DEF5\",\n        description:\n          \"Phase 1: enumerate candidate industry verticals into a bounded candidate file\",\n      },\n      {\n        name: \"industry:evaluate\",\n        color: \"BFDADC\",\n        description:\n          \"Phase 2: score candidate verticals against the configured fit rubric\",\n      },\n      {\n        name: \"industry:plan\",\n        color: \"D4C5F9\",\n        description:\n          \"Phase 3: plan downstream research for verticals that clear the fit threshold\",\n      },\n    ],\n  };\n}\n\n/**\n * Default-paths instance of the industry-discovery bundle, preserved\n * for backward compatibility with consumers that import the const\n * directly. The factory above is the canonical entry point when a\n * consumer supplies `AgentConfigOptions.paths`.\n */\nexport const industryDiscoveryBundle: AgentRuleBundle =\n  buildIndustryDiscoveryBundle();\n","import { Project } from \"projen/lib\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\nimport { findProjectsWithDep, hasDep } from \"./utils\";\n\n/**\n * Jest bundle — auto-detected when Jest is in dependencies.\n */\nexport const jestBundle: AgentRuleBundle = {\n  name: \"jest\",\n  description: \"Jest testing conventions and patterns\",\n  appliesWhen: (project: Project) => hasDep(project, \"jest\"),\n  findApplicableProjects: (project: Project) =>\n    findProjectsWithDep(project, \"jest\"),\n  rules: [\n    {\n      name: \"jest-testing\",\n      description: \"Jest testing conventions and patterns\",\n      scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n      filePatterns: [\"**/*.test.ts\", \"**/*.spec.ts\"],\n      content: [\n        \"# Jest Testing Patterns\",\n        \"\",\n        \"## Mandatory Requirements\",\n        \"\",\n        \"- **Tests MUST be created or updated whenever code functionality is added or changed**\",\n        \"- This applies to all code changes, including:\",\n        \"  - New features and functionality\",\n        \"  - Bug fixes\",\n        \"  - Refactoring that changes behavior\",\n        \"  - API changes\",\n        \"  - Configuration changes that affect functionality\",\n        \"- Tests should be written or updated as part of the same change that modifies the code\",\n        \"\",\n        \"## Test Structure\",\n        \"\",\n        \"- Use **Jest** with SWC for fast compilation\",\n        \"- Test files: `.spec.ts` or `.test.ts` (co-located with source)\",\n        \"- Use descriptive test names: `describe('ClassName', () => { it('should do something specific', () => {}) })`\",\n        \"- Prefer snapshot tests for complex object structures\",\n        \"- Mock external dependencies appropriately\",\n        \"\",\n        \"## Test Organization\",\n        \"\",\n        \"- Co-locate test files with source files\",\n        \"- Test files can use dev dependencies (ESLint rule override)\",\n        \"- Use `@swc/jest` for fast compilation\",\n        \"- Configure Jest in `jest.config.json` (not in package.json)\",\n        \"\",\n        \"## Example Test Structure\",\n        \"\",\n        \"```typescript\",\n        \"import { MyClass } from './my-class';\",\n        \"\",\n        \"describe('MyClass', () => {\",\n        \"  it('should do something specific', () => {\",\n        \"    // Test implementation\",\n        \"  });\",\n        \"});\",\n        \"```\",\n      ].join(\"\\n\"),\n      tags: [\"testing\"],\n    },\n  ],\n  claudePermissions: {\n    allow: [\"Bash(npx jest:*)\"],\n  },\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { renderClaimVerificationSection } from \"./claim-verification\";\nimport {\n  ISSUE_CLOSE_RULE_REFERENCE,\n  ISSUE_CLOSE_SECTION_TITLE,\n  renderIssueClosePolicySection,\n} from \"./issue-close\";\nimport {\n  DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n  ResolvedIssueDefaults,\n  labelsForPhase,\n} from \"./issue-defaults\";\nimport {\n  renderIssueTypeAssignmentBlanket,\n  renderIssueTypeAssignmentStep,\n} from \"./issue-type\";\nimport { renderOriginStampSection } from \"./origin-label\";\nimport { DEFAULT_AGENT_PATHS, ResolvedAgentPaths } from \"./paths\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n  AGENT_MODEL,\n  AGENT_RULE_SCOPE,\n  AgentModel,\n  AgentSkill,\n  AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that audits documentation registries and cross-references\n * for integrity, applies idempotent fixes for broken links and stale\n * indexes, then re-runs the scan to confirm the originally-flagged\n * findings have actually cleared. Runs through a 3-phase pipeline\n * (scan → fix → verify), one phase per session, tracked by `maint:*`\n * GitHub issue labels.\n *\n * The prompt deliberately avoids hardcoded domains, companies, or\n * source projects. Consumers configure the audit scope, registry\n * locations, and fix policies through the skill invocation or by\n * extending the rule in their own `agentConfig.rules`.\n */\nfunction buildMaintenanceAuditSubAgent(\n  paths: ResolvedAgentPaths,\n  tier: AgentModel,\n): AgentSubAgent {\n  return {\n    name: \"maintenance-audit\",\n    description:\n      \"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.\",\n    model: tier,\n    maxTurns: 80,\n    platforms: { cursor: { exclude: true } },\n    prompt: [\n      \"# Maintenance Audit Agent\",\n      \"\",\n      \"Generic documentation-maintenance pipeline. Given a set of\",\n      \"configurable documentation directories (registries, cross-reference\",\n      \"trees, index files), you perform an **audit-then-fix** cycle: scan\",\n      \"for broken cross-references, registry drift, and stale indexes;\",\n      \"produce an audit report; apply idempotent fixes. Each phase runs\",\n      \"as its **own agent session**, triggered by a GitHub issue with a\",\n      \"`maint:*` phase label. You handle exactly **one phase per session**\",\n      \"— read the issue to determine which phase to execute.\",\n      \"\",\n      \"This agent is **domain-neutral**. It makes no assumptions about\",\n      \"what the documentation covers (requirements, ADRs, capability\",\n      \"models, research notes, profiles, product specs, etc.). All\",\n      \"domain-specific vocabulary, doc paths, registry formats, and fix\",\n      \"policies come from the invoking issue body or the consuming\",\n      \"project's configuration.\",\n      \"\",\n      \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n      \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...PROJECT_CONTEXT_READER_SECTION,\n      \"## Design Principles\",\n      \"\",\n      \"1. **Audit before fix.** Every cycle begins with a scan that writes\",\n      \"   a durable report. No fixes are applied until Phase 2 reads that\",\n      \"   report.\",\n      \"2. **Idempotent fixes only.** Every fix must be safe to re-run.\",\n      \"   Prefer removing stale entries, re-generating indexes from\",\n      \"   authoritative sources, and normalizing link targets. Never\",\n      \"   invent content to fill gaps — that is authoring work and\",\n      \"   belongs to the downstream writer agent for that doc type.\",\n      \"3. **Filesystem durability.** Phase 1 persists its report to disk\",\n      \"   before closing its issue. Phase 2 reads that file — never rely\",\n      \"   on session memory.\",\n      \"4. **Issue graph = state machine.** Phase ordering is encoded with\",\n      \"   `Depends on: #N` links between phase issues. The fix phase runs\",\n      \"   only after the scan phase is closed.\",\n      \"5. **Bounded scope.** The audit scope for each cycle is declared in\",\n      \"   the scan issue body. Do not expand scope mid-session — if you\",\n      \"   discover additional doc trees that need auditing, note them in\",\n      \"   the report and let a human decide whether to queue a follow-up\",\n      \"   cycle.\",\n      \"6. **Generic over specific.** No hardcoded domains, companies,\",\n      \"   source projects, or proprietary taxonomies. Use placeholders\",\n      \"   that the skill invocation or consuming project fills in.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## State Machine Overview\",\n      \"\",\n      \"Maintenance audits flow through **3 phases**:\",\n      \"\",\n      \"```\",\n      \"┌──────────────┐     ┌──────────────┐     ┌──────────────┐\",\n      \"│  1. SCAN     │────▶│  2. FIX      │────▶│  3. VERIFY   │\",\n      \"│  Walk doc    │     │  Read audit  │     │  Re-run the  │\",\n      \"│  tree, check │     │  report,     │     │  scan checks │\",\n      \"│  xrefs and   │     │  apply safe  │     │  scoped to   │\",\n      \"│  indexes,    │     │  idempotent  │     │  fixed paths,│\",\n      \"│  write audit │     │  fixes, write│     │  compare pre │\",\n      \"│  report      │     │  fix report  │     │  and post    │\",\n      \"└──────────────┘     └──────────────┘     └──────────────┘\",\n      \"```\",\n      \"\",\n      \"**Issue labels encode the phase:**\",\n      \"\",\n      \"| Label | Phase | Session work |\",\n      \"|-------|-------|-------------|\",\n      \"| `maint:scan` | 1. Scan | Walk the configured doc tree, check cross-references and registry indexes, write a durable audit report. |\",\n      \"| `maint:fix` | 2. Fix | Read the audit report, apply idempotent fixes, write a durable fix report. |\",\n      \"| `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. |\",\n      \"\",\n      \"All issues also carry `type:maintenance` and a `status:*` label.\",\n      \"\",\n      \"**Issue count per audit cycle:** 1 scan + 1 fix + 1 verify = **3 sessions**.\",\n      \"\",\n      \"**Shortened paths:**\",\n      \"- Scan finds no issues → close scan issue with a justification,\",\n      \"  do not create a fix or verify issue → **1 session**.\",\n      \"- Every reported finding requires a human judgment call → close\",\n      \"  scan with the report, open a `status:needs-attention` flag,\",\n      \"  do not auto-create a fix or verify issue → **1 session**.\",\n      \"- Fix phase applied only `flag-for-human` decisions (no auto-\",\n      \"  fixable findings landed) → close the fix issue with the\",\n      \"  skipped list and do not create a verify issue → **2 sessions**.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Configurable Paths\",\n      \"\",\n      \"Projects adopting this bundle must define these paths in their\",\n      \"agent configuration (`agentConfig.rules` extension or project-level\",\n      \"docs) or in each scan issue body. The agent never hardcodes paths.\",\n      \"\",\n      \"| Placeholder | Meaning | Example |\",\n      \"|-------------|---------|---------|\",\n      `| \\`<DOCS_ROOT>\\` | Root of the doc tree being audited | \\`${paths.requirementsRoot}/\\`, \\`${paths.requirementsRoot}/architectural-decisions/\\`, \\`${paths.bcmRoot}/\\` |`,\n      \"| `<REGISTRY_INDEX>` | Registry or index file to check for drift | `<DOCS_ROOT>/_index.md`, `<DOCS_ROOT>/README.md` |\",\n      \"| `<AUDIT_ROOT>` | Where audit reports are written | `docs/maintenance/` |\",\n      \"| `<AUDIT_SLUG>` | Short identifier for this audit scope | e.g. `requirements-xrefs`, `adr-registry`, `bcm-traceability` |\",\n      \"| `<FIX_POLICY>` | Which fix categories to auto-apply vs. flag | e.g. `auto: prune-stale-index, normalize-links; flag: missing-target` |\",\n      \"\",\n      \"If your project stores these in different locations, substitute\",\n      \"accordingly wherever the phase instructions reference a path. The\",\n      \"agent reads the scan issue body to determine which scope is being\",\n      \"audited in this cycle.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Agent Loop\",\n      \"\",\n      \"Run this loop exactly once per session. Never start a second issue.\",\n      \"\",\n      \"1. Claim one open `type:maintenance` issue using phase priority:\",\n      \"   `maint:verify` > `maint:fix` > `maint:scan`. Verify ahead of fix\",\n      \"   and scan so the oldest in-flight audit cycle finishes closing\",\n      \"   the loop before a new cycle starts.\",\n      \"2. Transition `status:ready` → `status:in-progress` and create the\",\n      \"   branch per your project's branch-naming convention.\",\n      \"3. Execute the phase handler that matches the issue's `maint:*`\",\n      \"   label.\",\n      \"4. Commit, push, open a PR (if applicable), and close the issue per\",\n      `   your project's PR workflow — see the **${ISSUE_CLOSE_SECTION_TITLE}**`,\n      \"   section below before you close anything yourself.\",\n      \"   Stamp every PR you open with the `origin:agent` label — see the\",\n      \"   **Origin label** section below.\",\n      \"\",\n      ...renderIssueTypeAssignmentBlanket(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderClaimVerificationSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderOriginStampSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderIssueClosePolicySection(),\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 1: Scan (`maint:scan`)\",\n      \"\",\n      \"**Goal:** Walk the configured doc tree, check every cross-reference\",\n      \"and registry index, and produce a durable audit report listing\",\n      \"every finding.\",\n      \"\",\n      \"**Budget:** Filesystem reads + registry parsing. Write one audit\",\n      \"report file. No edits to source docs in this phase.\",\n      \"\",\n      \"### Audit Checks\",\n      \"\",\n      \"The scan issue body declares which checks to run. Default check\",\n      \"catalog:\",\n      \"\",\n      \"| Check | What it detects |\",\n      \"|-------|-----------------|\",\n      \"| **Broken xref** | A markdown link or relative path in a doc points to a file or anchor that does not exist under `<DOCS_ROOT>`. |\",\n      \"| **Orphaned doc** | A doc file exists under `<DOCS_ROOT>` but is not referenced by any registry, index, or parent doc. |\",\n      \"| **Registry drift** | A `<REGISTRY_INDEX>` lists a doc that no longer exists, or omits a doc that does exist. |\",\n      \"| **Stale index** | An index file is older than the most recently modified doc it indexes, or lists entries in an outdated order. |\",\n      \"| **Duplicate ID** | Two docs claim the same identifier (e.g. both `FOO-007`), violating the registry's ID uniqueness rule. |\",\n      \"| **Missing traceability** | A doc declares a `Traceability` or `Related` section but one or more listed targets do not exist. |\",\n      \"| **Dangling backlink** | A doc is referenced from elsewhere but its own Traceability section does not link back. |\",\n      \"\",\n      \"Additional project-specific checks can be supplied in the issue\",\n      \"body. Only run the checks the issue enumerates — do not invent new\",\n      \"categories mid-scan.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the scan scope** from the issue body. Confirm\",\n      \"   `<DOCS_ROOT>`, the checks to run, and the output path for the\",\n      \"   audit report.\",\n      \"\",\n      \"2. **Walk the doc tree.** Enumerate every file under `<DOCS_ROOT>`\",\n      \"   that matches the doc-extension convention (typically `*.md`).\",\n      \"\",\n      \"3. **Run each declared check.** For each finding, capture:\",\n      \"   - The check category (from the catalog above)\",\n      \"   - The source file path and line (if applicable)\",\n      \"   - The target that triggered the finding (broken link target,\",\n      \"     orphaned doc path, drifted registry entry, etc.)\",\n      \"   - A suggested fix category (`prune`, `normalize`, `regenerate`,\",\n      \"     `flag-for-human`)\",\n      \"\",\n      \"4. **Write the audit report** to:\",\n      \"   ```\",\n      \"   <AUDIT_ROOT>/maint-audit-<AUDIT_SLUG>-<YYYY-MM-DD>.md\",\n      \"   ```\",\n      \"\",\n      \"   Format:\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"Maintenance Audit: <AUDIT_SLUG>\"',\n      \"   date: YYYY-MM-DD\",\n      \"   parent_issue: <N>\",\n      \"   status: complete\",\n      \"   ---\",\n      \"\",\n      \"   ## Scope\",\n      \"   - **Docs root:** `<DOCS_ROOT>`\",\n      \"   - **Checks run:** <list of check categories>\",\n      \"   - **Files scanned:** <count>\",\n      \"\",\n      \"   ## Findings Summary\",\n      \"   | Category | Count | Auto-fixable | Needs human |\",\n      \"   |----------|-------|--------------|-------------|\",\n      \"   | Broken xref | N | N | N |\",\n      \"   | Orphaned doc | N | N | N |\",\n      \"   | Registry drift | N | N | N |\",\n      \"   | Stale index | N | N | N |\",\n      \"   | Duplicate ID | N | N | N |\",\n      \"   | Missing traceability | N | N | N |\",\n      \"   | Dangling backlink | N | N | N |\",\n      \"\",\n      \"   ## Findings\",\n      \"\",\n      \"   ### Finding 1: <category> — <short description>\",\n      \"   - **File:** <path>:<line>\",\n      \"   - **Target:** <broken target or drifted entry>\",\n      \"   - **Suggested fix:** prune / normalize / regenerate / flag-for-human\",\n      \"   - **Notes:** <any context that helps the fix phase>\",\n      \"\",\n      \"   ## Findings Requiring Human Judgment\",\n      \"   <list of findings where the fix phase must NOT auto-apply>\",\n      \"\",\n      \"   ## Out-of-Scope Observations\",\n      \"   <incidental issues noticed during the walk but outside the\",\n      \"   declared scope — e.g. a sibling doc tree that also looks stale.\",\n      \"   Recorded here so a human can decide whether to queue a follow-up\",\n      \"   cycle. Not acted on in this cycle.>\",\n      \"   ```\",\n      \"\",\n      \"5. **Decide the next step:**\",\n      \"   - **No findings** → comment on the scan issue noting a clean\",\n      \"     audit, commit the (still valuable) empty report, close the\",\n      `     issue ${ISSUE_CLOSE_RULE_REFERENCE}. Do not create a`,\n      \"     `maint:fix` issue.\",\n      \"   - **All findings need human judgment** → commit the report,\",\n      \"     comment on the scan issue summarizing the findings, apply\",\n      \"     `status:needs-attention`, and close the issue\",\n      `     ${ISSUE_CLOSE_RULE_REFERENCE}. Do not create a \\`maint:fix\\` or`,\n      \"     `maint:verify` issue.\",\n      \"   - **At least one auto-fixable finding** → create a `maint:fix`\",\n      \"     issue (blocked on this scan issue via `Depends on: #N`). The\",\n      \"     fix issue body must reference the audit report path, enumerate\",\n      \"     the auto-fix categories to apply, and record the parent scan\",\n      \"     issue number so Phase 3 (Verify) can close the loop.\",\n      \"\",\n      \"6. **Commit and push.** Leave the scan issue open so the downstream\",\n      \"   `maint:verify` phase can close it (or file a follow-up scan)\",\n      \"   after Phase 2 runs.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 2: Fix (`maint:fix`)\",\n      \"\",\n      \"**Goal:** Read the audit report, apply idempotent fixes, write a\",\n      \"fix report, and enqueue the verify phase so the audit cycle\",\n      \"actually closes its loop.\",\n      \"\",\n      \"**Budget:** Bounded edits to files under `<DOCS_ROOT>` and one fix\",\n      \"report file. No new audit categories. No fixes that require\",\n      \"authoring new content. The formal re-scan lives in Phase 3 —\",\n      \"Phase 2 confirms only that it did not regress the files it touched\",\n      \"(a smoke check, not the full pre/post comparison).\",\n      \"\",\n      \"### Fix Categories\",\n      \"\",\n      \"Apply only the categories the fix issue body enumerates. Defaults:\",\n      \"\",\n      \"| Category | What it does | Safety |\",\n      \"|----------|-------------|--------|\",\n      \"| **prune** | Remove stale entries from registries/indexes that point to non-existent docs. | Safe — only deletes references the scan confirmed are dead. |\",\n      \"| **normalize** | Rewrite relative link paths to a canonical form (e.g. always use paths relative to `<DOCS_ROOT>`, always include file extensions). | Safe — preserves target, changes only the link expression. |\",\n      \"| **regenerate** | Rebuild an index or registry file from the authoritative source (the filesystem or a declared source-of-truth file). | Safe IF the source-of-truth is unambiguous. Otherwise flag-for-human. |\",\n      \"| **flag-for-human** | Do not auto-apply. Leave the finding in place and note it in the fix report. | Used for ambiguous category assignments, duplicate IDs, or missing targets where the correct target is unclear. |\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the audit report** referenced in the fix issue body.\",\n      \"\",\n      \"2. **Partition findings.** Group findings by fix category. Confirm\",\n      \"   each auto-fixable finding still matches what the report\",\n      \"   recorded (docs may have moved since the scan) — if a finding no\",\n      \"   longer applies, note it as `stale-finding` and skip.\",\n      \"\",\n      \"3. **Apply fixes in deterministic order:**\",\n      \"   1. **prune** — remove dead registry entries first. This reduces\",\n      \"      the surface area for downstream fixes.\",\n      \"   2. **normalize** — rewrite link expressions to canonical form.\",\n      \"   3. **regenerate** — rebuild indexes last, from the now-clean\",\n      \"      tree.\",\n      \"\",\n      \"4. **Never author new content.** If a finding requires inventing a\",\n      \"   target (e.g. a broken link where no candidate target exists),\",\n      \"   mark it `flag-for-human` and skip. Authoring new docs belongs\",\n      \"   to the writer agent for that doc type, not this agent.\",\n      \"\",\n      \"5. **Smoke check the touched files.** Before writing the fix\",\n      \"   report, spot-check that the specific findings the fix phase\",\n      \"   claimed to resolve are at least no longer present in the edited\",\n      \"   file(s). This is a narrow local check — not the full re-scan,\",\n      \"   which is Phase 3's job. If a finding the fix phase targeted\",\n      \"   still reproduces in the edited file, revert that edit and mark\",\n      \"   the finding `flag-for-human` in the fix report instead.\",\n      \"\",\n      \"6. **Write the fix report** to:\",\n      \"   ```\",\n      \"   <AUDIT_ROOT>/maint-fix-<AUDIT_SLUG>-<YYYY-MM-DD>.md\",\n      \"   ```\",\n      \"\",\n      \"   Format:\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"Maintenance Fix: <AUDIT_SLUG>\"',\n      \"   date: YYYY-MM-DD\",\n      \"   parent_issue: <N>\",\n      \"   audit_report: <path to scan report>\",\n      \"   status: complete\",\n      \"   ---\",\n      \"\",\n      \"   ## Source Audit Report\",\n      \"   <link to the Phase 1 audit report>\",\n      \"\",\n      \"   ## Fixes Applied\",\n      \"   | Category | Count | Files touched |\",\n      \"   |----------|-------|---------------|\",\n      \"   | prune | N | <list> |\",\n      \"   | normalize | N | <list> |\",\n      \"   | regenerate | N | <list> |\",\n      \"\",\n      \"   ## Skipped\",\n      \"   <findings that were stale, flagged for human, or reverted\",\n      \"   during the smoke check — one entry each, with the reason>\",\n      \"\",\n      \"   ## Paths Touched\",\n      \"   <ordered list of files edited, plus any index files those edits\",\n      \"   affect. This is the Phase 3 re-scan scope — the verify phase\",\n      \"   reads this section to decide which paths to re-check.>\",\n      \"   ```\",\n      \"\",\n      \"7. **Comment on the scan issue** with a summary of what was fixed,\",\n      \"   what was skipped, and that Phase 3 (Verify) will close the loop.\",\n      \"\",\n      \"8. **Create the `maint:verify` issue.** Block it on this fix issue\",\n      \"   via `Depends on: #N` so it only runs after the fix PR lands.\",\n      \"   The verify issue body must reference:\",\n      \"   - The parent `maint:scan` issue number\",\n      \"   - The Phase 1 audit report path\",\n      \"   - The Phase 2 fix report path\",\n      \"   - The `Paths Touched` list (so Phase 3 scopes the re-scan\",\n      \"     correctly)\",\n      \"   - The same check catalog the scan phase used\",\n      \"\",\n      \"   If the fix phase applied **zero** auto-fixes (every finding was\",\n      \"   `stale-finding` or `flag-for-human`), skip the verify issue —\",\n      \"   there is nothing to verify. Summarize on the fix issue and close\",\n      `   it ${ISSUE_CLOSE_RULE_REFERENCE}, comment on the scan issue, and`,\n      \"   let a human decide whether to re-scan.\",\n      \"\",\n      \"9. **Commit and push.**\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 3: Verify (`maint:verify`)\",\n      \"\",\n      \"**Goal:** Close the loop on the audit cycle. Re-run the same checks\",\n      \"the scan phase ran, scoped to the paths and registries the fix\",\n      \"phase actually touched, compare pre and post findings, and record\",\n      \"the result in a durable verify report.\",\n      \"\",\n      \"**Budget:** Filesystem reads + registry parsing, just like Phase 1,\",\n      \"but bounded to the paths enumerated in the fix report's\",\n      \"`Paths Touched` section (plus any index files those paths transit).\",\n      \"No edits to source docs in this phase — if the re-scan surfaces a\",\n      \"regression, record it and file a follow-up `maint:scan` issue,\",\n      \"but do not attempt to re-fix in-session.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the verify scope** from the issue body. Confirm the parent\",\n      \"   scan issue number, the audit report path, the fix report path,\",\n      \"   and the `Paths Touched` list. If any of these are missing or\",\n      \"   the files they reference do not exist, close the verify issue\",\n      \"   with `status:needs-attention` and stop.\",\n      \"\",\n      \"2. **Re-run the same checks the scan phase ran**, scoped to the\",\n      \"   paths the fix phase touched plus any index or registry files\",\n      \"   those paths transit. Use the identical check catalog that the\",\n      \"   parent scan issue declared — do not add or remove checks\",\n      \"   between scan and verify.\",\n      \"\",\n      \"3. **Compare pre and post findings.** For each finding in the Phase 1\",\n      \"   audit report that fell within the re-scan scope, classify it as:\",\n      \"   - **resolved** — absent from the re-scan; the fix worked.\",\n      \"   - **still-failing** — still present in the re-scan; the fix did\",\n      \"     not clear it.\",\n      \"   - **regressed** — was not in the Phase 1 audit report but appears\",\n      \"     now; the fix introduced it.\",\n      \"   - **out-of-scope** — was in the Phase 1 audit report but its\",\n      \"     path was not in the fix phase's `Paths Touched` list, so this\",\n      \"     verify pass cannot speak to it.\",\n      \"\",\n      \"4. **Write the verify report** to:\",\n      \"   ```\",\n      \"   <AUDIT_ROOT>/maint-verify-<AUDIT_SLUG>-<YYYY-MM-DD>.md\",\n      \"   ```\",\n      \"\",\n      \"   Format:\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"Maintenance Verify: <AUDIT_SLUG>\"',\n      \"   date: YYYY-MM-DD\",\n      \"   parent_issue: <N>\",\n      \"   scan_issue: <N>\",\n      \"   fix_issue: <N>\",\n      \"   audit_report: <path to Phase 1 scan report>\",\n      \"   fix_report: <path to Phase 2 fix report>\",\n      \"   status: complete\",\n      \"   ---\",\n      \"\",\n      \"   ## Source Reports\",\n      \"   - Scan report: <link>\",\n      \"   - Fix report: <link>\",\n      \"\",\n      \"   ## Re-scan Scope\",\n      \"   - **Paths re-checked:** <list — from the fix report's\",\n      \"     `Paths Touched` section>\",\n      \"   - **Checks re-run:** <same catalog the scan phase used>\",\n      \"\",\n      \"   ## Pre/Post Comparison\",\n      \"   | Status | Count | Findings |\",\n      \"   |--------|-------|----------|\",\n      \"   | resolved | N | <one line per finding: category + file:line> |\",\n      \"   | still-failing | N | <one line per finding> |\",\n      \"   | regressed | N | <one line per finding> |\",\n      \"   | out-of-scope | N | <one line per finding> |\",\n      \"\",\n      \"   ## Verdict\",\n      \"   - **clean** — every in-scope finding resolved and no regressions;\",\n      \"     the parent scan issue will be closed.\",\n      \"   - **residual** — one or more still-failing or regressed findings;\",\n      \"     a follow-up `maint:scan` issue is filed and the parent scan\",\n      \"     issue is closed with a reference to the follow-up.\",\n      \"   ```\",\n      \"\",\n      \"5. **Decide the next step:**\",\n      \"   - **Clean verdict** (every in-scope finding resolved, no\",\n      \"     regressions, no still-failing entries) → comment on the parent\",\n      \"     `maint:scan` issue summarizing the result and **close it**.\",\n      \"     Do not file a follow-up scan.\",\n      \"   - **Residual verdict** (one or more `still-failing` or\",\n      \"     `regressed` entries) → file a new `maint:scan` issue for the\",\n      \"     residual scope, blocked on nothing (it is ready to run on its\",\n      \"     own schedule), and link the verify report from its body. Then\",\n      \"     comment on the parent scan issue with the residual summary and\",\n      \"     **close it**.\",\n      \"   - **Out-of-scope-only verdict** (every finding fell outside the\",\n      \"     fix phase's `Paths Touched`) → comment on the parent scan\",\n      \"     issue explaining that the fix phase did not cover those paths\",\n      \"     and leave it open with `status:needs-attention` so a human can\",\n      \"     re-scope the cycle. Do not auto-close the parent scan issue\",\n      \"     in this case.\",\n      \"\",\n      \"6. **Commit and push.** Comment the verdict on the verify issue in\",\n      `   one line, and close it ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Coordination with Other Agents\",\n      \"\",\n      \"| Direction | Agent | What |\",\n      \"|-----------|-------|------|\",\n      \"| 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 — the human may then dispatch the appropriate writer agent. This agent never opens writer-agent issues itself. |\",\n      \"\",\n      \"**File boundaries:** Writes audit, fix, and verify reports to\",\n      \"`<AUDIT_ROOT>/`. Applies bounded, idempotent edits under\",\n      \"`<DOCS_ROOT>/` only in Phase 2 (Fix), per the fix-policy declared\",\n      \"in the fix issue body. Phase 3 (Verify) never edits doc files —\",\n      \"it only reads and re-scans. Never writes to source code, never\",\n      \"writes to doc trees outside `<DOCS_ROOT>`, never authors new\",\n      \"document files to close a gap.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Blocked Issues\",\n      \"\",\n      \"Additional block reasons specific to maintenance audits:\",\n      \"- `<DOCS_ROOT>` is undefined or does not exist in the repo\",\n      \"- The registry file format is ambiguous (no declared schema)\",\n      \"- All findings are `flag-for-human` and the fix issue has nothing\",\n      \"  to auto-apply — resolve by closing the fix issue with a summary\",\n      \"  instead\",\n      \"- A `maint:verify` issue references a fix report whose\",\n      \"  `Paths Touched` list is empty — there is nothing to re-scan, so\",\n      \"  close the verify issue with a summary and let a human decide\",\n      \"  whether to re-run the scan\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Rules\",\n      \"\",\n      \"- **Audit before fix.** Never apply a fix whose finding is not\",\n      \"  recorded in the audit report referenced by the fix issue.\",\n      \"- **Idempotent fixes only.** If re-running the same fix twice\",\n      \"  would produce a different result, it is not an idempotent fix.\",\n      \"  Mark it `flag-for-human` instead.\",\n      \"- **Bounded scope.** Do not expand the audit scope mid-session.\",\n      \"  Record out-of-scope observations in the report for human review.\",\n      \"- **No authoring.** Do not invent new document content to close a\",\n      \"  finding. That work belongs to the writer agent for the doc type.\",\n      \"- **Verify closes the loop.** Every fix-phase run that lands at\",\n      \"  least one auto-fix must enqueue a `maint:verify` issue. Phase 3\",\n      \"  is the only phase that closes the parent `maint:scan` issue.\",\n      \"  Phase 2 never closes the scan issue itself.\",\n      \"- **Pre/post comparison is required.** The verify report must\",\n      \"  classify every in-scope finding from the scan report as\",\n      \"  `resolved`, `still-failing`, `regressed`, or `out-of-scope`.\",\n      \"  An unclassified finding means the re-scan was incomplete — re-\",\n      \"  run the missing checks before writing the verdict.\",\n      \"- **Residual findings get their own cycle.** When the verify phase\",\n      \"  finds `still-failing` or `regressed` entries, file a follow-up\",\n      \"  `maint:scan` issue rather than attempting to re-fix in-session.\",\n      \"  The new scan starts its own audit cycle with a fresh report.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off a maintenance audit cycle. */\nfunction buildMaintenanceAuditSkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"audit-docs\",\n    description:\n      \"Kick off a documentation-maintenance audit cycle (scan → fix → verify). Creates a maint:scan issue for the supplied scope and dispatches Phase 1.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"maintenance-audit\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Audit Docs\",\n      \"\",\n      \"Kick off a maintenance-audit cycle against a configurable doc\",\n      \"tree. Creates a `maint:scan` issue targeted at the requested\",\n      \"scope and dispatches Phase 1 (Scan) in the maintenance-audit\",\n      \"agent. Subsequent phases (`maint:fix`, `maint:verify`) are\",\n      \"created automatically as the cycle progresses.\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/audit-docs <scope>\",\n      \"\",\n      \"Where `<scope>` is a short slug plus path for the doc tree to\",\n      \"audit. Examples:\",\n      `- \\`requirements-xrefs:${paths.requirementsRoot}/\\` — audit requirement`,\n      \"  traceability links and the category registries\",\n      `- \\`adr-registry:${paths.requirementsRoot}/architectural-decisions/\\` — audit the ADR registry index`,\n      `- \\`bcm-traceability:${paths.bcmRoot}/\\` — audit BCM capability-model`,\n      \"  cross-references\",\n      \"\",\n      \"The consuming project defines which scopes are valid.\",\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `maint:scan` issue with `type:maintenance`,\",\n      `   \\`priority:${labelsForPhase(issueDefaults, \"maint:scan\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"maint:scan\").status}\\`. Body must list:`,\n      \"   - `<DOCS_ROOT>` — the doc tree to audit\",\n      \"   - `<AUDIT_ROOT>` — where to write the audit report\",\n      \"   - `<AUDIT_SLUG>` — short identifier for this audit\",\n      \"   - The audit checks to run (defaults to the full check catalog)\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 1 (Scan) of the maintenance-audit agent.\",\n      \"3. If auto-fixable findings exist, a `maint:fix` issue is created\",\n      \"   automatically.\",\n      \"4. When the fix phase lands, a `maint:verify` issue is created\",\n      \"   automatically so Phase 3 can re-run the checks and close the\",\n      \"   parent scan issue.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- A `maint-audit-<slug>-<YYYY-MM-DD>.md` report under\",\n      \"  `<AUDIT_ROOT>`.\",\n      \"- A `maint:fix` issue if auto-fixable findings were found.\",\n      \"- A `maint:verify` issue after the fix phase lands (Phase 3\",\n      \"  produces a `maint-verify-<slug>-<YYYY-MM-DD>.md` report).\",\n    ].join(\"\\n\"),\n  };\n}\n\n/**\n * Skill that kicks off the verify phase of a maintenance audit cycle.\n * Used when Phase 2 (Fix) created a verify issue automatically — this\n * skill is the explicit entry point for re-running the verify phase\n * on demand or for re-verifying an audit cycle whose Phase 3 did not\n * run automatically.\n */\nfunction buildMaintenanceVerifySkill(\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"verify-audit\",\n    description:\n      \"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.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"maintenance-audit\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Verify Audit\",\n      \"\",\n      \"Close the loop on a maintenance-audit cycle. Creates a\",\n      \"`maint:verify` issue and dispatches Phase 3 (Verify) in the\",\n      \"maintenance-audit agent.\",\n      \"\",\n      \"Phase 3 re-runs the same checks the scan phase ran, scoped to the\",\n      \"paths the fix phase actually touched, compares pre and post\",\n      \"findings, and writes a verify report. Based on the verdict the\",\n      \"phase either closes the parent `maint:scan` issue or files a\",\n      \"follow-up `maint:scan` for residual findings.\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/verify-audit <scan-issue-number>\",\n      \"\",\n      \"Where `<scan-issue-number>` is the `maint:scan` issue that kicked\",\n      \"off the audit cycle. The skill resolves the scan report, the\",\n      \"Phase 2 fix report, and the `Paths Touched` list from that scan\",\n      \"issue's downstream `maint:fix` issue.\",\n      \"\",\n      \"Most cycles do not need this skill — Phase 2 (Fix) creates the\",\n      \"verify issue automatically. Use this skill when:\",\n      \"- Phase 2 ran on an older audit cycle that predates the verify\",\n      \"  phase and never enqueued a verify issue, or\",\n      \"- A human wants to re-run the verify phase after a manual fix\",\n      \"  applied on top of the Phase 2 PR.\",\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `maint:verify` issue with `type:maintenance`,\",\n      `   \\`priority:${labelsForPhase(issueDefaults, \"maint:verify\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"maint:verify\").status}\\`. Body must list:`,\n      \"   - The parent `maint:scan` issue number\",\n      \"   - The Phase 1 audit report path\",\n      \"   - The Phase 2 fix report path (if one exists)\",\n      \"   - The `Paths Touched` list (copied from the fix report)\",\n      \"   - The audit check catalog (copied from the scan issue)\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 3 (Verify) of the maintenance-audit agent.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- A `maint-verify-<slug>-<YYYY-MM-DD>.md` report under\",\n      \"  `<AUDIT_ROOT>` containing the pre/post comparison.\",\n      \"- The parent `maint:scan` issue is closed (clean verdict) or a\",\n      \"  follow-up `maint:scan` issue is filed (residual verdict).\",\n    ].join(\"\\n\"),\n  };\n}\n\n/**\n * Maintenance-audit bundle — enabled by default.\n *\n * Consuming projects can disable it with\n * `excludeBundles: [\"maintenance-audit\"]`. `appliesWhen` always returns\n * `true` per this batch's directive that bundles assume peers are\n * present.\n *\n * Provides a 3-phase documentation-maintenance pipeline\n * (scan → fix → verify) designed for any project with structured doc\n * registries and cross-references. Ships a sub-agent, two user-\n * invocable skills (`/audit-docs`, `/verify-audit`), and `maint:*`\n * phase labels via the bundle `labels` mechanism so consuming projects\n * automatically pick up the label taxonomy through the sync-labels\n * workflow.\n */\nexport function buildMaintenanceAuditBundle(\n  paths: ResolvedAgentPaths = DEFAULT_AGENT_PATHS,\n  issueDefaults: ResolvedIssueDefaults = DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n  tier: AgentModel = AGENT_MODEL.BALANCED,\n): AgentRuleBundle {\n  return {\n    name: \"maintenance-audit\",\n    description:\n      \"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.\",\n    appliesWhen: () => true,\n    rules: [\n      {\n        name: \"maintenance-audit-workflow\",\n        description:\n          \"Describes the 3-phase documentation-maintenance pipeline, the maint:* label taxonomy, the audit-before-fix boundary, and the verify-closes-the-loop rule.\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Maintenance Audit Workflow\",\n          \"\",\n          \"Use `/audit-docs <scope>` to kick off a documentation-maintenance\",\n          \"audit cycle. The pipeline runs in 3 phases — scan, fix, and\",\n          \"verify — each tracked by its own GitHub issue labeled\",\n          \"`maint:scan`, `maint:fix`, or `maint:verify`. All issues carry\",\n          \"`type:maintenance`.\",\n          \"\",\n          \"One additional user-invocable skill drives the verify phase\",\n          \"on demand:\",\n          \"\",\n          \"- `/verify-audit <scan-issue-number>` — re-run the scan checks\",\n          \"  scoped to the paths the fix phase touched, compare pre/post\",\n          \"  findings, and close the parent `maint:scan` issue (or file a\",\n          \"  follow-up for residual findings). Phase 2 (Fix) normally\",\n          \"  enqueues the verify issue automatically — this skill is the\",\n          \"  explicit entry point for re-running the phase on demand.\",\n          \"\",\n          \"The maintenance-audit agent *audits doc registries and applies\",\n          \"idempotent fixes*; it does **not** author new document content.\",\n          \"Findings that would require authoring new docs are flagged for\",\n          \"human review so the appropriate writer agent can be dispatched.\",\n          \"\",\n          \"See the `maintenance-audit` agent definition for full workflow\",\n          \"details and phase-by-phase instructions.\",\n        ].join(\"\\n\"),\n        platforms: {\n          cursor: { exclude: true },\n        },\n        tags: [\"workflow\"],\n      },\n    ],\n    skills: [\n      buildMaintenanceAuditSkill(paths, issueDefaults),\n      buildMaintenanceVerifySkill(issueDefaults),\n    ],\n    subAgents: [buildMaintenanceAuditSubAgent(paths, tier)],\n    labels: [\n      {\n        name: \"type:maintenance\",\n        color: \"5319E7\",\n        description:\n          \"Work that audits or fixes documentation registries, cross-references, or indexes\",\n      },\n      {\n        name: \"maint:scan\",\n        color: \"C5DEF5\",\n        description:\n          \"Phase 1: scan doc tree for broken xrefs, registry drift, and stale indexes\",\n      },\n      {\n        name: \"maint:fix\",\n        color: \"BFDADC\",\n        description:\n          \"Phase 2: apply idempotent fixes from a maintenance audit report\",\n      },\n      {\n        name: \"maint:verify\",\n        color: \"D4C5F9\",\n        description:\n          \"Phase 3: re-run scan checks scoped to fix-phase paths, compare findings, close or re-queue scan\",\n      },\n    ],\n  };\n}\n\n/**\n * Default-paths instance of the maintenance-audit bundle, preserved\n * for backward compatibility with consumers that import the const\n * directly. The factory above is the canonical entry point when a\n * consumer supplies `AgentConfigOptions.paths`.\n */\nexport const maintenanceAuditBundle: AgentRuleBundle =\n  buildMaintenanceAuditBundle();\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { renderClaimVerificationSection } from \"./claim-verification\";\nimport {\n  ISSUE_CLOSE_RULE_REFERENCE,\n  ISSUE_CLOSE_SECTION_TITLE,\n  renderIssueClosePolicySection,\n} from \"./issue-close\";\nimport {\n  renderIssueTypeAssignmentBlanket,\n  renderIssueTypeAssignmentStep,\n} from \"./issue-type\";\nimport { renderOriginStampSection } from \"./origin-label\";\nimport { PROJECT_CONTEXT_MAINTAINER_SECTION } from \"./project-context\";\nimport {\n  AGENT_MODEL,\n  AGENT_RULE_SCOPE,\n  AgentModel,\n  AgentSkill,\n  AgentSubAgent,\n} from \"../types\";\n\n/** Sub-agent that processes meeting transcripts through the 4-phase pipeline. */\nfunction buildMeetingAnalystSubAgent(tier: AgentModel): AgentSubAgent {\n  return {\n    name: \"meeting-analyst\",\n    description:\n      \"Processes meeting notes and transcripts (sibling-tree layout) through a 4-phase pipeline: extract, notes, draft, and link\",\n    model: tier,\n    maxTurns: 80,\n    platforms: { cursor: { exclude: true } },\n    prompt: [\n      \"# Meeting Analyst Agent\",\n      \"\",\n      \"You process meeting notes and transcripts through a structured\",\n      \"4-phase pipeline. Notes and transcripts live in **parallel sibling\",\n      \"trees** keyed by basename — see the **Meeting file layout** section\",\n      \"below for the canonical directory layout and input-case matrix.\",\n      \"Each phase runs as a **separate agent session**, triggered by its own\",\n      \"GitHub issue with a `meeting:*` phase label. You handle exactly **one\",\n      \"phase per session** — read the issue to determine which phase to execute.\",\n      \"\",\n      \"## Execution Model\",\n      \"\",\n      \"1. Each meeting produces up to 4 GitHub issues (one per phase)\",\n      \"2. Each issue carries a `meeting:*` label identifying the phase\",\n      \"3. You pick up one issue, execute that phase, commit/push, then close\",\n      `   the issue — see the **${ISSUE_CLOSE_SECTION_TITLE}** section below`,\n      \"   before you close anything yourself\",\n      \"4. Phase 1 (Extract) creates the downstream phase issues for phases 2-4\",\n      \"5. Each downstream issue includes `Depends on: #N` linking to its predecessor\",\n      \"\",\n      \"## Design Principles\",\n      \"\",\n      \"1. **Extract, don't interpret.** Capture what was said and decided. Flag\",\n      \"   ambiguity as open items rather than resolving it.\",\n      \"2. **Route to the right category.** Meeting content maps to requirements,\",\n      \"   ADRs, product docs, and business strategy. Each output goes to the\",\n      \"   correct location per the project's taxonomy.\",\n      \"3. **Preserve provenance.** Every extracted item links back to the meeting\",\n      \"   source so reviewers can check context.\",\n      \"4. **Create issues, not documents.** For requirements and ADRs, create\",\n      \"   GitHub issues that other agents or humans will pick up. Do not write\",\n      \"   final requirement documents yourself.\",\n      \"5. **Bi-directional traceability.** Every document and issue created by\",\n      \"   this pipeline must link back to the meeting source, and the meeting\",\n      \"   source documents must link forward to everything created from them.\",\n      \"6. **Respect meeting type and areas.** Read the `meeting_type` and\",\n      \"   `areas` values from the meeting frontmatter before starting Phase 1.\",\n      \"   Apply the type-specific rules from the **Meeting type handling**\",\n      \"   table (phases 1–2) and the area-filtered routing rules from the\",\n      \"   **Areas filtering** table (phase 4).\",\n      \"7. **Treat notes and transcripts as paired siblings.** Notes are the\",\n      \"   curated narrative summary; transcripts are the verbatim evidence\",\n      \"   record. Both are first-class inputs to Phase 1 — never assume the\",\n      \"   transcript is the sole input.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Meeting file layout (sibling-tree model)\",\n      \"\",\n      \"The bundle organises meeting artifacts as **three parallel trees**\",\n      \"rooted at `<meetingsRoot>`, partitioned by meeting type\",\n      \"(`internal` / `external`):\",\n      \"\",\n      \"```\",\n      \"<meetingsRoot>/\",\n      \"├── transcripts/{internal,external}/   ← raw verbatim transcripts (input, evidence)\",\n      \"├── notes/{internal,external}/         ← curated narrative summary (input + Phase 2 output)\",\n      \"└── insights/{internal,external}/      ← structured extraction (Phase 1 output)\",\n      \"```\",\n      \"\",\n      \"Within a given `{internal,external}` partition, the three trees share\",\n      \"**identical basenames**: a meeting captured as\",\n      \"`notes/internal/2026-03-14-sprint-kickoff.md` has its companion\",\n      \"transcript at `transcripts/internal/2026-03-14-sprint-kickoff.md` and\",\n      \"its Phase 1 extraction at `insights/internal/2026-03-14-sprint-kickoff.md`.\",\n      \"Agents look up siblings via filesystem (basename match across the\",\n      \"three trees), not via frontmatter cross-references.\",\n      \"\",\n      \"**Input-case matrix.** A meeting always has a `notes/` or\",\n      \"`transcripts/` entry (often both); Phase 1 must handle every case:\",\n      \"\",\n      \"| Notes file? | Transcript file? | Case | Phase-1 behaviour |\",\n      \"|-------------|------------------|------|--------------------|\",\n      \"| Yes | Yes | **Both** | Read both; transcript is verbatim ground truth, notes are first-draft summary. Set `transcript_available: true`, `confidence: high`. |\",\n      \"| Yes | No | **Notes-only** | Read notes only. Set `transcript_available: false`, `confidence: medium`. Do not invent dialogue the notes do not record. |\",\n      \"| No | Yes | **Transcript-only** | Read transcript only. Set `transcript_available: true`, `confidence: high`. Phase 2 will author the notes file from the transcript. |\",\n      \"\",\n      \"Notes frontmatter is **optional**. A bare imported file with no\",\n      \"frontmatter is a normal input case — treat missing fields as the\",\n      \"defaults `meeting_type: other`, `source: unknown`, `confidence: medium`,\",\n      \"and populate the real values on first processing. Never fail-loud on\",\n      \"absent frontmatter.\",\n      \"\",\n      \"### Notes / insights frontmatter schema\",\n      \"\",\n      \"The following frontmatter fields are recognised on notes and\",\n      \"insights files. Every field is optional — agents must read them\",\n      \"defensively and supply defaults when absent.\",\n      \"\",\n      \"| Field | Type | Purpose | Default |\",\n      \"|-------|------|---------|---------|\",\n      \"| `slug` | string | Starlight slug override; lets agents normalise the URL without renaming files. | derived from filename |\",\n      \"| `source` | `gemini` \\\\| `human` \\\\| `hybrid` \\\\| `unknown` | Provenance of the original notes (which authoring path produced them). | `unknown` |\",\n      \"| `transcript_available` | boolean | Cached result of the filesystem check for the sibling transcript. | re-derive from filesystem |\",\n      \"| `confidence` | `high` \\\\| `medium` \\\\| `low` | Reliability of the extraction. Downstream draft phases mark requirements **Tentative** when `confidence != high`. | `medium` |\",\n      \"\",\n      \"These additions coexist with the existing `meeting_type` and `areas`\",\n      \"fields documented in the **Meeting type handling** and **Areas\",\n      \"filtering** sections below.\",\n      \"\",\n      \"Transcript files themselves remain frontmatter-free — they are\",\n      \"evidence-only, and agents never navigate to a transcript as a\",\n      \"Starlight artifact.\",\n      \"\",\n      \"### Tree-level index pages\",\n      \"\",\n      \"Each of the three trees carries an `index.md` at its root and at\",\n      \"each `{internal,external}` partition so Starlight renders a clean\",\n      \"sidebar:\",\n      \"\",\n      \"- `<meetingsRoot>/transcripts/index.md` (and one per partition)\",\n      \"- `<meetingsRoot>/notes/index.md` (and one per partition)\",\n      \"- `<meetingsRoot>/insights/index.md` (and one per partition)\",\n      \"\",\n      \"Phase 1 must create the matching `insights/{type}/index.md` page\",\n      \"the first time it writes a file into that partition. Phase 2 must\",\n      \"create the matching `notes/{type}/index.md` page the first time it\",\n      \"writes a notes file into that partition. Follow the `section-index`\",\n      \"convention: a 1–2 paragraph summary of the tree's purpose plus a\",\n      \"linked listing of the partition's children. Append a row for the\",\n      \"current meeting's basename when an index already exists.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Meeting type handling\",\n      \"\",\n      \"Meeting frontmatter is expected to carry a `meeting_type` field whose\",\n      \"value is one of the project's concrete meeting-type `id`s (declared\",\n      \"via `AgentConfigOptions.meetings.meetingTypes`). Each concrete `id`\",\n      \"maps to one of six generic **meeting kinds** that drive type-specific\",\n      \"extraction rules:\",\n      \"\",\n      \"| Kind | Primary outputs | Phase-1/2 rules |\",\n      \"|------|-----------------|-----------------|\",\n      \"| `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. |\",\n      \"| `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 — do not spawn a separate retro document. |\",\n      \"| `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. |\",\n      \"| `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. |\",\n      \"| `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. |\",\n      \"| `other` | General meeting extraction | Apply the default workflow with no type-specific overrides. |\",\n      \"\",\n      \"**How to resolve the kind:**\",\n      \"\",\n      \"1. Read `meeting_type` from the frontmatter.\",\n      \"2. Look up the matching `id` in the project's **Recognized meeting\",\n      \"   types** table (rendered below when `meetingTypes` is declared).\",\n      \"3. Use the `Kind` column value. If the table is absent, the `id` is\",\n      \"   unknown, or the `Kind` column is `—`, fall back to `other`.\",\n      \"4. Apply the rules in the row above **in addition to** the normal\",\n      \"   phase workflow — never as a replacement.\",\n      \"\",\n      \"If `meeting_type` is missing, invalid, or the declared `id` is not in\",\n      \"the project's table, note it in the extraction's Open Questions and\",\n      \"proceed with the default workflow (treat as `other`).\",\n      \"\",\n      \"## Areas filtering\",\n      \"\",\n      \"Meeting frontmatter may carry an `areas: [...]` list whose values\",\n      \"match `id`s from the project's **Area → doc-root mapping** table\",\n      \"(declared via `AgentConfigOptions.meetings.meetingAreas`). The list\",\n      \"scopes phase-4 direct edits and cross-references to the doc-root\",\n      \"sub-folders registered for those areas. A given area's effective\",\n      \"path resolves as `<docsRoot>/<docRoot>` — `docsRoot` comes from\",\n      \"`AgentPathsConfig.docsRoot`; `docRoot` is the sub-folder shown in\",\n      \"the **Area → doc-root mapping** table.\",\n      \"\",\n      \"**Gating contract (phase 4 only):**\",\n      \"\",\n      \"- **Scoped in:** direct edits and cross-reference stubs under the\",\n      \"  `docRoot` of every `id` present in the meeting's `areas` list.\",\n      \"- **Scoped out:** direct edits to any doc-root sub-folder that is\",\n      \"  declared in the project's area map but whose `id` is **not** in\",\n      \"  the meeting's `areas`. For those out-of-scope areas, create\",\n      \"  follow-up issues instead of editing the doc directly.\",\n      \"- **Not gated:** issue creation (requirements, ADRs, profiles,\",\n      \"  research) is always in scope regardless of areas.\",\n      \"\",\n      \"**Resolution rules:**\",\n      \"\",\n      \"1. If the meeting's `areas` frontmatter is missing or empty **and**\",\n      \"   the project has declared a non-empty `meetingAreas` map, no\",\n      \"   doc-root sub-folder is gated in: direct edits to any declared\",\n      \"   `docRoot` sub-folder are out-of-scope and become follow-up issues\",\n      \"   per step 6. Only the default meetings root (`meetingsRoot`)\",\n      \"   remains editable.\",\n      \"2. If `areas` lists an `id` that is not in the project's area map,\",\n      \"   note it in the extraction's Open Questions and treat the unknown\",\n      \"   `id` as absent. Do **not** invent a doc-root path for it.\",\n      \"3. Out-of-scope direct edits become `type:docs` follow-up issues on\",\n      \"   phase 4 step 6, with the area noted in the issue body.\",\n      \"\",\n      \"When the project has **not** declared any `meetingAreas` at all,\",\n      \"this section applies degenerately — no areas are gated, no\",\n      \"follow-up issues are synthesized for missing areas, and phase-4\",\n      \"direct edits follow the default workflow (step 6 edits any doc\",\n      \"flagged as Firm, unrestricted by `docRoot`).\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Action-item filing policy\",\n      \"\",\n      \"Not every action item should become a GitHub issue. The pipeline\",\n      \"can only ever close issues whose deliverable an automated agent\",\n      \"(or this repo's existing channels) can produce. Filing an issue\",\n      \"for a task only a human can do — in the real world or in a system\",\n      \"this pipeline cannot touch — creates queue noise that no worker or\",\n      \"orchestrator can ever resolve. Apply the **agent-workability\",\n      \"test** below in phases 1, 3, and 4.\",\n      \"\",\n      \"### Agent-workability test\",\n      \"\",\n      \"An action item is **agent-workable** only when completing it\",\n      \"produces a documentation deliverable an automated agent can author\",\n      \"in this repo's docs tree — a requirement document, an ADR, a docs\",\n      \"page, a BCM capability model, a research note, or a roadmap /\",\n      \"product-doc update. Route agent-workable items through their\",\n      \"**dedicated downstream channel** (`req:write`, `docs:write`,\",\n      \"`bcm:*`, `research:scope`, roadmap/product-doc follow-up). Never\",\n      \"file them as a generic `action-item` / `type:chore` issue.\",\n      \"\",\n      \"An action item is **human-owned** when it requires a person to act\",\n      \"in the real world or in a system this pipeline cannot reach.\",\n      \"Typical cues:\",\n      \"\",\n      '- **send / email / schedule / invite / call** — e.g. \"send out',\n      '  company invoices\", \"invite X to next week\\'s call\".',\n      '- **install / configure / provision / set up** — e.g. \"install and',\n      '  configure Claude\", \"get codebase read access\".',\n      \"- **decide / approve / choose / prioritise** (a human judgement\",\n      \"  call, not a documented decision record).\",\n      '- **communicate / notify / give a heads-up** — e.g. \"give Dr. Y a',\n      '  heads-up\".',\n      \"- **get / request access or credentials**, **pay / invoice**.\",\n      \"- **build or change code in another repo**, **design in an\",\n      \"  external tool** (Figma, etc.).\",\n      \"\",\n      \"Record human-owned items **only** in the notes `## Action Items`\",\n      \"table (who / what / when) — that table is the **system of record**\",\n      \"for human follow-ups. Do **not** file a GitHub issue for them.\",\n      \"\",\n      \"When an item is ambiguous, default to **human-owned**\",\n      \"(notes-only): a missed issue is cheaper than queue noise the\",\n      \"pipeline can never close.\",\n      \"\",\n      \"**Consumer tuning.** When the project supplies\",\n      \"`AgentConfigOptions.meetings.actionItemFiling`, an\",\n      \"**Action-item filing policy** subsection is rendered into the\",\n      \"meetings taxonomy with any extra human-owned / agent-workable cues\",\n      \"and a note when the split is disabled. Apply those overrides on\",\n      \"top of the built-in cues above; if the split is disabled, fall\",\n      \"back to filing a follow-up issue for every non-draft action item.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...PROJECT_CONTEXT_MAINTAINER_SECTION,\n      \"## Traceability\",\n      \"\",\n      \"All outputs must be bi-directionally linked so any artifact can be traced\",\n      \"back to the meeting that produced it and forward to everything it spawned.\",\n      \"\",\n      \"### Backward links (created artifact → meeting source)\",\n      \"\",\n      \"Every GitHub issue and document created by this pipeline must include a\",\n      \"`## Traceability` section with:\",\n      \"\",\n      \"```markdown\",\n      \"## Traceability\",\n      \"\",\n      \"- **Source meeting:** <path to transcript or meeting notes>\",\n      \"- **Extraction:** <path to extraction file>\",\n      \"- **Phase issue:** #<N> (the phase issue that created this artifact)\",\n      \"```\",\n      \"\",\n      \"### Forward links (meeting source → created artifacts)\",\n      \"\",\n      \"After Phase 4 (Link) creates all follow-up issues and documents:\",\n      \"\",\n      \"1. **Update the extraction file** with a `## Downstream Artifacts` section\",\n      \"   listing every issue and document created from this meeting:\",\n      \"\",\n      \"   ```markdown\",\n      \"   ## Downstream Artifacts\",\n      \"\",\n      \"   | Artifact | Type | Issue/Path |\",\n      \"   |----------|------|------------|\",\n      \"   | <title> | requirement / ADR / docs / profile / research | #<N> or <path> |\",\n      \"   ```\",\n      \"\",\n      \"2. **Update the meeting notes** with a similar `## Related Issues` section\",\n      \"   listing all issues created from this meeting.\",\n      \"\",\n      \"3. **Comment on the extract issue** with a summary linking to all created\",\n      \"   artifacts.\",\n      \"\",\n      \"### Within-pipeline links\",\n      \"\",\n      \"- Phase issues link to predecessors via `Depends on: #N`\",\n      \"- Phase issues reference the extraction file path in their body\",\n      \"- Draft documents reference both the extraction and the meeting notes\",\n      \"\",\n      \"---\",\n      \"\",\n      ...renderClaimVerificationSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderOriginStampSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderIssueClosePolicySection(),\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 1: Extract (`meeting:extract`)\",\n      \"\",\n      \"**Goal:** Read the available meeting inputs (notes, transcript, or both)\",\n      \"and categorize all substantive content into a structured extraction.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. Identify the meeting's basename and `{internal,external}` partition\",\n      \"   from the issue body using the **basename-pairing algorithm**, then\",\n      \"   read **every** sibling file that exists on disk:\",\n      \"   - Notes: `<meetingsRoot>/notes/{type}/<basename>.md`\",\n      \"   - Transcript: `<meetingsRoot>/transcripts/{type}/<basename>.md`\",\n      \"\",\n      \"   **Basename-pairing algorithm.** The issue body (or invoking\",\n      \"   skill) may name either tree's path; resolve the sibling\",\n      \"   implicitly:\",\n      \"\",\n      \"   - Infer the basename (filename without `.md`) and the\",\n      \"     `{internal,external}` partition from the provided path —\",\n      \"     `…/notes/internal/2026-03-14-sprint-kickoff.md` yields\",\n      \"     basename `2026-03-14-sprint-kickoff` and type `internal`.\",\n      \"   - If the input path lives under `/notes/`, look for the\",\n      \"     sibling at `<meetingsRoot>/transcripts/<type>/<basename>.md`.\",\n      \"     If it lives under `/transcripts/`, look for the sibling at\",\n      \"     `<meetingsRoot>/notes/<type>/<basename>.md`. If the path\",\n      \"     matches neither (ad-hoc location), infer basename + type as\",\n      \"     best you can from the filename and surrounding folder\",\n      \"     segments, then proceed with whichever sibling-tree lookups\",\n      \"     succeed. Best-effort, never fail-loud.\",\n      \"   - A missing sibling is a normal outcome — the input-case matrix\",\n      \"     covers notes-only and transcript-only paths. Never prompt or\",\n      \"     warn the user about the absence.\",\n      \"\",\n      \"   Use the **input-case matrix** in **Meeting file layout** to decide\",\n      \"   which case you are in (both / notes-only / transcript-only). Parse\",\n      \"   the notes frontmatter first (if a notes file exists), capturing\",\n      \"   `meeting_type`, `areas`, `source`, and `confidence`. Resolve\",\n      \"   `meeting_type` to a kind using the **Meeting type handling**\",\n      \"   table; note the resolved kind in the extraction frontmatter. If\",\n      \"   `meeting_type` is missing, treat it as `other` and flag it in\",\n      \"   Open Questions — do **not** fail-loud on missing frontmatter.\",\n      \"2. Identify and categorize content into these buckets:\",\n      \"\",\n      \"   | Bucket | What to look for |\",\n      \"   |--------|-----------------|\",\n      '   | **Decisions** | \"We decided...\", \"Let\\'s go with...\", explicit choices |',\n      '   | **Requirements** | Feature descriptions, acceptance criteria, \"it should...\" |',\n      \"   | **Technology discussions** | Platform comparisons, architecture options, tool evaluations |\",\n      '   | **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**. |',\n      '   | **Open questions** | \"We need to figure out...\", unresolved debates |',\n      \"   | **People of interest** | Industry contacts, domain experts mentioned |\",\n      \"   | **Companies of interest** | Competitors, vendors, partners discussed |\",\n      \"   | **Strategic direction** | Business model changes, market positioning |\",\n      \"   | **Product direction** | Roadmap changes, feature prioritization |\",\n      \"\",\n      \"3. Write the extraction to\",\n      \"   `<meetingsRoot>/insights/{type}/<basename>.md` (matching the\",\n      \"   basename and `{internal,external}` partition of the source\",\n      \"   notes / transcript) with structured sections:\",\n      \"   - Attendees\",\n      \"   - Decisions Made (with category and confidence: Firm / Tentative / Needs confirmation)\",\n      \"   - Requirements Identified (with category and priority estimate)\",\n      \"   - Technology Discussions (with status: Decided / Leaning toward / Open)\",\n      \"   - Action Items (with assignee and due date if stated, and a\",\n      \"     **disposition** tag — `agent-workable` or `human-owned` — per\",\n      \"     the **Action-item filing policy** so Phase 4 can route each\",\n      \"     item without re-classifying it)\",\n      \"   - Open Questions\",\n      \"   - People of Interest (with context and whether a profile exists)\",\n      \"   - Companies of Interest (with type and context)\",\n      \"   - Strategic / Product Direction\",\n      \"\",\n      \"   Carry the following into the extraction frontmatter so downstream\",\n      \"   phases can gate behaviour without re-parsing the source files:\",\n      \"   `meeting_type`, the resolved `meeting_kind`, `areas`,\",\n      \"   `transcript_available: true|false` (cached from the filesystem\",\n      \"   check in step 1), and `confidence: high|medium|low` (per the\",\n      \"   input-case matrix — `high` when a transcript is present, `medium`\",\n      \"   on notes-only, never silently downgraded to `low` without an\",\n      \"   explicit reason recorded in Open Questions).\",\n      \"\",\n      \"4. **Apply type-specific rules.** Consult the **Meeting type handling**\",\n      \"   table for the resolved kind and apply its phase-1 rules in\",\n      \"   addition to the default extraction above. Examples:\",\n      \"   - `standup`: skip requirement, ADR, and BDR extraction; focus on\",\n      \"     action items and status.\",\n      \"   - `brainstorm`: emphasize Open Questions and Future Features.\",\n      \"     Only mark decisions as Firm when the transcript is unambiguous.\",\n      \"   - `external`: default attendees outside the team into People of\",\n      \"     Interest; default organizations mentioned into Companies of\",\n      \"     Interest (signal threshold still applies); capture customer\",\n      \"     pain points as candidate BR (not FR).\",\n      \"\",\n      \"5. **Plan the `insights/` tree index update — do not commit it\",\n      \"   yet.** Ensure `<meetingsRoot>/insights/index.md` and\",\n      \"   `<meetingsRoot>/insights/{type}/index.md` exist (create them\",\n      \"   following the `section-index` convention if missing). Note\",\n      \"   the basename row this phase will eventually append, but\",\n      \"   **defer** the row insert and its commit to step 8 below so\",\n      \"   the shared-index commit can land in the smallest possible\",\n      \"   window before push.\",\n      \"\",\n      \"6. **Create downstream phase issues** using `gh issue create`:\",\n      \"   - Always create a `meeting:notes` issue (blocked on this extract issue)\",\n      \"   - If requirements OR decisions/ADRs identified, create a `meeting:draft` issue\",\n      \"     (blocked on the notes issue). For kind `standup`, skip the\",\n      \"     `meeting:draft` issue — standup meetings almost never produce\",\n      \"     formal drafts.\",\n      \"   - Always create a `meeting:link` issue — blocked on the draft issue if one\",\n      \"     was created, otherwise blocked on the notes issue\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"7. **Commit the extraction content first.** Stage and commit\",\n      \"   the `insights/{type}/<basename>.md` file (and any newly\",\n      \"   created `insights/index.md` / `insights/{type}/index.md`\",\n      \"   stub pages from step 5 that do not yet exist on the remote)\",\n      \"   in a single focused commit. **Do not push yet.**\",\n      \"\",\n      \"8. **Defer the shared-index row insert to a final pre-push\",\n      \"   commit.** Per the `shared-editing-safety` rule's\",\n      \"   **Defer Shared-Index Commit to Final Pre-Push Step**\",\n      \"   subsection, the index update for an existing\",\n      \"   `insights/{type}/index.md` is a **shared-index row insert**\",\n      \"   that races other parallel meeting sessions writing rows into\",\n      \"   the same partition file. Apply the deferred sequence:\",\n      \"\",\n      \"   ```bash\",\n      \"   git fetch origin\",\n      \"   git pull --rebase origin <default-branch>\",\n      \"   ```\",\n      \"\",\n      \"   Re-read `insights/{type}/index.md` from the now-up-to-date\",\n      \"   working tree, re-compute the alphabetical insert position\",\n      \"   for the current meeting's basename row (another session may\",\n      \"   have appended a sibling row in the meantime), insert exactly\",\n      \"   one row, and commit the index edit in its **own focused\",\n      \"   commit** whose only file is the shared index. Run the\",\n      \"   commit-path verification step (`git show HEAD:<index-path>`\",\n      \"   + grep count) against that commit before pushing.\",\n      \"\",\n      \"9. **Push and close.** Push the branch, then close the extract issue\",\n      `   ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 2: Notes (`meeting:notes`)\",\n      \"\",\n      \"**Goal:** Produce a curated `notes/{type}/<basename>.md` file that\",\n      \"reflects the structured meeting record. The pivot here from older\",\n      'versions of this bundle: Phase 2 is no longer \"author notes from',\n      'scratch.\" It is **enhance and verify** — restructure the existing',\n      \"Gemini-generated notes (when present), verify factual claims\",\n      \"against the transcript (when present), and fall back to authoring\",\n      \"only when no notes file exists.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. Read the extraction at\",\n      \"   `<meetingsRoot>/insights/{type}/<basename>.md` (output of Phase 1).\",\n      \"   Read the `transcript_available` and `confidence` fields from its\",\n      \"   frontmatter. Then determine which input-case branch applies by\",\n      \"   checking the filesystem for the sibling notes and transcript\",\n      \"   files.\",\n      \"2. **Branch by input case** (see the input-case matrix in the\",\n      \"   **Meeting file layout** section):\",\n      \"\",\n      \"   - **Both notes and transcript present** (enhance + verify):\",\n      \"     Read the existing `notes/{type}/<basename>.md` in place.\",\n      \"     Restructure it into the canonical section layout below.\",\n      \"     Verify every factual claim against the transcript — when the\",\n      \"     transcript contradicts the notes, the transcript wins and the\",\n      \"     notes are corrected. Fill in gaps the transcript reveals were\",\n      \"     missed. Overwrite the notes file in place; preserve the\",\n      \"     existing frontmatter and update only the fields you changed\",\n      \"     (e.g. flip `source: gemini` to `source: hybrid` once the agent\",\n      \"     has edited the file). Set `confidence: high`.\",\n      \"\",\n      \"   - **Notes only** (light structural cleanup):\",\n      \"     Read the existing `notes/{type}/<basename>.md`. Restructure it\",\n      \"     into the canonical section layout below. Do **not** invent\",\n      \"     dialogue or claims the notes do not record. Do **not** mark\",\n      \"     `confidence: high` — keep `confidence: medium` and record the\",\n      '     reason (\"no transcript available for verification\") in the',\n      \"     notes' Open Questions section so downstream phases know to\",\n      \"     treat downstream requirement drafts as `Tentative`.\",\n      \"\",\n      \"   - **Transcript only** (author from scratch):\",\n      \"     The notes file does not yet exist. Author\",\n      \"     `notes/{type}/<basename>.md` from the transcript using the\",\n      \"     section layout below. Populate frontmatter with\",\n      \"     `source: gemini` if the transcript is a Gemini transcript,\",\n      \"     otherwise `source: unknown`. Set `confidence: high`.\",\n      \"\",\n      \"3. Canonical notes section layout (applied in every branch above):\",\n      \"   - Meeting metadata (title, date, attendees)\",\n      \"   - Agenda / topics covered\",\n      \"   - Key Discussion Points (organized by topic)\",\n      \"   - Decisions (numbered, with rationale)\",\n      \"   - Action Items (table: who, what, when). This table is the\",\n      \"     **system of record for human follow-ups** — human-owned\",\n      \"     action items live here and are never filed as GitHub issues\",\n      \"     (see the **Action-item filing policy**). Capture every\",\n      \"     action item here regardless of disposition.\",\n      \"   - Open Questions\",\n      \"   - Follow-up items\",\n      \"4. **Plan the `notes/` tree index update — do not commit it\",\n      \"   yet.** Ensure `<meetingsRoot>/notes/index.md` and\",\n      \"   `<meetingsRoot>/notes/{type}/index.md` exist (create them\",\n      \"   following the `section-index` convention if missing). Note\",\n      \"   the basename row this phase will eventually append, but\",\n      \"   **defer** the row insert and its commit to step 6 below so\",\n      \"   the shared-index commit can land in the smallest possible\",\n      \"   window before push.\",\n      \"5. **Commit the notes content first.** Stage and commit the\",\n      \"   `notes/{type}/<basename>.md` file (and any newly created\",\n      \"   `notes/index.md` / `notes/{type}/index.md` stub pages from\",\n      \"   step 4 that do not yet exist on the remote) in a single\",\n      \"   focused commit. **Do not push yet.**\",\n      \"6. **Defer the shared-index row insert to a final pre-push\",\n      \"   commit.** Per the `shared-editing-safety` rule's\",\n      \"   **Defer Shared-Index Commit to Final Pre-Push Step**\",\n      \"   subsection, the index update for an existing\",\n      \"   `notes/{type}/index.md` is a **shared-index row insert**\",\n      \"   that races other parallel meeting sessions writing rows\",\n      \"   into the same partition file. Apply the deferred sequence:\",\n      \"\",\n      \"   ```bash\",\n      \"   git fetch origin\",\n      \"   git pull --rebase origin <default-branch>\",\n      \"   ```\",\n      \"\",\n      \"   Re-read `notes/{type}/index.md` from the now-up-to-date\",\n      \"   working tree, re-compute the alphabetical insert position\",\n      \"   for the current meeting's basename row (another session may\",\n      \"   have appended a sibling row in the meantime), insert exactly\",\n      \"   one row, and commit the index edit in its **own focused\",\n      \"   commit** whose only file is the shared index. Run the\",\n      \"   commit-path verification step against that commit before\",\n      \"   pushing.\",\n      `7. Push, then close the notes issue ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 3: Draft (`meeting:draft`)\",\n      \"\",\n      \"**Goal:** Draft proposals for requirements, ADRs, and product/strategy updates.\",\n      \"\",\n      \"This phase only exists if the extraction identified requirements, architectural\",\n      \"decisions, or strategy changes. If this issue exists, execute it.\",\n      \"\",\n      \"Draft proposals only for **agent-workable** deliverables (per the\",\n      \"**Action-item filing policy**). Action items tagged `human-owned`\",\n      \"in the extraction are not drafted here — they stay in the notes\",\n      \"`## Action Items` table and produce no follow-up issue.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. Read the extraction file from Phase 1 at\",\n      \"   `<meetingsRoot>/insights/{type}/<basename>.md`.\",\n      \"2. Check existing requirement registries and ADR registries for duplicates.\",\n      \"3. Draft requirement proposals with:\",\n      \"   - Category (FR, BR, NFR, etc.)\",\n      \"   - Summary (2-3 sentences)\",\n      \"   - Draft acceptance criteria\",\n      \"   - Related existing requirements\",\n      \"4. Draft ADR proposals for technology decisions with:\",\n      \"   - Context and problem statement\",\n      \"   - Options discussed\",\n      \"   - Stated preferences or decisions\",\n      \"   - Status: Proposed or Decided\",\n      \"5. Summarize product/strategy document updates needed.\",\n      \"6. Commit, push, and close the draft issue\",\n      `   ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 4: Link (`meeting:link`)\",\n      \"\",\n      \"**Goal:** Create GitHub issues for follow-up work, cross-reference the\",\n      \"meeting into existing documentation, and complete bi-directional traceability.\",\n      \"\",\n      \"### Idempotent dedup gate (open AND closed)\",\n      \"\",\n      \"Phase 3 (`meeting:draft`) already files one downstream issue per\",\n      \"drafted artifact — a `req:write` per requirement draft, plus\",\n      \"`docs:write` / `bcm:*` / `research:scope` where applicable. Phase 4\",\n      \"must **not** re-file what Phase 3 already filed. Before creating\",\n      \"**any** downstream issue (`req:write`, `docs:write`, `bcm:*`,\",\n      \"`research:scope`) for a drafted artifact, dedup against existing\",\n      \"issues:\",\n      \"\",\n      \"1. **Search open AND closed issues** for one already covering the\",\n      \"   same artifact, matching on the draft's title / basename — e.g.\",\n      \"   `gh issue list --search '<draft title or basename>' --state all --json number,title,state`.\",\n      \"   Searching **all states** is load-bearing: the original may have\",\n      \"   already been worked and **merged (closed)**, and an open-only\",\n      \"   search misses it — re-filing then collides with the shipped\",\n      \"   document and produces an ID-collision PR.\",\n      \"2. **If a match exists (open or closed), SKIP creation.** Link to\",\n      \"   the existing issue from the `## Downstream Artifacts` section\",\n      \"   instead of filing a new one.\",\n      \"3. **Only create issues for follow-up work that has no Phase 3\",\n      \"   draft.** A drafted artifact already has its downstream issue;\",\n      \"   file new issues only for items the draft phase did not cover.\",\n      \"4. **Be idempotent.** Re-running the same `meeting:link` issue must\",\n      \"   file nothing new — a second run finds the first run's issues\",\n      \"   (now open or closed) via the same search and skips them.\",\n      \"\",\n      \"Apply this gate to **both** Step 2 (requirement issues) and Step 4\",\n      \"(action-item routing) below.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      ...renderIssueTypeAssignmentBlanket(),\n      \"\",\n      \"1. Read the drafts from Phase 3 (if they exist) and the extraction\",\n      \"   from Phase 1 at `<meetingsRoot>/insights/{type}/<basename>.md`.\",\n      \"   Re-read the extraction frontmatter for `meeting_kind` and `areas`,\",\n      \"   then build the area-gate: the set of `docRoot` sub-folders that\",\n      \"   are in scope for direct edits on this meeting. Apply the rules in\",\n      \"   the **Areas filtering** section above.\",\n      \"2. Create requirement issues using `gh issue create` with appropriate labels.\",\n      \"   **First apply the Idempotent dedup gate above:** search open AND\",\n      \"   closed issues for one already covering the drafted requirement\",\n      \"   (match on its title / basename) and **skip creation when a match\",\n      \"   exists** — Phase 3 already filed a `req:write` issue per requirement\",\n      \"   draft, so file here only for requirements with no Phase 3 draft.\",\n      \"   Include a `## Traceability` section in each issue body linking back to\",\n      \"   the source meeting and extraction file. Issue creation is **not**\",\n      \"   gated by areas.\",\n      \"3. Create ADR issues if technology decisions need formal records.\",\n      \"   Include a `## Traceability` section in each. Not gated by areas.\",\n      \"4. **Route action items per the Action-item filing policy — do\",\n      \"   not file a generic `action-item` issue per task.** Read each\",\n      \"   action item's `disposition` tag from the extraction (re-apply\",\n      \"   the **agent-workability test** if the tag is missing):\",\n      \"   - **Agent-workable** (yields a doc deliverable an agent can\",\n      \"     author): file it through its **dedicated downstream channel**\",\n      \"     — a `req:write` issue for a requirement, a `docs:write` issue\",\n      \"     for a docs page, `bcm:*` for a capability model, a\",\n      \"     `research:scope` issue for a research note, or a roadmap /\",\n      \"     product-doc follow-up. **First apply the Idempotent dedup gate\",\n      \"     above:** search open AND closed issues for one already covering\",\n      \"     this artifact and **skip creation when a match exists** (link\",\n      \"     to it instead) — file only for action items that have no Phase\",\n      \"     3 draft. Use the matching template from the issue-templates\",\n      \"     page; include a `## Traceability` section. Issue creation is\",\n      \"     not gated by areas.\",\n      \"   - **Human-owned** (send/schedule/install/decide/communicate/\",\n      \"     get-access/build-elsewhere): record it **only** in the notes\",\n      \"     `## Action Items` table (step 8 already carries the table\",\n      \"     forward). **File no GitHub issue.** When ambiguous, treat the\",\n      \"     item as human-owned.\",\n      \"   If the project disabled the split via\",\n      \"   `meetings.actionItemFiling.enabled: false`, fall back to filing\",\n      \"   a follow-up issue for every action item not already covered by\",\n      \"   a Phase 3 draft.\",\n      \"5. Cross-reference the meeting in any existing documents that were\",\n      \"   discussed **and that live under an in-scope `docRoot`**. For\",\n      \"   discussed documents under an out-of-scope `docRoot`, open a\",\n      \"   follow-up `type:docs` issue instead of editing the doc directly.\",\n      \"6. Apply direct product/strategy doc updates for items flagged as\",\n      \"   **Firm** confidence. When the project declares `meetingAreas`,\",\n      \"   gate these edits: only apply them when the target path lies\",\n      \"   under an in-scope `docRoot`, and for Firm items targeting an\",\n      \"   out-of-scope `docRoot` open a follow-up `type:docs` issue\",\n      \"   noting the area and the target path. When the project has not\",\n      \"   declared any `meetingAreas`, apply Firm updates unrestricted\",\n      \"   (the degenerate case above). For the kind `planning`, also\",\n      \"   update the active sprint-plan doc directly (when the\",\n      \"   sprint-plan doc's area is in-scope, or always when no\",\n      \"   `meetingAreas` are declared); for the kind `review`, mark\",\n      \"   completed tasks in that same doc.\",\n      \"7. **Update the extraction file** at\",\n      \"   `<meetingsRoot>/insights/{type}/<basename>.md` with a\",\n      \"   `## Downstream Artifacts` section listing every issue and\",\n      \"   document created from this meeting. Note any items that were\",\n      \"   deferred to follow-up issues because of the area gate.\",\n      \"8. **Update the meeting notes** at\",\n      \"   `<meetingsRoot>/notes/{type}/<basename>.md` with a\",\n      \"   `## Related Issues` section listing all issues created from this\",\n      \"   meeting.\",\n      \"9. Comment on the parent extract issue with a summary linking to all\",\n      \"   created artifacts.\",\n      \"10. Commit and push (if any file changes were made), then close the\",\n      `    link issue ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## GitHub Integration\",\n      \"\",\n      \"- Use `gh` CLI for all GitHub operations\",\n      \"- Apply the appropriate `meeting:*` phase label to each phase issue\",\n      \"- Use `type:docs` for documentation-producing issues, `type:chore` for\",\n      \"  maintenance/organizational tasks the pipeline can action\",\n      \"- Do **not** file issues for human-owned action items — per the\",\n      \"  **Action-item filing policy** they live only in the notes\",\n      \"  `## Action Items` table\",\n      \"- Use `status:` labels to track progress (`status:ready`, `status:in-progress`, `status:done`)\",\n      \"- Reference the source meeting transcript in all created issues\",\n      \"- Link phase issues with `Depends on: #N` to enforce ordering\",\n      \"\",\n      \"## When to Shorten the Pipeline\",\n      \"\",\n      \"- **Short meetings** (<30 min, <2000 words): combine extract + notes into one session\",\n      \"- **No requirements or decisions**: Phase 1 skips creating the `meeting:draft` issue\",\n      \"- **Only action items**: extract + notes + link (3 phase issues)\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off meeting transcript processing. */\nconst processMeetingSkill: AgentSkill = {\n  name: \"process-meeting\",\n  description:\n    \"Process a meeting transcript through the 4-phase meeting analysis pipeline\",\n  disableModelInvocation: true,\n  userInvocable: true,\n  context: \"fork\",\n  agent: \"meeting-analyst\",\n  platforms: { cursor: { exclude: true } },\n  instructions: [\n    \"# Process Meeting\",\n    \"\",\n    \"Kick off meeting processing by executing Phase 1 (Extract) and\",\n    \"creating downstream phase issues for the remaining phases. Inputs\",\n    \"live in the **sibling-tree layout**: pass any file from\",\n    \"`<meetingsRoot>/notes/{type}/` or `<meetingsRoot>/transcripts/{type}/`\",\n    \"(both, notes-only, and transcript-only are all valid input cases).\",\n    \"\",\n    \"## Usage\",\n    \"\",\n    \"/process-meeting <path-to-notes-or-transcript>\",\n    \"\",\n    \"## Basename-pairing algorithm\",\n    \"\",\n    \"The user may pass either a notes-tree path or a transcripts-tree\",\n    \"path. Resolve the sibling implicitly via filesystem lookup —\",\n    \"do **not** prompt the user or fail-loud when the sibling is\",\n    \"absent:\",\n    \"\",\n    \"1. Infer the **basename** (filename without the `.md` extension)\",\n    \"   and the `{internal,external}` partition from the provided path.\",\n    \"   Both segments are usually adjacent in the path —\",\n    \"   `…/notes/internal/2026-03-14-sprint-kickoff.md` yields basename\",\n    \"   `2026-03-14-sprint-kickoff` and type `internal`.\",\n    \"2. Determine the **input tree** from the path:\",\n    \"   - If the path contains `/notes/`, treat it as the notes input\",\n    \"     and look for the sibling at\",\n    \"     `<meetingsRoot>/transcripts/<type>/<basename>.md`.\",\n    \"   - If the path contains `/transcripts/`, treat it as the\",\n    \"     transcript input and look for the sibling at\",\n    \"     `<meetingsRoot>/notes/<type>/<basename>.md`.\",\n    \"   - If the path matches neither (e.g. an ad-hoc location), infer\",\n    \"     basename + type as best you can from the filename and\",\n    \"     surrounding folder segments, then proceed with whichever\",\n    \"     sibling-tree lookups succeed. Best-effort, never fail-loud.\",\n    \"3. Read **every** sibling that exists on disk. The combination\",\n    \"   (notes present, transcript present, both present) selects the\",\n    \"   Phase-1 input case from the **input-case matrix** in the\",\n    \"   `meeting-analyst` agent prompt.\",\n    \"4. A missing sibling is a normal outcome — proceed with whatever\",\n    \"   was found. Notes-only and transcript-only are both valid\",\n    \"   Phase-1 input cases; the agent never warns or prompts the\",\n    \"   user about the absence.\",\n    \"\",\n    \"## Steps\",\n    \"\",\n    \"1. Resolve the basename, partition, and any sibling files using\",\n    \"   the **Basename-pairing algorithm** above\",\n    \"2. Execute Phase 1 (Extract) — categorize the available content into\",\n    \"   decisions, requirements, action items, open questions, and more.\",\n    \"   Tag each action item's disposition (`agent-workable` vs\",\n    \"   `human-owned`) per the agent's **Action-item filing policy** so\",\n    \"   Phase 4 keeps human-owned tasks out of the issue queue\",\n    \"3. Write the extraction to\",\n    \"   `<meetingsRoot>/insights/{type}/<basename>.md`\",\n    \"4. Create downstream phase issues using `gh issue create`:\",\n    \"   - `meeting:notes` issue (always)\",\n    \"   - `meeting:draft` issue (if requirements or decisions were found)\",\n    \"   - `meeting:link` issue (always)\",\n    \"\",\n    ...renderIssueTypeAssignmentStep(),\n    \"5. Each downstream issue includes `Depends on:` linking to its predecessor\",\n    \"6. Commit and push the extraction file\",\n    \"\",\n    \"## Input\",\n    \"\",\n    \"Provide a path to a file in either `notes/` or `transcripts/`. The\",\n    \"agent will look up the sibling automatically via basename match. A\",\n    \"missing sibling is a normal case (notes-only or transcript-only) —\",\n    \"the agent handles all three input cases.\",\n    \"\",\n    \"## Output\",\n    \"\",\n    \"- A structured extraction at\",\n    \"  `<meetingsRoot>/insights/{type}/<basename>.md`\",\n    \"- Phase issues with `meeting:*` labels for downstream agent sessions\",\n    \"  to pick up (notes, draft, link)\",\n  ].join(\"\\n\"),\n};\n\n/**\n * Build the meeting-analysis bundle with the supplied default sub-agent\n * model tier. The tier knob lets consumers globally demote the\n * `meeting-analyst` sub-agent to BALANCED (sonnet) — which is the\n * post-2026-05-08 default — without forking the bundle.\n */\nexport function buildMeetingAnalysisBundle(\n  tier: AgentModel = AGENT_MODEL.BALANCED,\n): AgentRuleBundle {\n  return {\n    name: \"meeting-analysis\",\n    description:\n      \"Meeting transcript processing workflow with 4-phase pipeline (extract, notes, draft, link)\",\n    appliesWhen: () => true,\n    rules: [\n      {\n        name: \"meeting-processing-workflow\",\n        description:\n          \"Describes the 4-phase meeting processing pipeline, extraction taxonomy, and labeling conventions\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Meeting Processing Workflow\",\n          \"\",\n          \"Use `/process-meeting <path>` to process a meeting through a\",\n          \"4-phase pipeline (extract → notes → draft → link). Each phase runs as a\",\n          \"separate agent session tracked by a GitHub issue with a `meeting:*` label.\",\n          \"See the `meeting-analyst` agent definition for full workflow details.\",\n          \"\",\n          \"Meeting artifacts live in **three parallel trees** rooted at the\",\n          \"project's meetings root:\",\n          \"\",\n          \"- `transcripts/{internal,external}/` — verbatim transcripts (evidence)\",\n          \"- `notes/{internal,external}/` — curated narrative summary\",\n          \"  (input + Phase 2 output)\",\n          \"- `insights/{internal,external}/` — structured extraction (Phase 1 output)\",\n          \"\",\n          \"The three trees share identical basenames so a meeting's siblings\",\n          \"are looked up by filename, not by frontmatter cross-references.\",\n          \"Phase 1 accepts every input case (notes + transcript, notes only,\",\n          \"or transcript only) and Phase 2 enhances the notes file in place\",\n          \"rather than authoring it from scratch.\",\n          \"\",\n          \"Notes and insights files may carry optional frontmatter fields\",\n          \"`slug`, `source`, `transcript_available`, and `confidence`\",\n          \"alongside the existing `meeting_type` and `areas` fields. Missing\",\n          \"frontmatter is treated as a normal input case — never fail-loud.\",\n          \"\",\n          \"Meeting notes may declare a `meeting_type` (one of the project's\",\n          \"recognized types) and an `areas: [...]` list. The `meeting_type`\",\n          \"resolves to a generic kind — `planning` / `review` / `brainstorm` /\",\n          \"`standup` / `external` / `other` — that drives type-specific\",\n          \"extraction rules in phases 1–2. The `areas` list scopes phase-4\",\n          \"direct edits to the doc-root sub-folders declared in the project's\",\n          \"**Area → doc-root mapping** table. When both fields are absent\",\n          \"the pipeline falls back to the default workflow (kind `other`,\",\n          \"no area gating).\",\n          \"\",\n          \"Phase 4 applies an **agent-workability split** to action items:\",\n          \"items that yield a documentation deliverable an agent can author\",\n          \"are filed through their dedicated downstream channel\",\n          \"(`req:write`, `docs:write`, `bcm:*`, `research:scope`, roadmap\",\n          \"follow-up); human-owned tasks (send / schedule / install /\",\n          \"decide / communicate / get-access / build-elsewhere) are\",\n          \"recorded **only** in the notes `## Action Items` table, which is\",\n          \"the **system of record for human follow-ups** — no GitHub issue\",\n          \"is filed for them. Consumers tune or disable the split via\",\n          \"`AgentConfigOptions.meetings.actionItemFiling`.\",\n        ].join(\"\\n\"),\n        platforms: {\n          cursor: { exclude: true },\n        },\n        tags: [\"workflow\"],\n      },\n    ],\n    skills: [processMeetingSkill],\n    subAgents: [buildMeetingAnalystSubAgent(tier)],\n    labels: [\n      {\n        name: \"type:meeting-processing\",\n        color: \"5319E7\",\n        description: \"Meeting transcript processing pipeline\",\n      },\n      {\n        name: \"meeting:extract\",\n        color: \"C5DEF5\",\n        description: \"Phase 1: raw extraction from a meeting transcript\",\n      },\n      {\n        name: \"meeting:notes\",\n        color: \"BFDADC\",\n        description: \"Phase 2: curated notes derived from an extraction\",\n      },\n      {\n        name: \"meeting:draft\",\n        color: \"D4C5F9\",\n        description: \"Phase 3: draft follow-up issues proposed from notes\",\n      },\n      {\n        name: \"meeting:link\",\n        color: \"FEF2C0\",\n        description:\n          \"Phase 4: linking/reconciling drafted issues with existing work\",\n      },\n    ],\n  };\n}\n\n/**\n * Default-tier instance of the meeting-analysis bundle, preserved for\n * backward compatibility with consumers that import the const directly.\n * The factory above is the canonical entry point when a consumer\n * supplies `AgentConfigOptions.defaultAgentTier`.\n */\nexport const meetingAnalysisBundle: AgentRuleBundle =\n  buildMeetingAnalysisBundle();\n","import { RunRatioConfig } from \"../agent-config-options\";\n\n/**\n * Default dispatch-to-housekeeping ratio — openhi's `DISPATCHER.md`\n * ships a 4:1 ratio: four consecutive dispatch runs, then one\n * housekeeping run, then the counter wraps. The ratio value stored\n * here is the dispatch-run count per housekeeping run; with\n * `ratio = 4`, runs 1–4 dispatch and run 5 housekeeps. The cycle\n * length is therefore `ratio + 1`.\n *\n * @see RunRatioConfig\n */\nexport const DEFAULT_DISPATCH_TO_HOUSEKEEPING_RATIO = 4;\n\n/**\n * Default on-disk path for the orchestrator run-counter state file,\n * relative to the repo root. The file is tiny JSON\n * (`{ \"run_counter\": <n> }`) and is gitignored in most consumer repos\n * because it's local-only — each operator's orchestrator session\n * maintains its own counter.\n *\n * @see RunRatioConfig\n */\nexport const DEFAULT_STATE_FILE_PATH = \".state/orchestrator-runs.json\";\n\n/**\n * Default recommended model label for dispatch runs. Rendered into\n * the orchestrator-conventions rule so agents and humans can read the\n * model pairing at a glance; the string is purely informational and\n * does not cause configulator to set `AGENT_MODEL` on the sub-agent.\n *\n * @see RunRatioConfig\n */\nexport const DEFAULT_DISPATCH_MODEL = \"opus\";\n\n/**\n * Default recommended model label for housekeeping runs. See\n * `DEFAULT_DISPATCH_MODEL` for the rendering contract. Housekeeping\n * runs are mechanical (batch PR review + maintenance scan), so a\n * cheaper model like Sonnet is the documented recommendation.\n *\n * @see RunRatioConfig\n */\nexport const DEFAULT_HOUSEKEEPING_MODEL = \"sonnet\";\n\n/**\n * Fully-resolved run-ratio settings. Every field is defaulted so\n * downstream renderers can reason about a single canonical shape.\n */\nexport interface ResolvedRunRatio {\n  readonly enabled: boolean;\n  readonly ratio: number;\n  readonly stateFilePath: string;\n  readonly dispatchModel: string;\n  readonly housekeepingModel: string;\n}\n\n/**\n * Resolve a (possibly absent) `RunRatioConfig` into a canonical\n * `ResolvedRunRatio` with every field filled in. Unset fields\n * cascade from their documented defaults.\n *\n * Malformed configs (non-integer or non-positive ratio, empty or\n * whitespace-only state file path) throw a descriptive `Error` —\n * callers should not need to guard against it at runtime.\n */\nexport function resolveRunRatio(config?: RunRatioConfig): ResolvedRunRatio {\n  const ratio = config?.ratio ?? DEFAULT_DISPATCH_TO_HOUSEKEEPING_RATIO;\n  assertValidRatio(ratio);\n\n  const stateFilePath = config?.stateFilePath ?? DEFAULT_STATE_FILE_PATH;\n  assertValidStateFilePath(stateFilePath);\n\n  return {\n    enabled: config?.enabled ?? true,\n    ratio,\n    stateFilePath,\n    dispatchModel: config?.dispatchModel ?? DEFAULT_DISPATCH_MODEL,\n    housekeepingModel: config?.housekeepingModel ?? DEFAULT_HOUSEKEEPING_MODEL,\n  };\n}\n\n/**\n * Synth-time validation hook. Throws a descriptive `Error` when the\n * supplied `RunRatioConfig` is malformed. Called by\n * `AgentConfig.preSynthesize` before any rendering so a misconfigured\n * ratio fails the build instead of silently shipping broken\n * housekeeping cadence. Returns the resolved ratio unchanged so\n * callers can write `const rr = validateRunRatioConfig(config)` in\n * one line.\n *\n * Malformed cases rejected here:\n *\n * - `ratio` non-integer, zero, or negative.\n * - `stateFilePath` empty / whitespace-only, or an absolute path\n *   (the state file must live inside the repo).\n */\nexport function validateRunRatioConfig(\n  config?: RunRatioConfig,\n): ResolvedRunRatio {\n  return resolveRunRatio(config);\n}\n\n/**\n * Compute the run type (`\"dispatch\"` or `\"housekeeping\"`) for a\n * given run counter value and resolved ratio. Used by the TypeScript\n * side (tests, downstream consumers that want to reason about the\n * cadence without shelling out). The shell helper produced by\n * `renderRunRatioShellHelpers` implements the same logic.\n *\n * Every `(ratio + 1)`th run is a housekeeping run; all others\n * dispatch. For `ratio = 4`, runs 1–4 dispatch and run 5\n * housekeeps; run 6 is again dispatch; run 10 housekeeps.\n */\nexport function classifyRun(\n  runCounter: number,\n  ratio: ResolvedRunRatio,\n): \"dispatch\" | \"housekeeping\" {\n  if (!ratio.enabled) {\n    return \"dispatch\";\n  }\n  const cycle = ratio.ratio + 1;\n  return runCounter > 0 && runCounter % cycle === 0\n    ? \"housekeeping\"\n    : \"dispatch\";\n}\n\n/**\n * Render the markdown subsection appended to the\n * `orchestrator-conventions` rule. Always returns a non-empty string\n * so the orchestrator rule documents the cadence even when the\n * consumer relies on the defaults.\n */\nexport function renderRunRatioSection(ratio: ResolvedRunRatio): string {\n  const lines: Array<string> = [\n    \"## Run ratio (dispatch vs housekeeping)\",\n    \"\",\n    \"The orchestrator keeps a **persistent run counter** and interleaves\",\n    \"dispatch runs (pick the next ready issue, recommend a worker) with\",\n    \"**housekeeping runs** (batch PR review + maintenance scan) on a\",\n    \"configurable ratio. This mirrors openhi's `DISPATCHER.md` contract:\",\n    \"multiple dispatch runs feed the worker queue, then one batched\",\n    \"housekeeping run flushes review backlog and runs maintenance\",\n    \"triage so the pipeline never drifts.\",\n    \"\",\n  ];\n\n  if (!ratio.enabled) {\n    lines.push(\n      \"**The run ratio is disabled for this project.** Every orchestrator\",\n      \"run executes the full dispatch pipeline; PR review and maintenance\",\n      \"remain manual invocations. Enable the ratio via\",\n      \"`AgentConfigOptions.runRatio.enabled = true` once the operator is\",\n      \"comfortable with the counter-backed cadence.\",\n      \"\",\n    );\n    return lines.join(\"\\n\");\n  }\n\n  const cycle = ratio.ratio + 1;\n\n  lines.push(\n    \"### Cadence\",\n    \"\",\n    `The cycle length is **${cycle}** runs:`,\n    \"\",\n    `- Runs 1 through ${ratio.ratio} execute the **dispatch** pipeline`,\n    `  (recommended model: \\`${ratio.dispatchModel}\\`).`,\n    `- Run ${cycle} executes the **housekeeping** pipeline`,\n    `  (recommended model: \\`${ratio.housekeepingModel}\\`).`,\n    `- The counter wraps — run ${cycle + 1} is a dispatch run again, run ${cycle * 2} is the next housekeeping run, and so on.`,\n    \"\",\n    \"The orchestrator increments the counter **once per invocation** at\",\n    \"the top of the run, before any pipeline phase executes. The\",\n    \"pre-increment value is never observed — the tick always returns\",\n    \"the post-increment counter and the classified run type in a single\",\n    \"atomic update.\",\n    \"\",\n    \"### State file\",\n    \"\",\n    `The run counter persists at \\`${ratio.stateFilePath}\\`. The file is`,\n    \"plain JSON with a single `run_counter` integer field:\",\n    \"\",\n    \"```json\",\n    '{ \"run_counter\": 42 }',\n    \"```\",\n    \"\",\n    \"The state file is **gitignored** in consumer repos (it is local to\",\n    \"each operator's machine). On a first run, or if the file is missing\",\n    \"or corrupt, the orchestrator recreates it with `run_counter: 1`.\",\n    \"\",\n    \"### Dispatch-run pipeline\",\n    \"\",\n    \"1. Phase A — startup (fetch + checkout default branch).\",\n    \"2. Phase C — triage unblock (resolve `Depends on:` chains).\",\n    \"3. Phase E — queue scan (pick the top `PICK` line, run the scope\",\n    \"   gate, emit `NEXT_WORK_ITEM`).\",\n    \"4. Phase F — cleanup.\",\n    \"\",\n    \"### Housekeeping-run pipeline\",\n    \"\",\n    \"1. Phase A — startup.\",\n    \"2. Phase B — batch PR review across every eligible open PR.\",\n    \"3. Phase D — maintenance scan (stale detection, orphaned branches,\",\n    \"   needs-attention summary).\",\n    \"4. Phase F — cleanup.\",\n    \"\",\n    \"### Model recommendations\",\n    \"\",\n    `Dispatch runs should use \\`${ratio.dispatchModel}\\` — the routing`,\n    \"logic, scope gate, and funnel-tier sort benefit from the stronger\",\n    \"reasoning model. Housekeeping runs are mechanical (read CI status,\",\n    \"toggle labels, post canned comments) and should use\",\n    `\\`${ratio.housekeepingModel}\\` so the batched PR review and`,\n    \"maintenance scan cost less per invocation.\",\n    \"\",\n    \"These strings are **informational** — they surface in the\",\n    \"orchestrator's rendered rule content so operators know which model\",\n    \"to run each session against. Configulator does not inject them as\",\n    \"`model:` frontmatter on the sub-agent definition; the operator (or\",\n    \"a scheduled task) picks the model at invocation time.\",\n  );\n\n  return lines.join(\"\\n\");\n}\n\n/**\n * Render a shell-script snippet embedded in `check-blocked.sh`. The\n * snippet declares a `run_counter_tick()` function that:\n *\n * 1. Reads the state file (creating it with `run_counter: 1` if\n *    missing or unparseable).\n * 2. Increments the counter.\n * 3. Writes the new counter back atomically (temp file + `mv`).\n * 4. Echoes the post-increment counter and the classified run type\n *    (`dispatch` or `housekeeping`) in the canonical\n *    `run=<n> type=<dispatch|housekeeping>` format.\n *\n * Returns the body of a shell function block (including the\n * `run_counter_tick()` wrapper) so the surrounding script can splice\n * it inline at the exact indent level it wants.\n */\nexport function renderRunRatioShellHelpers(ratio: ResolvedRunRatio): string {\n  const cycle = ratio.ratio + 1;\n  return [\n    \"# Increment the orchestrator run counter and classify the run.\",\n    \"# Reads the state file (creating it on first run or corruption),\",\n    \"# increments the counter, writes back atomically, and echoes\",\n    \"# `run=<n> type=<dispatch|housekeeping>` on stdout.\",\n    \"#\",\n    \"# Uses the cycle length (ratio + 1) hard-coded from the resolved\",\n    \"# RunRatioConfig so the shell helper matches the rendered rule\",\n    \"# content byte-for-byte.\",\n    \"run_counter_tick() {\",\n    '  local state_file=\"$ORCHESTRATOR_STATE_FILE\"',\n    \"  local state_dir\",\n    '  state_dir=$(dirname \"$state_file\")',\n    '  mkdir -p \"$state_dir\" 2>/dev/null || true',\n    \"\",\n    \"  local current=0\",\n    '  if [ -f \"$state_file\" ]; then',\n    \"    # jq returns empty string on parse failure; guard against it.\",\n    \"    current=$(jq -r '.run_counter // 0' \\\"$state_file\\\" 2>/dev/null || echo 0)\",\n    '    case \"$current\" in',\n    \"      ''|*[!0-9]*) current=0 ;;\",\n    \"    esac\",\n    \"  fi\",\n    \"\",\n    \"  local next=$((current + 1))\",\n    \"\",\n    '  local tmp_file=\"${state_file}.tmp.$$\"',\n    '  printf \\'{ \"run_counter\": %d }\\\\n\\' \"$next\" > \"$tmp_file\"',\n    '  mv \"$tmp_file\" \"$state_file\"',\n    \"\",\n    \"  local run_type=dispatch\",\n    `  if [ $((next % ${cycle})) -eq 0 ]; then`,\n    \"    run_type=housekeeping\",\n    \"  fi\",\n    '  printf \\'run=%d type=%s\\\\n\\' \"$next\" \"$run_type\"',\n    \"}\",\n  ].join(\"\\n\");\n}\n\n/*******************************************************************************\n *\n * Internal helpers\n *\n ******************************************************************************/\n\nfunction assertValidRatio(ratio: number): void {\n  if (!Number.isInteger(ratio)) {\n    throw new Error(\n      `RunRatioConfig.ratio must be a positive integer; got ${ratio}`,\n    );\n  }\n  if (ratio < 1) {\n    throw new Error(\n      `RunRatioConfig.ratio must be a positive integer; got ${ratio}`,\n    );\n  }\n}\n\nfunction assertValidStateFilePath(stateFilePath: string): void {\n  const trimmed = stateFilePath.trim();\n  if (trimmed.length === 0) {\n    throw new Error(\n      \"RunRatioConfig.stateFilePath must be a non-empty string relative to the repo root\",\n    );\n  }\n  if (trimmed.startsWith(\"/\")) {\n    throw new Error(\n      `RunRatioConfig.stateFilePath must be relative to the repo root (no leading '/'); got ${stateFilePath}`,\n    );\n  }\n}\n","import { isScheduledTaskOwnedByExcluded } from \"./bundle-ownership\";\nimport {\n  ScheduledTaskEntry,\n  ScheduledTaskOverride,\n  ScheduledTasksConfig,\n} from \"../agent-config-options\";\n\n/**\n * Recommended model labels surfaced on the scheduled-task SKILL.md\n * frontmatter. The labels are **informational** — configulator does not\n * pin a model per task (the Claude Code scheduled-task runtime does not\n * support per-task model pinning yet). Operators choose the model at\n * invocation time; splitting workers by type still gives independent\n * cadence and clean opt-in/opt-out control.\n *\n * @see ScheduledTasksConfig\n */\nexport const SCHEDULED_TASK_MODEL_VALUES = [\"opus\", \"sonnet\", \"haiku\"] as const;\nexport type ScheduledTaskModel = (typeof SCHEDULED_TASK_MODEL_VALUES)[number];\n\n/**\n * Valid `kind` values for a scheduled-task entry. See\n * `ScheduledTaskEntry.kind` for semantics.\n */\nexport const SCHEDULED_TASK_KIND_VALUES = [\"issue-worker\", \"pipeline\"] as const;\nexport type ScheduledTaskKind = (typeof SCHEDULED_TASK_KIND_VALUES)[number];\n\n/**\n * Default `kind` applied when a `ScheduledTaskEntry` does not declare\n * one. The overwhelming majority of registered tasks delegate work to\n * the generic `issue-worker`; only end-to-end pipeline managers like\n * the orchestrator opt into `kind: \"pipeline\"`.\n */\nexport const DEFAULT_SCHEDULED_TASK_KIND: ScheduledTaskKind = \"issue-worker\";\n\n/**\n * Default root directory (relative to the repo root) for scheduled-task\n * files. Mirrors the vortex layout — one directory per task at\n * `.claude/scheduled-tasks/<taskId>/SKILL.md`.\n *\n * @see ScheduledTasksConfig\n */\nexport const DEFAULT_SCHEDULED_TASKS_ROOT = \".claude/scheduled-tasks\";\n\n/**\n * Off-peak cron sample surfaced in the rendered documentation. Every\n * 20 minutes during off-peak hours (before 08:00 and after 14:00\n * local). Informational only — tasks ship disabled by default with\n * no cron, so the consumer must opt in and set a cron explicitly.\n *\n * @see ScheduledTasksConfig\n */\nexport const DEFAULT_OFF_PEAK_CRON_EXAMPLE = \"3,23,43 0-7,14-23 * * *\";\n\n/**\n * A single fully-resolved scheduled-task entry. Returned by\n * `resolveScheduledTasks()`; the rendered documentation section and\n * the emitted `.claude/scheduled-tasks/<taskId>/SKILL.md` files are\n * derived from this list.\n */\nexport interface ResolvedScheduledTask {\n  /**\n   * Unique task directory name. Emitted under\n   * `<root>/<taskId>/SKILL.md`. Derived from the sub-agent name by\n   * default (e.g. `company-profile-analyst` → `worker-company-profile`).\n   */\n  readonly taskId: string;\n  /**\n   * Target sub-agent name (e.g. `company-profile-analyst`). The task's\n   * rendered prompt points operators at `.claude/agents/<agent>.md`.\n   */\n  readonly agent: string;\n  /**\n   * Human-readable agent label for rendered tables and frontmatter\n   * descriptions (e.g. `\"Company Profile\"`).\n   */\n  readonly agentLabel: string;\n  /**\n   * Primary GitHub `type:*` label (without the `type:` prefix). When\n   * `typeLabels` is unset, this is the sole type filter; when\n   * `typeLabels` is set, it is the first element.\n   */\n  readonly typeLabel: string;\n  /**\n   * Exact `type:*` label values (without the `type:` prefix) the\n   * worker picks up. When set (`length >= 1`), represents a\n   * multi-type filter (e.g. routing-bucket `worker-issue`). When\n   * unset, the `typeLabel` single-value filter applies.\n   */\n  readonly typeLabels?: ReadonlyArray<string>;\n  /**\n   * Optional phase-label prefix (e.g. `company:`). When present and\n   * `phaseLabels` is unset, the task's SKILL.md instructs the worker\n   * to filter on both `type:<typeLabel>` **and** any `<phasePrefix>*`\n   * label. Ignored when `phaseLabels` is set.\n   */\n  readonly phasePrefix?: string;\n  /**\n   * Exact phase-label values the worker filters on (e.g.\n   * `[\"req:write\"]`). When set (`length >= 1`), takes precedence over\n   * `phasePrefix`. When unset, the `phasePrefix` prefix-match\n   * applies.\n   */\n  readonly phaseLabels?: ReadonlyArray<string>;\n  /**\n   * Recommended model tier. Surfaced on the task's SKILL.md\n   * frontmatter and in the rendered documentation table.\n   */\n  readonly recommendedModel: ScheduledTaskModel;\n  /** Whether the task is emitted to disk. Default: `false`. */\n  readonly enabled: boolean;\n  /**\n   * Optional cron expression. When `null` the task is manual-only\n   * (runs only when an operator invokes it explicitly).\n   */\n  readonly cron: string | null;\n  /**\n   * Short one-line description for the rendered table and SKILL.md\n   * frontmatter.\n   */\n  readonly description: string;\n  /**\n   * Discriminator controlling how the SKILL.md body and the registered-\n   * tasks table cell are rendered. `\"issue-worker\"` (default) emits the\n   * standard delegate-to-issue-worker prompt; `\"pipeline\"` emits a\n   * pipeline-manager prompt that points the operator at the target\n   * sub-agent's full workflow and renders `_(none — pipeline manager)_`\n   * for the type-label cell.\n   */\n  readonly kind: ScheduledTaskKind;\n}\n\n/**\n * Canonical default registry of scheduled-task entries. One entry per\n * agent bundle that ships with configulator. Every entry is\n * **disabled by default** — consumers must explicitly opt in via\n * `ScheduledTasksConfig.overrides[taskId].enabled = true`.\n *\n * The registry mirrors the funnel-tier table in `tiers.ts` so the\n * dispatch ordering, scheduled-task filter, and orchestrator queue\n * scan all agree on the type-label taxonomy.\n */\nexport const DEFAULT_SCHEDULED_TASK_ENTRIES: ReadonlyArray<ResolvedScheduledTask> =\n  [\n    // Tier 0 — routing (issue-worker and orchestrator).\n    {\n      taskId: \"worker-issue\",\n      agent: \"issue-worker\",\n      agentLabel: \"Issue Worker\",\n      typeLabel: \"feat\",\n      typeLabels: [\n        \"feat\",\n        \"fix\",\n        \"chore\",\n        \"refactor\",\n        \"docs\",\n        \"release\",\n        \"hotfix\",\n      ],\n      kind: \"issue-worker\",\n      recommendedModel: \"sonnet\",\n      enabled: false,\n      cron: null,\n      description:\n        \"Generic issue worker for feat/fix/chore/refactor/docs/release/hotfix routing issues.\",\n    },\n    {\n      taskId: \"worker-orchestrator\",\n      agent: \"orchestrator\",\n      agentLabel: \"Orchestrator\",\n      // Pipeline tasks do not filter on a `type:*` label — the\n      // orchestrator runs an end-to-end cycle every invocation. The\n      // `typeLabel` field is required by the registry shape so we\n      // store the routing-bucket sentinel `feat`; rendered output\n      // uses the `_(none — pipeline manager)_` cell instead.\n      typeLabel: \"feat\",\n      kind: \"pipeline\",\n      recommendedModel: \"sonnet\",\n      enabled: false,\n      cron: null,\n      description:\n        \"End-to-end pipeline manager: triage, maintenance, queue scan, delegate the picked issue to the issue-worker, then cleanup.\",\n    },\n    // Tier 1 — research.\n    {\n      taskId: \"worker-research\",\n      agent: \"research-analyst\",\n      agentLabel: \"Research\",\n      typeLabel: \"research\",\n      phasePrefix: \"research:\",\n      kind: \"issue-worker\",\n      recommendedModel: \"opus\",\n      enabled: false,\n      cron: null,\n      description:\n        \"Generic research pipeline — scope, slice, verify phases tracked by research:* labels.\",\n    },\n    {\n      taskId: \"worker-industry-discovery\",\n      agent: \"industry-discovery-analyst\",\n      agentLabel: \"Industry Discovery\",\n      typeLabel: \"industry-discovery\",\n      phasePrefix: \"industry:\",\n      kind: \"issue-worker\",\n      recommendedModel: \"opus\",\n      enabled: false,\n      cron: null,\n      description:\n        \"Industry-vertical discovery — discover, evaluate, plan phases.\",\n    },\n    {\n      taskId: \"worker-standards-research\",\n      agent: \"standards-research-analyst\",\n      agentLabel: \"Standards Research\",\n      typeLabel: \"standards-research\",\n      phasePrefix: \"standards:\",\n      kind: \"issue-worker\",\n      recommendedModel: \"opus\",\n      enabled: false,\n      cron: null,\n      description: \"Standards / framework research pipeline.\",\n    },\n    {\n      taskId: \"worker-regulatory-research\",\n      agent: \"regulatory-research-analyst\",\n      agentLabel: \"Regulatory Research\",\n      typeLabel: \"regulatory-research\",\n      phasePrefix: \"regulatory:\",\n      kind: \"issue-worker\",\n      recommendedModel: \"opus\",\n      enabled: false,\n      cron: null,\n      description: \"Regulatory-framework research pipeline.\",\n    },\n    // Tier 2 — profiles.\n    {\n      taskId: \"worker-company-profile\",\n      agent: \"company-profile-analyst\",\n      agentLabel: \"Company Profile\",\n      typeLabel: \"company-profile\",\n      phasePrefix: \"company:\",\n      kind: \"issue-worker\",\n      recommendedModel: \"sonnet\",\n      enabled: false,\n      cron: null,\n      description:\n        \"Company research, drafting, followup, match, refresh, and competitive analysis phases.\",\n    },\n    {\n      taskId: \"worker-people-profile\",\n      agent: \"people-profile-analyst\",\n      agentLabel: \"People Profile\",\n      typeLabel: \"people-profile\",\n      phasePrefix: \"people:\",\n      kind: \"issue-worker\",\n      recommendedModel: \"sonnet\",\n      enabled: false,\n      cron: null,\n      description: \"Person research and drafting phases.\",\n    },\n    {\n      taskId: \"worker-software-profile\",\n      agent: \"software-profile-analyst\",\n      agentLabel: \"Software Profile\",\n      typeLabel: \"software-profile\",\n      phasePrefix: \"software:\",\n      kind: \"issue-worker\",\n      recommendedModel: \"sonnet\",\n      enabled: false,\n      cron: null,\n      description:\n        \"Software product research, profiling, feature-matrix, capability mapping, and followup phases.\",\n    },\n    {\n      taskId: \"worker-customer-profile\",\n      agent: \"customer-profile-analyst\",\n      agentLabel: \"Customer Profile\",\n      typeLabel: \"customer-profile\",\n      phasePrefix: \"customer:\",\n      kind: \"issue-worker\",\n      recommendedModel: \"sonnet\",\n      enabled: false,\n      cron: null,\n      description: \"Customer discovery, profiling, and analysis phases.\",\n    },\n    // Tier 3 — synthesis.\n    {\n      taskId: \"worker-business-models\",\n      agent: \"business-models-analyst\",\n      agentLabel: \"Business Models\",\n      typeLabel: \"business-model\",\n      phasePrefix: \"business-models:\",\n      kind: \"issue-worker\",\n      recommendedModel: \"opus\",\n      enabled: false,\n      cron: null,\n      description: \"Business-model canvas authoring and segment synthesis.\",\n    },\n    {\n      taskId: \"worker-bcm-writer\",\n      agent: \"bcm-writer\",\n      agentLabel: \"BCM Writer\",\n      typeLabel: \"bcm-document\",\n      phasePrefix: \"bcm:\",\n      kind: \"issue-worker\",\n      recommendedModel: \"sonnet\",\n      enabled: false,\n      cron: null,\n      description:\n        \"Business capability-model document authoring phases (outline, scaffold, context, connect).\",\n    },\n    {\n      taskId: \"worker-requirements-analyst\",\n      agent: \"requirements-analyst\",\n      agentLabel: \"Requirements Analyst\",\n      typeLabel: \"requirement\",\n      phasePrefix: \"req:\",\n      kind: \"issue-worker\",\n      recommendedModel: \"opus\",\n      enabled: false,\n      cron: null,\n      description: \"Requirements gap discovery — scan, draft-trace phases.\",\n    },\n    {\n      taskId: \"worker-requirements-writer\",\n      agent: \"requirements-writer\",\n      agentLabel: \"Requirements Writer\",\n      typeLabel: \"requirement\",\n      phaseLabels: [\"req:write\"],\n      kind: \"issue-worker\",\n      recommendedModel: \"sonnet\",\n      enabled: false,\n      cron: null,\n      description: \"Requirements document authoring (req:write label).\",\n    },\n    {\n      taskId: \"worker-requirements-reviewer\",\n      agent: \"requirements-reviewer\",\n      agentLabel: \"Requirements Reviewer\",\n      typeLabel: \"requirement\",\n      phaseLabels: [\"req:review\", \"req:deprecate\"],\n      kind: \"issue-worker\",\n      recommendedModel: \"opus\",\n      enabled: false,\n      cron: null,\n      description:\n        \"Requirements review and deprecation phases (req:review / req:deprecate).\",\n    },\n    // Tier 4 — support.\n    {\n      taskId: \"worker-meeting-analysis\",\n      agent: \"meeting-analyst\",\n      agentLabel: \"Meeting Analysis\",\n      typeLabel: \"meeting-processing\",\n      phasePrefix: \"meeting:\",\n      kind: \"issue-worker\",\n      recommendedModel: \"sonnet\",\n      enabled: false,\n      cron: null,\n      description:\n        \"Meeting transcript processing pipeline (extract, notes, draft, link).\",\n    },\n    {\n      taskId: \"worker-agenda\",\n      agent: \"agenda-analyst\",\n      agentLabel: \"Agenda\",\n      typeLabel: \"agenda\",\n      phasePrefix: \"agenda:\",\n      kind: \"issue-worker\",\n      recommendedModel: \"sonnet\",\n      enabled: false,\n      cron: null,\n      description: \"Meeting-agenda drafting pipeline.\",\n    },\n    {\n      taskId: \"worker-maintenance\",\n      agent: \"maintenance-audit\",\n      agentLabel: \"Maintenance\",\n      typeLabel: \"maintenance\",\n      phasePrefix: \"maint:\",\n      kind: \"issue-worker\",\n      recommendedModel: \"haiku\",\n      enabled: false,\n      cron: null,\n      description:\n        \"Documentation-maintenance audit pipeline (scan, fix, verify phases).\",\n    },\n    {\n      taskId: \"worker-pr-review\",\n      agent: \"pr-reviewer\",\n      agentLabel: \"PR Review\",\n      typeLabel: \"pr-review\",\n      kind: \"issue-worker\",\n      recommendedModel: \"haiku\",\n      enabled: false,\n      cron: null,\n      description:\n        \"Scans open PRs and reviews / merges eligible ones. No type-label filter.\",\n    },\n    {\n      taskId: \"worker-docs-sync\",\n      agent: \"docs-sync\",\n      agentLabel: \"Docs Sync\",\n      typeLabel: \"docs-sync\",\n      phasePrefix: \"docs-sync:\",\n      kind: \"issue-worker\",\n      recommendedModel: \"sonnet\",\n      enabled: false,\n      cron: null,\n      description:\n        \"Documentation-sync drift-detection and audit pipeline (scaffolding release — behavior carried by downstream child issues of the parent docs-sync epic).\",\n    },\n  ];\n\n/**\n * Fully-resolved scheduled-tasks settings. Every field is defaulted so\n * downstream renderers can reason about a single canonical shape.\n */\nexport interface ResolvedScheduledTasks {\n  readonly enabled: boolean;\n  readonly root: string;\n  readonly tasks: ReadonlyArray<ResolvedScheduledTask>;\n}\n\n/**\n * Resolve a (possibly absent) `ScheduledTasksConfig` into a canonical\n * `ResolvedScheduledTasks` with every field filled in. Unset fields\n * cascade from their documented defaults.\n *\n * The resolver merges three sources in this order:\n *\n * 1. `DEFAULT_SCHEDULED_TASK_ENTRIES` — the built-in per-agent registry.\n * 2. `config.overrides` — per-task consumer overrides keyed by `taskId`.\n * 3. `config.tasks` — fully consumer-authored entries. Entries whose\n *    `taskId` matches a default entry **replace** it; entries with a new\n *    `taskId` are appended.\n *\n * Malformed configs (unknown model, empty taskId/agent/typeLabel,\n * duplicate taskIds in a single supplied list) throw a descriptive\n * `Error` — callers should not need to guard against it at runtime.\n */\nexport function resolveScheduledTasks(\n  config?: ScheduledTasksConfig,\n  excludeBundles: ReadonlyArray<string> = [],\n): ResolvedScheduledTasks {\n  const root = config?.root ?? DEFAULT_SCHEDULED_TASKS_ROOT;\n  assertValidRoot(root);\n\n  const merged = new Map<string, ResolvedScheduledTask>();\n  for (const entry of DEFAULT_SCHEDULED_TASK_ENTRIES) {\n    // Drop default entries whose target bundle has been excluded.\n    // Consumer-supplied entries via `tasks` and per-task overrides\n    // pass through unchanged so a consumer can still wire a custom\n    // worker against an excluded bundle's type label if they really\n    // want to.\n    if (isScheduledTaskOwnedByExcluded(entry.taskId, excludeBundles)) {\n      continue;\n    }\n    merged.set(entry.taskId, entry);\n  }\n\n  if (config?.overrides) {\n    for (const [taskId, override] of Object.entries(config.overrides)) {\n      const existing = merged.get(taskId);\n      if (!existing) {\n        // The taskId may be unknown because its bundle was excluded.\n        // Skip the override silently in that case so consumers can\n        // declare overrides defensively without tracking exclusions.\n        if (isScheduledTaskOwnedByExcluded(taskId, excludeBundles)) {\n          continue;\n        }\n        throw new Error(\n          `ScheduledTasksConfig.overrides references unknown taskId ${JSON.stringify(\n            taskId,\n          )}; override entries must match a default taskId. Supply full entries via \\`tasks\\` to add new tasks.`,\n        );\n      }\n      merged.set(taskId, applyOverride(existing, override, taskId));\n    }\n  }\n\n  if (config?.tasks) {\n    const seen = new Set<string>();\n    for (const entry of config.tasks) {\n      const resolved = validateFullEntry(entry);\n      if (seen.has(resolved.taskId)) {\n        throw new Error(\n          `ScheduledTasksConfig.tasks declares taskId ${JSON.stringify(\n            resolved.taskId,\n          )} more than once; every taskId must appear at most once within \\`tasks\\`.`,\n        );\n      }\n      seen.add(resolved.taskId);\n      merged.set(resolved.taskId, resolved);\n    }\n  }\n\n  return {\n    enabled: config?.enabled ?? true,\n    root,\n    tasks: [...merged.values()],\n  };\n}\n\n/**\n * Synth-time validation hook. Throws a descriptive `Error` when the\n * supplied `ScheduledTasksConfig` is malformed. Called by\n * `AgentConfig.preSynthesize` before any rendering so a misconfigured\n * scheduled-tasks table fails the build instead of silently shipping\n * broken worker prompts. Returns the resolved config unchanged so\n * callers can write `const st = validateScheduledTasksConfig(config)` in\n * one line.\n *\n * Malformed cases rejected here:\n *\n * - `root` empty, whitespace-only, or absolute.\n * - `overrides[taskId]` referencing an unknown `taskId`.\n * - Consumer-supplied `tasks` entry with unknown model, empty\n *   `taskId` / `agent` / `typeLabel`, or cron string that is not a\n *   plain string.\n * - Duplicate `taskId` values within the supplied `tasks` list.\n */\nexport function validateScheduledTasksConfig(\n  config?: ScheduledTasksConfig,\n  excludeBundles: ReadonlyArray<string> = [],\n): ResolvedScheduledTasks {\n  return resolveScheduledTasks(config, excludeBundles);\n}\n\n/**\n * Render the markdown subsection appended to the\n * `orchestrator-conventions` rule. Always returns a non-empty string —\n * the default registry is non-empty so the section documents the\n * per-agent scheduled-task layout even when every task is disabled\n * (the default).\n */\nexport function renderScheduledTasksSection(\n  resolved: ResolvedScheduledTasks,\n): string {\n  const lines: Array<string> = [\n    \"## Per-agent scheduled tasks\",\n    \"\",\n    \"Each agent bundle that ships with configulator can emit a\",\n    \"**scheduled-task definition** under\",\n    `\\`${resolved.root}/<taskId>/SKILL.md\\`. The definition carries:`,\n    \"\",\n    \"- A **label filter** — the `type:*` label (and optional phase-label\",\n    \"  prefix) the worker consults when picking up an issue.\",\n    \"- A **recommended model** — rendered on the task's frontmatter so\",\n    \"  operators know which model tier to launch the task against.\",\n    \"- An optional **cron** expression — when absent, the task is\",\n    \"  manual-only (runs only when invoked explicitly).\",\n    \"\",\n    \"Every task ships **disabled by default**. Consumers opt in via\",\n    \"`AgentConfigOptions.scheduledTasks.overrides.<taskId>.enabled =\",\n    \"true`. Only enabled tasks are emitted to disk; disabled tasks\",\n    \"leave no trace in the generated repo.\",\n    \"\",\n  ];\n\n  if (!resolved.enabled) {\n    lines.push(\n      \"**The scheduled-tasks subsystem is disabled for this project.**\",\n      \"No `<root>/<taskId>/SKILL.md` files are emitted regardless of\",\n      \"individual task overrides. Enable via\",\n      \"`AgentConfigOptions.scheduledTasks.enabled = true`.\",\n      \"\",\n    );\n    return lines.join(\"\\n\");\n  }\n\n  lines.push(\n    \"### Recommended-model caveat\",\n    \"\",\n    \"The Claude Code scheduled-task runtime does **not** currently pin\",\n    \"a model per task — each task runs on whatever model the runtime\",\n    \"is launched with. The recommended-model column below is\",\n    \"informational; splitting workers by type still delivers two\",\n    \"practical benefits:\",\n    \"\",\n    \"1. **Independent cadence.** Expensive Opus workers can run less\",\n    \"   frequently than cheap Haiku workers.\",\n    \"2. **Clean opt-in/opt-out.** Disable an entire agent category by\",\n    \"   toggling one task — no label surgery needed.\",\n    \"\",\n    \"To route each task to its recommended model today, the operator\",\n    \"runs a scheduler instance per model tier (Opus / Sonnet / Haiku)\",\n    \"and enables only the tasks belonging to that tier in each instance.\",\n    \"\",\n    \"### Off-peak cron example\",\n    \"\",\n    `A reasonable off-peak cadence is \\`${DEFAULT_OFF_PEAK_CRON_EXAMPLE}\\` —`,\n    \"every 20 minutes outside the 08:00–14:00 local window. Override\",\n    \"per-task via\",\n    \"`AgentConfigOptions.scheduledTasks.overrides.<taskId>.cron`.\",\n    \"\",\n    \"### Registered tasks\",\n    \"\",\n    \"| Task ID | Target agent | `type:*` filter | Phase prefix | Model | Enabled | Cron |\",\n    \"|---------|--------------|-----------------|--------------|-------|---------|------|\",\n  );\n\n  for (const task of resolved.tasks) {\n    let typeCell: string;\n    let phaseCell: string;\n    if (task.kind === \"pipeline\") {\n      typeCell = \"_(none — pipeline manager)_\";\n      phaseCell = \"_(none — pipeline manager)_\";\n    } else {\n      typeCell =\n        task.typeLabels && task.typeLabels.length > 1\n          ? task.typeLabels.map((l) => `\\`type:${l}\\``).join(\", \")\n          : `\\`type:${task.typeLabel}\\``;\n      if (task.phaseLabels && task.phaseLabels.length > 0) {\n        phaseCell = task.phaseLabels.map((l) => `\\`${l}\\``).join(\", \");\n      } else if (task.phasePrefix) {\n        phaseCell = `\\`${task.phasePrefix}*\\``;\n      } else {\n        phaseCell = \"_(any)_\";\n      }\n    }\n    const cronCell = task.cron ? `\\`${task.cron}\\`` : \"_manual-only_\";\n    lines.push(\n      `| \\`${task.taskId}\\` | \\`${task.agent}\\` | ${typeCell} | ${phaseCell} | ${task.recommendedModel} | ${task.enabled ? \"yes\" : \"no\"} | ${cronCell} |`,\n    );\n  }\n\n  return lines.join(\"\\n\");\n}\n\n/**\n * Render the body of a single scheduled-task `SKILL.md` file. The\n * frontmatter carries the task name, description, and recommended\n * model; the body teaches the worker which label filter to apply and\n * which agent file to route issues to.\n *\n * The output is the full file contents — including the leading\n * frontmatter delimiter — so callers can hand it straight to a\n * `TextFile`.\n */\nexport function renderScheduledTaskSkillFile(\n  task: ResolvedScheduledTask,\n): string {\n  const lines: Array<string> = [\n    \"---\",\n    `name: ${task.taskId}`,\n    `description: ${task.description}`,\n    `model: ${task.recommendedModel}`,\n  ];\n  if (task.cron) {\n    lines.push(`cron: \"${task.cron}\"`);\n  }\n  lines.push(\"---\", \"\");\n\n  if (task.kind === \"pipeline\") {\n    return renderPipelineSkillBody(task, lines);\n  }\n  return renderIssueWorkerSkillBody(task, lines);\n}\n\nfunction renderIssueWorkerSkillBody(\n  task: ResolvedScheduledTask,\n  lines: Array<string>,\n): string {\n  lines.push(\n    `# ${task.agentLabel} Scheduled Worker`,\n    \"\",\n    `You are the **${task.agentLabel}** scheduled worker. Follow the`,\n    \"full workflow in `.claude/agents/issue-worker.md` (clean starting\",\n    \"state → unblock → PR review → find-oldest-unblocked-issue → route\",\n    \"to agent → one unit of work), with the label filter below applied\",\n    \"at the find-an-issue step.\",\n    \"\",\n    \"## Label filter\",\n    \"\",\n    \"Only consider issues matching **both**:\",\n    \"\",\n  );\n  if (task.typeLabels && task.typeLabels.length > 1) {\n    const formatted = task.typeLabels.map((l) => `\\`type:${l}\\``).join(\", \");\n    lines.push(`- Any of: ${formatted}`);\n  } else {\n    lines.push(`- Label: \\`type:${task.typeLabel}\\``);\n  }\n  if (task.phaseLabels && task.phaseLabels.length > 0) {\n    const formatted = task.phaseLabels.map((l) => `\\`${l}\\``).join(\", \");\n    const noun = task.phaseLabels.length === 1 ? \"label\" : \"labels\";\n    lines.push(`- Exact phase ${noun}: ${formatted}`);\n  } else if (task.phasePrefix) {\n    lines.push(\n      `- Any phase label matching \\`${task.phasePrefix}*\\` (e.g. \\`${task.phasePrefix}${SAMPLE_PHASE}\\`).`,\n    );\n  } else {\n    lines.push(\"- No phase-label filter — all matching issues are eligible.\");\n  }\n\n  lines.push(\n    \"\",\n    `Route matched issues to \\`.claude/agents/${task.agent}.md\\` and`,\n    \"execute its phase-specific workflow.\",\n    \"\",\n  );\n\n  if (task.taskId === \"worker-issue\") {\n    lines.push(\n      \"## Feedback-pull scan (runs before issue selection)\",\n      \"\",\n      \"Because you run autonomously (scheduled mode), **also scan for PRs\",\n      \"needing feedback work before scanning the issue queue** — and\",\n      \"prefer them. The pr-reviewer hands fixes off by applying a durable\",\n      \"`review:needs-worker` marker on the PR (it cannot spawn you in\",\n      \"session). Pull that marker instead of waiting for an explicit push:\",\n      \"\",\n      \"```bash\",\n      \"gh pr list --state open --label 'review:needs-worker' \\\\\",\n      \"  --json number,labels,headRefName,updatedAt\",\n      \"```\",\n      \"\",\n      \"If any open PR carries an unconsumed `review:needs-worker` fix-list,\",\n      \"enter **feedback mode** for the highest-priority match (no explicit\",\n      \"`feedback mode: PR #<n>` push required) and run the issue-worker's\",\n      \"feedback-mode phases: apply the fix-list, push, write the\",\n      \"worker-report comment, and **clear `review:needs-worker`** (leave\",\n      \"`review:fixing` for the reviewer's confirm pass). Only when no PR\",\n      \"needs a worker do you fall through to the issue-queue selection\",\n      \"above. See the **Invocation Mode** and **Phase 1** sections of\",\n      \"`.claude/agents/issue-worker.md` for the full contract.\",\n      \"\",\n    );\n  }\n\n  lines.push(\n    \"## Recommended model\",\n    \"\",\n    `**${capitalize(task.recommendedModel)}** — see`,\n    `\\`.claude/agents/${task.agent}.md\\` for the agent's full model`,\n    \"rationale. The operator launches the scheduler instance on the\",\n    \"recommended model; this task does not pin a model at the runtime\",\n    \"level.\",\n    \"\",\n    \"## Exit conditions\",\n    \"\",\n    \"Exit cleanly after completing one unit of work (or immediately if\",\n    \"no eligible issue exists). Do not pick up issues outside the\",\n    \"filter above — leave them for other workers.\",\n  );\n\n  return lines.join(\"\\n\");\n}\n\nfunction renderPipelineSkillBody(\n  task: ResolvedScheduledTask,\n  lines: Array<string>,\n): string {\n  lines.push(\n    `# ${task.agentLabel} Pipeline Worker`,\n    \"\",\n    `You are the **${task.agentLabel}** pipeline worker. This task is a`,\n    \"**pipeline manager**, not an issue-worker delegator — it does not\",\n    \"filter issues by `type:*` or phase label. Each invocation runs the\",\n    `target sub-agent's full end-to-end cycle exactly once.`,\n    \"\",\n    \"## Depth-0 execution contract\",\n    \"\",\n    \"**You — the scheduled-task session — are the pipeline manager.**\",\n    \"Do **not** spawn the target sub-agent via the `Agent` tool. The\",\n    \"Claude Code runtime forbids nested sub-agent spawning: a depth-1\",\n    \"sub-agent cannot invoke `Agent` to reach depth-2, so a pipeline\",\n    \"manager that delegates to other workers must run at depth-0 (this\",\n    \"scheduled-task session). See\",\n    '<https://code.claude.com/docs/en/sub-agents> — *\"Subagents cannot',\n    \"spawn other subagents. If your workflow requires nested delegation,\",\n    'use Skills or chain subagents from the main conversation.\"*',\n    \"\",\n    \"Therefore:\",\n    \"\",\n    `1. **Read \\`.claude/agents/${task.agent}.md\\` in this session** and`,\n    \"   execute its phase pipeline directly. Treat the agent file as a\",\n    \"   workflow runbook the scheduled-task session follows step-by-step,\",\n    \"   not as a sub-agent to spawn.\",\n    \"2. **Use the `Agent` tool (with the `subagent_type` parameter set\",\n    \"   to the target worker name) to delegate one tier down.** From\",\n    \"   depth-0, you can spawn a depth-1 sub-agent (e.g. `issue-worker`,\",\n    \"   `pr-reviewer`) for the implementation, review, or merge step the\",\n    \"   pipeline calls out.\",\n    \"3. **Never spawn the pipeline manager itself as a sub-agent.** Do\",\n    `   not call \\`Agent(subagent_type: \"${task.agent}\", ...)\\`. That`,\n    \"   would put the pipeline manager at depth-1 and break every\",\n    \"   subsequent delegation step.\",\n    \"\",\n    \"## Recommended model\",\n    \"\",\n    `**${capitalize(task.recommendedModel)}** — see`,\n    `\\`.claude/agents/${task.agent}.md\\` for the agent's full model`,\n    \"rationale. The operator launches the scheduler instance on the\",\n    \"recommended model; this task does not pin a model at the runtime\",\n    \"level.\",\n    \"\",\n    \"## Exit conditions\",\n    \"\",\n    \"Exit cleanly after one full cycle of the target pipeline (or\",\n    \"immediately if the pipeline reports there is no eligible work).\",\n    \"Do not loop — the next scheduled invocation runs another cycle.\",\n  );\n\n  return lines.join(\"\\n\");\n}\n\n/*******************************************************************************\n *\n * Internal helpers\n *\n ******************************************************************************/\n\nconst SAMPLE_PHASE = \"phase1\";\n\nfunction capitalize(value: string): string {\n  if (value.length === 0) {\n    return value;\n  }\n  return value[0].toUpperCase() + value.slice(1);\n}\n\nfunction applyOverride(\n  base: ResolvedScheduledTask,\n  override: ScheduledTaskOverride,\n  taskId: string,\n): ResolvedScheduledTask {\n  if (override.recommendedModel !== undefined) {\n    assertValidModel(override.recommendedModel, taskId);\n  }\n  if (override.cron !== undefined && override.cron !== null) {\n    assertValidCron(override.cron, taskId);\n  }\n  if (override.typeLabels !== undefined) {\n    assertNonEmptyLabelList(override.typeLabels, taskId, \"typeLabels\");\n  }\n  if (override.phaseLabels !== undefined) {\n    assertNonEmptyLabelList(override.phaseLabels, taskId, \"phaseLabels\");\n  }\n  if (override.kind !== undefined) {\n    assertValidKind(override.kind, taskId);\n  }\n  const resolvedTypeLabels =\n    override.typeLabels !== undefined\n      ? normalizeLabelList(override.typeLabels)\n      : base.typeLabels;\n  const primaryTypeLabel = resolvedTypeLabels?.[0] ?? base.typeLabel;\n  return {\n    ...base,\n    enabled: override.enabled ?? base.enabled,\n    cron: override.cron === undefined ? base.cron : override.cron,\n    recommendedModel: override.recommendedModel ?? base.recommendedModel,\n    description: override.description ?? base.description,\n    typeLabel: primaryTypeLabel,\n    typeLabels: resolvedTypeLabels,\n    phaseLabels:\n      override.phaseLabels !== undefined\n        ? normalizeLabelList(override.phaseLabels)\n        : base.phaseLabels,\n    kind: override.kind ?? base.kind,\n  };\n}\n\nfunction validateFullEntry(entry: ScheduledTaskEntry): ResolvedScheduledTask {\n  const taskId = (entry.taskId ?? \"\").trim();\n  if (taskId.length === 0) {\n    throw new Error(\n      \"ScheduledTasksConfig.tasks entry has an empty or whitespace-only `taskId`; every entry must declare a non-empty taskId.\",\n    );\n  }\n  const agent = (entry.agent ?? \"\").trim();\n  if (agent.length === 0) {\n    throw new Error(\n      `ScheduledTasksConfig.tasks entry for taskId ${JSON.stringify(taskId)} has an empty or whitespace-only \\`agent\\`; every entry must target a sub-agent name.`,\n    );\n  }\n  const typeLabel = (entry.typeLabel ?? \"\").trim();\n  if (typeLabel.length === 0) {\n    throw new Error(\n      `ScheduledTasksConfig.tasks entry for taskId ${JSON.stringify(taskId)} has an empty or whitespace-only \\`typeLabel\\`; every entry must declare a type:* label value.`,\n    );\n  }\n  assertValidModel(entry.recommendedModel, taskId);\n  if (entry.cron !== undefined && entry.cron !== null) {\n    assertValidCron(entry.cron, taskId);\n  }\n  if (entry.typeLabels !== undefined) {\n    assertNonEmptyLabelList(entry.typeLabels, taskId, \"typeLabels\");\n  }\n  if (entry.phaseLabels !== undefined) {\n    assertNonEmptyLabelList(entry.phaseLabels, taskId, \"phaseLabels\");\n  }\n  if (entry.kind !== undefined) {\n    assertValidKind(entry.kind, taskId);\n  }\n  const typeLabels =\n    entry.typeLabels !== undefined\n      ? normalizeLabelList(entry.typeLabels)\n      : undefined;\n  const primaryTypeLabel = typeLabels?.[0] ?? typeLabel;\n  return {\n    taskId,\n    agent,\n    agentLabel: entry.agentLabel ?? agent,\n    typeLabel: primaryTypeLabel,\n    typeLabels,\n    phasePrefix: entry.phasePrefix?.trim() || undefined,\n    phaseLabels:\n      entry.phaseLabels !== undefined\n        ? normalizeLabelList(entry.phaseLabels)\n        : undefined,\n    recommendedModel: entry.recommendedModel,\n    enabled: entry.enabled ?? false,\n    cron: entry.cron ?? null,\n    description: entry.description ?? `${agent} scheduled worker.`,\n    kind: entry.kind ?? DEFAULT_SCHEDULED_TASK_KIND,\n  };\n}\n\nfunction assertValidKind(\n  value: string,\n  taskId: string,\n): asserts value is ScheduledTaskKind {\n  if (!(SCHEDULED_TASK_KIND_VALUES as ReadonlyArray<string>).includes(value)) {\n    throw new Error(\n      `ScheduledTasksConfig entry for taskId ${JSON.stringify(taskId)} has kind ${JSON.stringify(\n        value,\n      )}; must be one of ${SCHEDULED_TASK_KIND_VALUES.join(\" | \")}.`,\n    );\n  }\n}\n\nfunction assertValidModel(\n  value: string,\n  taskId: string,\n): asserts value is ScheduledTaskModel {\n  if (!(SCHEDULED_TASK_MODEL_VALUES as ReadonlyArray<string>).includes(value)) {\n    throw new Error(\n      `ScheduledTasksConfig entry for taskId ${JSON.stringify(taskId)} has recommendedModel ${JSON.stringify(\n        value,\n      )}; must be one of ${SCHEDULED_TASK_MODEL_VALUES.join(\" | \")}.`,\n    );\n  }\n}\n\nfunction assertValidCron(value: string, taskId: string): void {\n  if (typeof value !== \"string\" || value.trim().length === 0) {\n    throw new Error(\n      `ScheduledTasksConfig entry for taskId ${JSON.stringify(taskId)} has cron ${JSON.stringify(\n        value,\n      )}; cron must be a non-empty string or null.`,\n    );\n  }\n}\n\nfunction assertValidRoot(root: string): void {\n  const trimmed = root.trim();\n  if (trimmed.length === 0) {\n    throw new Error(\n      \"ScheduledTasksConfig.root must be a non-empty string relative to the repo root\",\n    );\n  }\n  if (trimmed.startsWith(\"/\")) {\n    throw new Error(\n      `ScheduledTasksConfig.root must be relative to the repo root (no leading '/'); got ${root}`,\n    );\n  }\n}\n\nfunction assertNonEmptyLabelList(\n  labels: ReadonlyArray<string>,\n  taskId: string,\n  field: \"typeLabels\" | \"phaseLabels\",\n): void {\n  if (labels.length === 0) {\n    throw new Error(\n      `ScheduledTasksConfig entry for taskId ${JSON.stringify(taskId)} has an empty \\`${field}\\` array; supply at least one label or omit the field to keep the default.`,\n    );\n  }\n  for (const label of labels) {\n    if (typeof label !== \"string\" || label.trim().length === 0) {\n      throw new Error(\n        `ScheduledTasksConfig entry for taskId ${JSON.stringify(taskId)} has an empty or whitespace-only value in \\`${field}\\`; every entry must be a non-empty string.`,\n      );\n    }\n  }\n}\n\nfunction normalizeLabelList(\n  labels: ReadonlyArray<string>,\n): ReadonlyArray<string> {\n  return labels.map((l) => l.trim());\n}\n","import { isPhaseLabelOwnedByExcluded } from \"./bundle-ownership\";\nimport {\n  ScopeGateBundleOverride,\n  ScopeGateConfig,\n  ScopeGateThresholds,\n} from \"../agent-config-options\";\n\n/**\n * Classified scope size for a single issue. Drives the dispatch\n * decision in the orchestrator — `small` / `medium` are dispatched,\n * `large` is rejected and decomposed.\n */\nexport const SCOPE_CLASS_VALUES = [\"small\", \"medium\", \"large\"] as const;\nexport type ScopeClass = (typeof SCOPE_CLASS_VALUES)[number];\n\n/**\n * Default acceptance-criteria thresholds — openhi's published\n * heuristic. An issue with at most 3 acceptance-criteria checkboxes\n * is `small`; at most 6 is `medium`; more than 6 is `large`.\n */\nexport const DEFAULT_AC_THRESHOLDS: ScopeGateThresholds = {\n  smallMax: 3,\n  mediumMax: 6,\n};\n\n/**\n * Default sources thresholds — openhi's published heuristic. An\n * issue with at most 2 listed sources is `small`; at most 5 is\n * `medium`; more than 5 is `large`.\n */\nexport const DEFAULT_SOURCES_THRESHOLDS: ScopeGateThresholds = {\n  smallMax: 2,\n  mediumMax: 5,\n};\n\n/**\n * Bundle overrides shipped out of the box for content-spec workflows\n * — issues whose AC list is the per-section content checklist for\n * one cohesive deliverable (not a phase-completion checklist that\n * can be decomposed). The global default cap (`mediumMax: 6`) is\n * calibrated for phased-bundle issues and systematically over-flags\n * single-document writes.\n *\n * The shipped overrides:\n *\n * - `req:write` — formal requirement documents (ADR / TR / OPS /\n *   SEC / NFR / UX / MT) routinely carry 12–20 ACs covering\n *   per-section content invariants (definition, alternatives,\n *   risks, traceability, revision history, open items). Cap:\n *   `mediumMax: 20` on the AC axis; sources unchanged.\n * - `bcm:scaffold` — multi-section BCM documents compress sub-\n *   addendum requirements into coarse ACs but still land above\n *   the global cap. Cap: `mediumMax: 12` on the AC axis; sources\n *   unchanged.\n * - `research:verify` — the `research-analyst` slice phase emits\n *   a fixed-shape verify template. A 32-issue cohort observed in\n *   `codedrifters/openhi-planning` (2026-05-04) all landed at\n *   identical `ac=9 / src=2` dimensions, so the template's shape\n *   itself is what trips the global cap. Cap: `mediumMax: 12` on\n *   the AC axis (max observed 9 + ~3 headroom); sources unchanged.\n * - `research:scope` — the `research-analyst` Phase-1 scope phase\n *   decomposes a research question and writes a single scope file\n *   whose ACs are the per-section content checklist for that one\n *   deliverable (question decomposition, per-slice briefs, and the\n *   acceptance criteria for the final deliverable), not a phase-\n *   completion checklist that can be decomposed. Sibling of\n *   `research:verify` in the same pipeline; observed ac=7\n *   (`codedrifters/openhi-planning`#6034). Cap: `mediumMax: 12` on\n *   the AC axis (matching the `research:verify` sibling); sources\n *   unchanged.\n * - `software:profile` — software-product profile pages enumerate\n *   per-section content invariants (overview, vendor, integrations,\n *   pricing, security posture, …). Max observed 11 ACs in the same\n *   openhi-planning sample; cap: `mediumMax: 14` on the AC axis\n *   (max observed + 3 headroom); sources unchanged.\n * - `software:research` — the `software-profile` Phase-1 research\n *   phase gathers public sources and writes a single bounded\n *   research-notes file whose ACs are the per-section content\n *   checklist for that one deliverable, not a decomposable plan.\n *   Sibling of `software:profile` in the same pipeline; observed\n *   ac=8 (`codedrifters/openhi-planning`#6259). Cap: `mediumMax: 14`\n *   on the AC axis (matching the `software:profile` sibling);\n *   sources unchanged.\n * - `regulatory:research` — single regulation pages carry per-\n *   section ACs covering jurisdiction, scope, obligations,\n *   penalties, and effective dates. Single-document conformance\n *   scans run ac=11; cap: `mediumMax: 12` on the AC axis;\n *   sources unchanged.\n * - `regulatory:impact` — the `regulatory-research` Phase-3 impact\n *   phase is synthesis-only (no web searches): it appends a single\n *   `## Impact` section to the regulation page — product-impact\n *   assessment, capability-gap enumeration, and obligation hand-offs\n *   — whose ACs are the per-section content checklist for that one\n *   document section. Sibling of `regulatory:research`; observed\n *   ac=9 (`codedrifters/openhi-planning`#3505). Cap: `mediumMax: 10`\n *   on the AC axis (observed max 9 + headroom; the tighter cap\n *   versus the research sibling's 12 reflects the narrower\n *   single-section deliverable); sources unchanged.\n * - `standards:research` — single standard-version research notes\n *   enumerate one cohesive deliverable across per-section ACs\n *   (candidate encodings, reconciliation, storage/query analysis,\n *   citations, recommendation). Sibling of `regulatory:research`\n *   with the same content-spec note shape. Max observed 7 ACs\n *   (`codedrifters/openhi-planning`#5994); cap: `mediumMax: 10` on\n *   the AC axis (max observed + 3 headroom, matching the\n *   `regulatory:research` sibling); sources unchanged.\n * - `software:map` — capability-mapping output is a single cohesive\n *   matrix file whose ACs enumerate per-row/per-column requirements\n *   and whose Sources block typically cross-references the entire\n *   BCM tree slice. Max observed `ac=9 / src=13`; cap:\n *   `acceptanceCriteria.mediumMax: 12` (max + 3) and\n *   `sources.mediumMax: 15` (max + 2 — sources headroom is tighter\n *   because BCM cross-refs naturally cap out near the slice size).\n * - `bcm:connect` — connect-phase outputs cross-link a capability\n *   to upstream value streams, downstream profiles, and adjacent\n *   capabilities. Max observed `ac=9 / src=6`; cap:\n *   `acceptanceCriteria.mediumMax: 12` (max + 3) and\n *   `sources.mediumMax: 8` (max + 2).\n * - `software:matrix` — physician-RCM-style feature matrices\n *   (per-row/per-column requirements for one cohesive matrix\n *   file). The shape mirrors `software:map`: single-cohesive-\n *   file matrix output whose ACs enumerate per-row/per-column\n *   requirements rather than phase milestones. Mirrors the\n *   `software:map` thresholds verbatim (closest-peer rationale,\n *   surfaced by openhi-planning#3223).\n * - `people:research` / `company:research` — profile research\n *   phases whose AC list is the per-section content checklist for\n *   one cohesive research-notes file (sources by tier, conflict\n *   resolution, dated claims). Not a phase-completion checklist\n *   that can be decomposed. Cap: `mediumMax: 12` on the AC axis;\n *   sources unchanged.\n * - `people:draft` / `company:draft` — profile draft phases that\n *   read the research notes and write one cohesive structured\n *   profile document. The per-section AC checklist (overview,\n *   leadership, history, sources, …) is the content spec for that\n *   single document, not a decomposable plan. Cap: `mediumMax: 12`\n *   on the AC axis; sources unchanged.\n * - `business-models:canvas` / `business-models:complete` — the\n *   business-models pipeline authors one cohesive Business Model\n *   Canvas document per segment across two content-spec phases that\n *   edit the SAME `business-model.md` file. The canvas phase writes\n *   the nine Osterwalder blocks + segment index + downstream handoff;\n *   the complete phase appends BIZBOK value streams, size / geographic\n *   / regulatory variations, and the value-stream-to-capability\n *   linking table. Both AC lists are the per-section content checklist\n *   for that single indivisible document, not a phase-completion\n *   checklist that can be decomposed — a single canvas cannot be split\n *   into sequential sub-issues without every phase editing the same\n *   file. A representative canvas issue observed at ac=7\n *   (`codedrifters/openhi-planning`#13613). Cap: `mediumMax: 12` on the\n *   AC axis for both (matching the `bcm:*` / `company:research`\n *   document-authoring norm; the complete phase is a multi-section\n *   append, so it takes the same cap as its canvas sibling rather than\n *   a tighter single-section cap); sources unchanged.\n * - `req:draft-trace` — the `requirements-analyst` draft-trace\n *   phase emits a single proposal-with-traceability document whose\n *   ACs enumerate per-section content invariants. Sibling of\n *   `req:write`; mirrors its `mediumMax: 20` AC cap (observed max\n *   ac=9, headroom intentional). Sources unchanged.\n * - `meeting:notes` — Phase-2 meeting-notes output is a single\n *   cohesive notes document whose ACs enumerate per-section\n *   content invariants. Cap: `mediumMax: 9` on the AC axis;\n *   sources unchanged.\n * - `meeting:draft` / `meeting:link` — Phase-3/Phase-4 meeting\n *   outputs carry a \"file N action-item issues\" criterion plus\n *   per-section content ACs, and cross-reference every session\n *   input. Cap: `acceptanceCriteria.mediumMax: 15` and\n *   `sources.mediumMax: 10` on both axes.\n * - `type:docs` — single-document doc writes whose AC list is the\n *   per-section content outline for one cohesive page, not a\n *   decomposable plan. This is the first override keyed on a\n *   `type:*` label rather than a phase label; it matches because\n *   the scope gate resolves overrides against every label on the\n *   issue (see `resolveOverrideForLabels`). Cap: `mediumMax: 12`\n *   on the AC axis; sources unchanged (global band).\n * - `bcm:context` — the `bcm-writer` context phase authors a\n *   single BCM context document whose AC list is a per-section\n *   content checklist (definitions, boundaries, sub-capabilities,\n *   value-stream links), not a decomposable plan. Sibling of\n *   `bcm:scaffold` / `bcm:connect`; mirrors their `mediumMax: 12`\n *   AC cap. AC axis only; sources fall through to the global band.\n * - `req:scan` — the `requirements-analyst` Phase-1 dedup scan\n *   produces one cohesive scan report, but a dedup pass inherently\n *   reads MANY existing requirements, ADRs, and open issues, so it\n *   trips BOTH the AC ceiling AND the sources ceiling (evidence\n *   issue scored `ac=7 / src=9`). Both axes are raised to\n *   `mediumMax: 12` — this is why `req:scan` carries a `sources`\n *   override the AC-only siblings do not.\n * - `bcm:outline` — the `bcm-writer` Phase-1 outline phase authors a\n *   single capability outline document whose AC list is the content\n *   checklist for that one indivisible deliverable (identify the L1\n *   parent, draft the L2 definition, document sub-facets, draw the\n *   capability boundary, write the outline file, update the\n *   capability map), not a decomposable plan — the criteria cannot be\n *   split into independently-mergeable sub-issues because every one\n *   of them edits the same outline file. Sibling of `bcm:scaffold` /\n *   `bcm:context` / `bcm:connect`; mirrors their `mediumMax: 12` AC\n *   cap. Observed ac=7 (`codedrifters/openhi-planning`#11216). AC\n *   axis only; sources fall through to the global band.\n *\n * Consumer overrides deep-merge with these defaults with\n * consumer-wins-per-key (see `resolveScopeGate` for the merge\n * semantics).\n */\nexport const DEFAULT_BUNDLE_OVERRIDES: {\n  readonly [phaseLabel: string]: ResolvedScopeGateBundleOverride;\n} = {\n  \"req:write\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 20 },\n  },\n  \"bcm:scaffold\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 12 },\n  },\n  \"research:verify\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 12 },\n  },\n  \"research:scope\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 12 },\n  },\n  \"software:profile\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 14 },\n  },\n  \"software:research\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 14 },\n  },\n  \"regulatory:research\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 12 },\n  },\n  \"regulatory:impact\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 10 },\n  },\n  \"standards:research\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 10 },\n  },\n  \"software:map\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 12 },\n    sources: { smallMax: 2, mediumMax: 15 },\n  },\n  \"bcm:connect\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 12 },\n    sources: { smallMax: 2, mediumMax: 8 },\n  },\n  \"software:matrix\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 12 },\n    sources: { smallMax: 2, mediumMax: 15 },\n  },\n  \"people:research\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 12 },\n  },\n  \"company:research\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 12 },\n  },\n  \"people:draft\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 12 },\n  },\n  \"company:draft\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 12 },\n  },\n  \"business-models:canvas\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 12 },\n  },\n  \"business-models:complete\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 12 },\n  },\n  \"req:draft-trace\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 20 },\n  },\n  \"meeting:notes\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 9 },\n  },\n  \"meeting:draft\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 15 },\n    sources: { smallMax: 2, mediumMax: 10 },\n  },\n  \"meeting:link\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 15 },\n    sources: { smallMax: 2, mediumMax: 10 },\n  },\n  \"type:docs\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 12 },\n  },\n  \"bcm:context\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 12 },\n  },\n  \"req:scan\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 12 },\n    sources: { smallMax: 2, mediumMax: 12 },\n  },\n  \"bcm:outline\": {\n    acceptanceCriteria: { smallMax: 3, mediumMax: 12 },\n  },\n};\n\n/**\n * Resolved per-phase-label override. At least one of the two axis\n * fields is populated — empty resolved overrides are dropped\n * rather than retained, so callers can assume any entry in the\n * resolved override map carries actionable thresholds.\n *\n * Each axis here is **fully resolved** (`smallMax` + `mediumMax`).\n * The override resolver fills in the missing axis from the global\n * resolved thresholds at the time `resolveScopeGate` runs.\n */\nexport interface ResolvedScopeGateBundleOverride {\n  readonly acceptanceCriteria?: ScopeGateThresholds;\n  readonly sources?: ScopeGateThresholds;\n}\n\n/**\n * Default decomposition-proposal comment body. The orchestrator\n * substitutes the following angle-bracketed uppercase-snake\n * placeholders at comment-composition time:\n *\n * - `<AC_COUNT>` — observed acceptance-criteria count.\n * - `<SOURCES_COUNT>` — observed sources count.\n * - `<AC_LIMIT>` — the `acceptanceCriteria.mediumMax` threshold.\n * - `<SOURCES_LIMIT>` — the `sources.mediumMax` threshold.\n *\n * The placeholder syntax deliberately avoids `{{curly-brace}}` form —\n * `AgentConfig`'s template resolver claims that namespace at rule\n * generation time, so a `{{acCount}}` placeholder would be rewritten\n * to `<acCount>` before the agent ever saw it.\n *\n * This template is deliberately generic so every consuming repo\n * can adopt it without customization — project-specific phrasing\n * belongs in `ScopeGateConfig.decompositionTemplate`.\n */\nexport const DEFAULT_DECOMPOSITION_TEMPLATE = [\n  \"## Scope gate: issue is too large to dispatch\",\n  \"\",\n  \"The orchestrator rejected this issue at dispatch because it\",\n  \"exceeds the configured scope thresholds:\",\n  \"\",\n  \"- Acceptance criteria: **<AC_COUNT>** (limit for single-session work: **<AC_LIMIT>**)\",\n  \"- Sources referenced: **<SOURCES_COUNT>** (limit for single-session work: **<SOURCES_LIMIT>**)\",\n  \"\",\n  \"### Proposed phased decomposition\",\n  \"\",\n  \"Split the work into sequential phases and file each phase as its\",\n  \"own sub-issue. Each sub-issue should land at or below the\",\n  \"`small` / `medium` scope thresholds so it dispatches normally on\",\n  \"the next orchestrator run.\",\n  \"\",\n  \"- **Phase 1 — <short title>.** <1 sentence scope + 1–3 AC>\",\n  \"- **Phase 2 — <short title>.** <1 sentence scope + 1–3 AC>\",\n  \"  *Depends on: #<phase-1-issue>*\",\n  \"- **Phase 3 — <short title>.** <1 sentence scope + 1–3 AC>\",\n  \"  *Depends on: #<phase-2-issue>*\",\n  \"\",\n  \"After the sub-issues are filed, this issue stays `status:blocked`\",\n  \"with a `Depends on: #<phase-1>, #<phase-2>, #<phase-3>` line in its\",\n  \"body so the unblock loop closes it automatically once every phase\",\n  \"merges. The `status:needs-attention` label is applied so a human\",\n  \"can confirm the decomposition before work starts.\",\n].join(\"\\n\");\n\n/**\n * Fully-resolved scope-gate settings. Every field is defaulted so\n * downstream renderers can reason about a single canonical shape.\n *\n * `bundleOverrides` is the deep-merged result of the shipped\n * `DEFAULT_BUNDLE_OVERRIDES` and any consumer-supplied\n * `ScopeGateConfig.bundleOverrides`. Consumer entries replace\n * shipped defaults per-key; entries set to `undefined` opt out of\n * the shipped default for that key. The resolved map only contains\n * entries whose merged value carries at least one axis — empty\n * overrides are dropped.\n */\nexport interface ResolvedScopeGate {\n  readonly enabled: boolean;\n  readonly acceptanceCriteria: ScopeGateThresholds;\n  readonly sources: ScopeGateThresholds;\n  readonly autoFile: boolean;\n  readonly decompositionTemplate: string;\n  readonly bundleOverrides: {\n    readonly [phaseLabel: string]: ResolvedScopeGateBundleOverride;\n  };\n}\n\n/**\n * Resolve a (possibly absent) `ScopeGateConfig` into a canonical\n * `ResolvedScopeGate` with every field filled in. Unset fields\n * cascade from their documented defaults.\n *\n * Malformed configs (negative or non-integer thresholds, inverted\n * ranges) throw a descriptive `Error` — callers should not need to\n * guard against it at runtime.\n */\nexport function resolveScopeGate(config?: ScopeGateConfig): ResolvedScopeGate {\n  const ac = resolveThresholds(\n    config?.acceptanceCriteria,\n    DEFAULT_AC_THRESHOLDS,\n    \"acceptanceCriteria\",\n  );\n  const sources = resolveThresholds(\n    config?.sources,\n    DEFAULT_SOURCES_THRESHOLDS,\n    \"sources\",\n  );\n  const bundleOverrides = resolveBundleOverrides(\n    config?.bundleOverrides,\n    DEFAULT_BUNDLE_OVERRIDES,\n  );\n\n  return {\n    enabled: config?.enabled ?? true,\n    acceptanceCriteria: ac,\n    sources,\n    autoFile: config?.autoFile ?? false,\n    decompositionTemplate:\n      config?.decompositionTemplate ?? DEFAULT_DECOMPOSITION_TEMPLATE,\n    bundleOverrides,\n  };\n}\n\n/**\n * Effective thresholds applied to a single issue. Produced by\n * `resolveOverrideForLabels` so the classifier (and the shell helper)\n * can use a single shape regardless of whether an override matched.\n */\nexport interface EffectiveScopeThresholds {\n  readonly acceptanceCriteria: ScopeGateThresholds;\n  readonly sources: ScopeGateThresholds;\n  readonly matchedLabel?: string;\n}\n\n/**\n * Pick the effective thresholds for an issue carrying `labels`.\n * Walks the resolved bundle-override map, finds every label whose\n * exact name appears as a key, and selects the **first match in\n * alphabetical order on the label name**. The override's\n * `acceptanceCriteria` and `sources` axes are independent — the\n * unspecified axis falls through to the global resolved\n * thresholds.\n *\n * When no label matches, returns the global thresholds with no\n * `matchedLabel`.\n */\nexport function resolveOverrideForLabels(\n  gate: ResolvedScopeGate,\n  labels: ReadonlyArray<string>,\n): EffectiveScopeThresholds {\n  const overrideKeys = Object.keys(gate.bundleOverrides);\n  if (overrideKeys.length === 0 || labels.length === 0) {\n    return {\n      acceptanceCriteria: gate.acceptanceCriteria,\n      sources: gate.sources,\n    };\n  }\n  // Sort the issue's labels alphabetically and pick the first one\n  // that matches an override key. This makes tie-breaking\n  // deterministic when multiple labels could match.\n  const sortedLabels = [...labels].sort((a, b) => a.localeCompare(b));\n  const matchedLabel = sortedLabels.find((label) =>\n    Object.prototype.hasOwnProperty.call(gate.bundleOverrides, label),\n  );\n  if (matchedLabel === undefined) {\n    return {\n      acceptanceCriteria: gate.acceptanceCriteria,\n      sources: gate.sources,\n    };\n  }\n  const override = gate.bundleOverrides[matchedLabel];\n  return {\n    acceptanceCriteria: override.acceptanceCriteria ?? gate.acceptanceCriteria,\n    sources: override.sources ?? gate.sources,\n    matchedLabel,\n  };\n}\n\n/**\n * Synth-time validation hook. Throws a descriptive `Error` when the\n * supplied `ScopeGateConfig` is malformed. Called by\n * `AgentConfig.preSynthesize` before any rendering so a misconfigured\n * gate fails the build instead of silently shipping broken dispatch\n * thresholds. Returns the resolved gate unchanged so callers can\n * write `const gate = validateScopeGateConfig(config)` in one line.\n *\n * Malformed cases rejected here:\n *\n * - Threshold values that are negative or non-integer.\n * - Threshold ranges where `mediumMax <= smallMax` (the gate would\n *   never classify an issue as `medium`).\n */\nexport function validateScopeGateConfig(\n  config?: ScopeGateConfig,\n): ResolvedScopeGate {\n  // resolveScopeGate does the numeric validation. We call it here\n  // so the same error messages surface whether the caller used the\n  // resolver or the validator entry point.\n  return resolveScopeGate(config);\n}\n\n/**\n * Classify a raw issue body against a resolved scope gate. Returns\n * the scope class and the observed counts so the orchestrator can\n * embed them in the decomposition-proposal comment.\n *\n * The parser is deliberately tolerant:\n *\n * - Acceptance-criteria checkboxes — lines matching `- [ ]` or\n *   `- [x]` (case-insensitive) under a `## Acceptance Criteria`\n *   heading (or any heading whose normalized text equals\n *   `acceptance criteria`). Stops at the next heading.\n * - Sources — bullet list items (`- ` or `* `) under any of\n *   `## Inputs`, `## References`, `## Sources` (case-insensitive).\n *   Counts from every matching section are summed, so an issue\n *   that uses both `## Inputs` and `## References` has its sources\n *   counted across both.\n *\n * An issue with **no** `## Acceptance Criteria` section produces an\n * `acCount` of 0 and is classified `small` on the AC axis. An issue\n * body that's pure prose with no recognizable sections classifies\n * `small` — the gate never rejects an issue it can't read.\n */\nexport function classifyIssueScope(\n  body: string,\n  gate: ResolvedScopeGate,\n  labels: ReadonlyArray<string> = [],\n): {\n  readonly scope: ScopeClass;\n  readonly acCount: number;\n  readonly sourcesCount: number;\n  readonly matchedLabel?: string;\n} {\n  const acCount = countAcceptanceCriteria(body);\n  const sourcesCount = countSources(body);\n  const effective = resolveOverrideForLabels(gate, labels);\n  const scope = resolveScopeClass(acCount, sourcesCount, effective);\n  return {\n    scope,\n    acCount,\n    sourcesCount,\n    matchedLabel: effective.matchedLabel,\n  };\n}\n\n/**\n * Render the markdown subsection appended to the\n * `orchestrator-conventions` rule. Always returns a non-empty string\n * so the orchestrator rule documents the scope gate even when the\n * consumer relies on the defaults.\n *\n * When `excludeBundles` is non-empty, per-phase override rows whose\n * phase label is owned by an excluded bundle are dropped from the\n * **Per-phase-label thresholds** sub-table. The sub-section as a\n * whole is hidden when no rows survive.\n */\nexport function renderScopeGateSection(\n  gate: ResolvedScopeGate,\n  excludeBundles: ReadonlyArray<string> = [],\n): string {\n  const { acceptanceCriteria: ac, sources } = gate;\n\n  const lines: Array<string> = [\n    \"## Scope gate\",\n    \"\",\n    \"The orchestrator enforces a **scope gate** at dispatch. Oversized\",\n    \"issues are rejected, flagged with `status:needs-attention`, and\",\n    \"decomposed into phased sub-issues instead of consuming a\",\n    \"multi-hour worker session. The gate reads the issue body only —\",\n    \"it does not inspect the repository.\",\n    \"\",\n  ];\n\n  if (!gate.enabled) {\n    lines.push(\n      \"**The scope gate is disabled for this project.** The orchestrator\",\n      \"dispatches every ready issue regardless of size. Enable the gate\",\n      \"via `AgentConfigOptions.scopeGate.enabled = true` once the queue\",\n      \"surfaces consistently sized issues.\",\n      \"\",\n    );\n    return lines.join(\"\\n\");\n  }\n\n  lines.push(\n    \"### Classification\",\n    \"\",\n    \"Each issue is scored on two signals read from its body:\",\n    \"\",\n    \"1. **Acceptance criteria** — count of checkbox lines\",\n    \"   (`- [ ]` / `- [x]`) under the `## Acceptance Criteria` heading.\",\n    \"2. **Sources** — count of bullet list items (`- ` / `* `) under\",\n    \"   any of `## Inputs`, `## References`, `## Sources`. Counts\",\n    \"   from every matching section are summed.\",\n    \"\",\n    \"| Class | Acceptance-criteria count | Sources count | Dispatch |\",\n    \"|-------|---------------------------|---------------|----------|\",\n    `| **small** | ≤ ${ac.smallMax} | ≤ ${sources.smallMax} | yes — worker claims normally |`,\n    `| **medium** | ≤ ${ac.mediumMax} | ≤ ${sources.mediumMax} | yes — worker claims normally |`,\n    `| **large** | > ${ac.mediumMax} on either axis | > ${sources.mediumMax} on either axis | **no — decompose first** |`,\n    \"\",\n    \"Both axes must clear the `small` threshold for the issue to classify\",\n    \"as `small`; both must clear the `medium` threshold for `medium`.\",\n    \"An issue with no recognizable `## Acceptance Criteria` section\",\n    \"counts as zero on that axis — the gate never rejects an issue it\",\n    \"cannot read.\",\n    \"\",\n    \"### Handling a `large` issue\",\n    \"\",\n    \"When the classifier returns `large`:\",\n    \"\",\n    \"1. **Add** the `status:needs-attention` label to the issue with\",\n    \"   `--add-label` alone. Leave the existing base `status:*` label\",\n    \"   (`status:ready`) in place — `status:needs-attention` is\",\n    \"   **additive**, so a flagged issue reads `status:ready` +\",\n    \"   `status:needs-attention`. Do **not** remove the base status:\",\n    \"   stripping it leaves the issue with no base `status:*` label,\",\n    \"   invisible to every status-driven query and to the queue itself,\",\n    \"   and a later flag-clear can never restore dispatchability. The\",\n    \"   `status:needs-attention` label already keeps the issue out of\",\n    \"   the dispatch queue, so the base label safely stays:\",\n    \"   ```bash\",\n    '   gh issue edit <number> --add-label \"status:needs-attention\"',\n    \"   ```\",\n    \"2. Post the decomposition-proposal comment (see template below),\",\n    \"   with `<AC_COUNT>` / `<SOURCES_COUNT>` substituted from the\",\n    \"   classification and `<AC_LIMIT>` / `<SOURCES_LIMIT>` set to\",\n    `   \\`${ac.mediumMax}\\` / \\`${sources.mediumMax}\\`.`,\n    \"3. Skip the issue this dispatch cycle — do **not** claim the\",\n    \"   issue, create a branch, or start implementation.\",\n  );\n\n  if (gate.autoFile) {\n    lines.push(\n      \"4. **Auto-file is ON.** After posting the comment, file each\",\n      \"   phase from the proposal as a new sub-issue, link them with\",\n      \"   `Depends on:` lines, and update the parent body to include\",\n      \"   `Depends on: #<phase-1>, #<phase-2>, #<phase-3>`. Set the\",\n      \"   parent to `status:blocked`.\",\n    );\n  } else {\n    lines.push(\n      \"4. **Auto-file is OFF.** Stop after posting the comment. A human\",\n      \"   reviews the proposal, files the phased sub-issues manually,\",\n      \"   and clears `status:needs-attention` when the decomposition\",\n      \"   is in place. When clearing the flag, if the issue carries **no**\",\n      \"   base `status:*` label — a legacy issue flagged before the\",\n      \"   additive-flag fix, whose base status was stripped at flag time —\",\n      \"   also add `status:ready` (or `status:blocked` when the body still\",\n      \"   declares an open `Depends on:` dependency) in the same edit so\",\n      \"   the issue re-enters the queue instead of going invisible.\",\n    );\n  }\n\n  const overrideEntries = Object.entries(gate.bundleOverrides).filter(\n    ([label]) => !isPhaseLabelOwnedByExcluded(label, excludeBundles),\n  );\n  if (overrideEntries.length > 0) {\n    lines.push(\n      \"\",\n      \"### Per-phase-label thresholds\",\n      \"\",\n      \"Issues whose `type:*` or phase label matches an entry below are\",\n      \"classified against the override's thresholds instead of the\",\n      \"global `acceptance-criteria` / `sources` defaults. This\",\n      \"accommodates **content-spec workflows** — issues whose AC list\",\n      \"is the per-section content checklist for one cohesive document,\",\n      \"not a phase-completion checklist that can be decomposed.\",\n      \"\",\n      \"| Phase label | AC `mediumMax` | Sources `mediumMax` |\",\n      \"|-------------|----------------|---------------------|\",\n    );\n    // Sort keys for deterministic rendering.\n    const sortedKeys = overrideEntries.map(([k]) => k).sort();\n    for (const label of sortedKeys) {\n      const override = gate.bundleOverrides[label];\n      const acMax = override.acceptanceCriteria?.mediumMax;\n      const sourcesMax = override.sources?.mediumMax;\n      const acCell = acMax === undefined ? \"_(global)_\" : `${acMax}`;\n      const sourcesCell =\n        sourcesMax === undefined ? \"_(global)_\" : `${sourcesMax}`;\n      lines.push(`| \\`${label}\\` | ${acCell} | ${sourcesCell} |`);\n    }\n    lines.push(\n      \"\",\n      \"When an issue carries multiple labels that each match an entry\",\n      \"in this table, the orchestrator picks the **first match in\",\n      \"alphabetical order on the label name** — first-wins, deterministic.\",\n    );\n  }\n\n  lines.push(\n    \"\",\n    \"### Reconfiguring the thresholds\",\n    \"\",\n    \"Every threshold above is configurable per repo — the global\",\n    \"`acceptance-criteria` / `sources` classification bands and each\",\n    \"per-phase-label override. Retune them in the project's\",\n    \"configulator config so the gate fits this repo's issue shapes:\",\n    \"\",\n    \"- `AgentConfigOptions.scopeGate.acceptanceCriteria` /\",\n    \"  `AgentConfigOptions.scopeGate.sources` — the global\",\n    \"  `smallMax` / `mediumMax` bands applied to every issue.\",\n    \"- `AgentConfigOptions.scopeGate.bundleOverrides.<phase-label>` —\",\n    \"  a per-phase-label override for **any** phase label, not just\",\n    \"  the ones shipped above. The map deep-merges with the shipped\",\n    \"  defaults (consumer-wins-per-key): add a key to raise a new\",\n    \"  label's AC / sources ceiling, set an existing key to replace a\",\n    \"  shipped default, or set a key to `undefined` to drop a shipped\",\n    \"  default and classify that label against the global bands.\",\n    \"\",\n    \"Each override entry's `acceptanceCriteria` and `sources` axes are\",\n    \"independent — override one and the other falls through to the\",\n    \"global band. Malformed thresholds (negative, non-integer, or\",\n    \"`mediumMax <= smallMax`) fail the build at synth time.\",\n  );\n\n  lines.push(\n    \"\",\n    \"### Decomposition-proposal template\",\n    \"\",\n    \"The orchestrator posts the following comment on every `large`\",\n    \"issue. Consumer repos may override the body via\",\n    \"`AgentConfigOptions.scopeGate.decompositionTemplate`.\",\n    \"\",\n    \"```markdown\",\n    gate.decompositionTemplate,\n    \"```\",\n  );\n\n  return lines.join(\"\\n\");\n}\n\n/**\n * Render a shell-script snippet embedded in `check-blocked.sh`. The\n * snippet declares a `scope_of()` function that reads an issue body\n * (passed as `$1`) and echoes one of `small` / `medium` / `large`.\n * Orchestrator-side bash hooks call this function before dispatch.\n *\n * Returns the body of a shell function block (including the\n * `scope_of()` wrapper) so the surrounding script can splice it\n * inline at the exact indent level it wants.\n */\nexport function renderScopeGateShellHelpers(gate: ResolvedScopeGate): string {\n  const { acceptanceCriteria: ac, sources } = gate;\n\n  // The POSIX shell function below:\n  // 1. Reads an issue body from stdin.\n  // 2. Counts checkbox lines under \"## Acceptance Criteria\".\n  // 3. Counts bullet lines under \"## Inputs\" / \"## References\" /\n  //    \"## Sources\".\n  // 4. Echoes \"small\" / \"medium\" / \"large\" on stdout.\n  //\n  // The counts are emitted on stderr as `ac=<n> sources=<n>` so the\n  // caller can embed them in the decomposition-proposal comment\n  // without re-parsing the body.\n  //\n  // Effective thresholds are read from four shell variables so the\n  // caller can override them per-issue based on phase-label matches\n  // (see `bundle_override_for()` for the lookup helper).\n  // Defaults preserve the global thresholds when the caller does\n  // not set them.\n  const lines: Array<string> = [\n    \"# Classify an issue body against the scope-gate thresholds.\",\n    \"# Reads the issue body from stdin. Echoes one of 'small',\",\n    \"# 'medium', or 'large' on stdout. Writes the observed counts to\",\n    \"# stderr as `ac=<n> sources=<n>` so the caller can embed them in\",\n    \"# the decomposition-proposal comment.\",\n    \"#\",\n    \"# Effective per-issue thresholds are read from the four\",\n    \"# `_EFFECTIVE_*` shell variables. The caller is expected to set\",\n    \"# them via `bundle_override_for()` before invoking scope_of();\",\n    \"# defaults preserve the global thresholds.\",\n    `_EFFECTIVE_AC_SMALL_MAX=\"\\${_EFFECTIVE_AC_SMALL_MAX:-${ac.smallMax}}\"`,\n    `_EFFECTIVE_AC_MEDIUM_MAX=\"\\${_EFFECTIVE_AC_MEDIUM_MAX:-${ac.mediumMax}}\"`,\n    `_EFFECTIVE_SOURCES_SMALL_MAX=\"\\${_EFFECTIVE_SOURCES_SMALL_MAX:-${sources.smallMax}}\"`,\n    `_EFFECTIVE_SOURCES_MEDIUM_MAX=\"\\${_EFFECTIVE_SOURCES_MEDIUM_MAX:-${sources.mediumMax}}\"`,\n    \"scope_of() {\",\n    \"  local body\",\n    \"  body=$(cat)\",\n    \"  local ac_count sources_count\",\n    \"  ac_count=$(printf '%s\\\\n' \\\"$body\\\" | awk '\",\n    \"    # Count only TOP-LEVEL checkboxes — those at the shallowest\",\n    \"    # indentation in each Acceptance-Criteria section. A checkbox\",\n    \"    # with nested/indented sub-checkboxes (e.g. a `file N action-\",\n    \"    # item issues` criterion) counts once, mirroring the TS\",\n    \"    # countTopLevelCheckboxes() helper.\",\n    \"    function flush() {\",\n    \"      if (n > 0) { for (i = 0; i < n; i++) if (indents[i] == mini) total++ }\",\n    \"      n = 0; mini = -1\",\n    \"    }\",\n    \"    BEGIN { in_ac=0; total=0; n=0; mini=-1 }\",\n    \"    # Fully case-insensitive heading match mirrors the TypeScript\",\n    \"    # classifier (/^## acceptance criteria\\\\s*$/i); POSIX awk has\",\n    \"    # no /i flag, so we compare via tolower() instead of a\",\n    \"    # per-letter character class like [Aa]cceptance [Cc]riteria\",\n    \"    # which would drift for headings like `## ACCEPTANCE CRITERIA`.\",\n    \"    { lower = tolower($0) }\",\n    \"    lower ~ /^## acceptance criteria[[:space:]]*$/ { flush(); in_ac=1; next }\",\n    \"    /^## / { if (in_ac) { flush(); in_ac=0 } }\",\n    \"    in_ac && /^[[:space:]]*-[[:space:]]*\\\\[[ xX]\\\\]/ {\",\n    \"      match($0, /^[[:space:]]*/); ind = RLENGTH;\",\n    \"      indents[n++] = ind;\",\n    \"      if (mini < 0 || ind < mini) mini = ind;\",\n    \"    }\",\n    \"    END { flush(); print total }\",\n    \"  ')\",\n    \"  sources_count=$(printf '%s\\\\n' \\\"$body\\\" | awk '\",\n    \"    BEGIN { in_src=0; count=0 }\",\n    \"    # Fully case-insensitive heading match mirrors the TypeScript\",\n    \"    # classifier; see the `ac_count` block above for rationale.\",\n    \"    { lower = tolower($0) }\",\n    \"    lower ~ /^## (inputs|references|sources)[[:space:]]*$/ { in_src=1; next }\",\n    \"    /^## / { in_src=0 }\",\n    \"    # Exclude `Key: value` metadata bullets (e.g. `- Basename: …`)\",\n    \"    # — a bullet whose text is a `Word:` key/value pair is\",\n    \"    # metadata, not a source. Mirrors the TS countSourceBullets()\",\n    \"    # METADATA_KEY_VALUE_REGEX exclusion.\",\n    \"    in_src && /^[[:space:]]*[-*][[:space:]]+/ {\",\n    \"      rest = $0;\",\n    '      sub(/^[[:space:]]*[-*][[:space:]]+/, \"\", rest);',\n    \"      if (rest ~ /^[A-Za-z][A-Za-z0-9-]*:[[:space:]]+[^[:space:]]/) next;\",\n    \"      count++;\",\n    \"    }\",\n    \"    END { print count }\",\n    \"  ')\",\n    '  printf \\'ac=%s sources=%s\\\\n\\' \"$ac_count\" \"$sources_count\" >&2',\n    '  if [ \"$ac_count\" -le \"$_EFFECTIVE_AC_SMALL_MAX\" ] && [ \"$sources_count\" -le \"$_EFFECTIVE_SOURCES_SMALL_MAX\" ]; then',\n    \"    echo small\",\n    '  elif [ \"$ac_count\" -le \"$_EFFECTIVE_AC_MEDIUM_MAX\" ] && [ \"$sources_count\" -le \"$_EFFECTIVE_SOURCES_MEDIUM_MAX\" ]; then',\n    \"    echo medium\",\n    \"  else\",\n    \"    echo large\",\n    \"  fi\",\n    \"}\",\n    \"\",\n    \"# Resolve per-phase-label threshold overrides. Reads a newline-\",\n    \"# separated list of label names on stdin and echoes effective\",\n    \"# threshold variable assignments (one per line) on stdout. The\",\n    \"# caller `eval`s the output to set the four `_EFFECTIVE_*`\",\n    \"# variables before calling `scope_of()`. Also echoes\",\n    \"# `MATCHED_LABEL=<label>` (or `MATCHED_LABEL=`) so the caller can\",\n    \"# report which override fired.\",\n    \"#\",\n    \"# Tie-breaking: when more than one label matches an override key,\",\n    \"# the alphabetical first-wins rule applies — the same rule the\",\n    \"# TypeScript classifier uses.\",\n    \"bundle_override_for() {\",\n    `  local default_ac_small=${ac.smallMax}`,\n    `  local default_ac_medium=${ac.mediumMax}`,\n    `  local default_sources_small=${sources.smallMax}`,\n    `  local default_sources_medium=${sources.mediumMax}`,\n    \"  # Sort labels alphabetically so the first match is deterministic.\",\n    \"  local sorted_labels\",\n    \"  sorted_labels=$(LC_ALL=C sort)\",\n    \"  local matched_label=''\",\n    \"  local ac_small=$default_ac_small\",\n    \"  local ac_medium=$default_ac_medium\",\n    \"  local sources_small=$default_sources_small\",\n    \"  local sources_medium=$default_sources_medium\",\n    \"  while IFS= read -r label; do\",\n    '    [ -z \"$label\" ] && continue',\n    `    case \"$label\" in`,\n  ];\n\n  // Emit one case branch per shipped/resolved override.\n  // Sort keys alphabetically so the rendered shell mirrors the\n  // alphabetical first-wins rule.\n  const sortedKeys = Object.keys(gate.bundleOverrides).sort();\n  if (sortedKeys.length === 0) {\n    // Emit a no-op case so the case statement is syntactically valid.\n    lines.push(\"      *) ;;\");\n  } else {\n    for (const label of sortedKeys) {\n      const override = gate.bundleOverrides[label];\n      const acThresholds = override.acceptanceCriteria;\n      const sourcesThresholds = override.sources;\n      // POSIX shell case patterns require careful escaping; phase\n      // labels in this codebase contain only `:`, `-`, lower-case\n      // letters, and digits (e.g. `req:write`, `bcm:scaffold`), so\n      // a single-quoted literal pattern is safe.\n      const branchLines: Array<string> = [`      '${label}')`];\n      if (acThresholds !== undefined) {\n        branchLines.push(`        ac_small=${acThresholds.smallMax}`);\n        branchLines.push(`        ac_medium=${acThresholds.mediumMax}`);\n      }\n      if (sourcesThresholds !== undefined) {\n        branchLines.push(`        sources_small=${sourcesThresholds.smallMax}`);\n        branchLines.push(\n          `        sources_medium=${sourcesThresholds.mediumMax}`,\n        );\n      }\n      branchLines.push(`        matched_label='${label}'`);\n      branchLines.push(\"        break\");\n      branchLines.push(\"        ;;\");\n      lines.push(...branchLines);\n    }\n  }\n\n  lines.push(\n    \"    esac\",\n    `  done <<<\"$sorted_labels\"`,\n    `  printf 'MATCHED_LABEL=%s\\\\n' \"$matched_label\"`,\n    `  printf '_EFFECTIVE_AC_SMALL_MAX=%s\\\\n' \"$ac_small\"`,\n    `  printf '_EFFECTIVE_AC_MEDIUM_MAX=%s\\\\n' \"$ac_medium\"`,\n    `  printf '_EFFECTIVE_SOURCES_SMALL_MAX=%s\\\\n' \"$sources_small\"`,\n    `  printf '_EFFECTIVE_SOURCES_MEDIUM_MAX=%s\\\\n' \"$sources_medium\"`,\n    \"}\",\n  );\n\n  return lines.join(\"\\n\");\n}\n\n/*******************************************************************************\n *\n * Internal helpers\n *\n ******************************************************************************/\n\nfunction resolveThresholds(\n  supplied: ScopeGateThresholds | undefined,\n  defaults: ScopeGateThresholds,\n  field: \"acceptanceCriteria\" | \"sources\",\n): ScopeGateThresholds {\n  const merged: ScopeGateThresholds = {\n    smallMax: supplied?.smallMax ?? defaults.smallMax,\n    mediumMax: supplied?.mediumMax ?? defaults.mediumMax,\n  };\n  assertValidThresholds(merged, field);\n  return merged;\n}\n\n/**\n * Deep-merge the consumer's `bundleOverrides` over the shipped\n * defaults with consumer-wins-per-key.\n *\n * - Setting a key to a defined override replaces the shipped\n *   default for that key.\n * - Setting a key to `undefined` opts out of the shipped default.\n * - Adding a new key extends the override map without touching\n *   the shipped defaults.\n *\n * Resolved entries that carry no axis (both `acceptanceCriteria`\n * and `sources` are absent) are dropped so `resolveOverrideForLabels`\n * can assume any entry is actionable.\n *\n * Each axis is validated against the same rules as the global\n * thresholds — negative, non-integer, or inverted ranges throw.\n */\nfunction resolveBundleOverrides(\n  supplied:\n    | { readonly [phaseLabel: string]: ScopeGateBundleOverride | undefined }\n    | undefined,\n  defaults: { readonly [phaseLabel: string]: ResolvedScopeGateBundleOverride },\n): { readonly [phaseLabel: string]: ResolvedScopeGateBundleOverride } {\n  const out: {\n    [phaseLabel: string]: ResolvedScopeGateBundleOverride;\n  } = {};\n\n  // Start with the shipped defaults so untouched keys carry through.\n  for (const [label, override] of Object.entries(defaults)) {\n    out[label] = override;\n  }\n\n  if (supplied !== undefined) {\n    for (const label of Object.keys(supplied)) {\n      const value = supplied[label];\n      if (value === undefined) {\n        // Opt-out — drop the shipped default (or any earlier entry).\n        delete out[label];\n        continue;\n      }\n\n      const resolved: {\n        acceptanceCriteria?: ScopeGateThresholds;\n        sources?: ScopeGateThresholds;\n      } = {};\n      if (value.acceptanceCriteria !== undefined) {\n        resolved.acceptanceCriteria = resolveThresholds(\n          value.acceptanceCriteria,\n          DEFAULT_AC_THRESHOLDS,\n          \"acceptanceCriteria\",\n        );\n      }\n      if (value.sources !== undefined) {\n        resolved.sources = resolveThresholds(\n          value.sources,\n          DEFAULT_SOURCES_THRESHOLDS,\n          \"sources\",\n        );\n      }\n\n      // Drop empty overrides — they would otherwise mask a shipped\n      // default with a no-op entry.\n      if (\n        resolved.acceptanceCriteria === undefined &&\n        resolved.sources === undefined\n      ) {\n        delete out[label];\n        continue;\n      }\n\n      out[label] = resolved;\n    }\n  }\n\n  return out;\n}\n\nfunction assertValidThresholds(\n  thresholds: ScopeGateThresholds,\n  field: \"acceptanceCriteria\" | \"sources\",\n): void {\n  const { smallMax, mediumMax } = thresholds;\n  for (const [key, value] of [\n    [\"smallMax\", smallMax],\n    [\"mediumMax\", mediumMax],\n  ] as const) {\n    if (!Number.isInteger(value)) {\n      throw new Error(\n        `ScopeGateConfig.${field}.${key} must be a non-negative integer; got ${value}`,\n      );\n    }\n    if (value < 0) {\n      throw new Error(\n        `ScopeGateConfig.${field}.${key} must be a non-negative integer; got ${value}`,\n      );\n    }\n  }\n  if (mediumMax <= smallMax) {\n    throw new Error(\n      `ScopeGateConfig.${field} requires mediumMax > smallMax; got smallMax=${smallMax}, mediumMax=${mediumMax}`,\n    );\n  }\n}\n\nfunction resolveScopeClass(\n  acCount: number,\n  sourcesCount: number,\n  thresholds: {\n    readonly acceptanceCriteria: ScopeGateThresholds;\n    readonly sources: ScopeGateThresholds;\n  },\n): ScopeClass {\n  const { acceptanceCriteria: ac, sources } = thresholds;\n  if (acCount <= ac.smallMax && sourcesCount <= sources.smallMax) {\n    return \"small\";\n  }\n  if (acCount <= ac.mediumMax && sourcesCount <= sources.mediumMax) {\n    return \"medium\";\n  }\n  return \"large\";\n}\n\nconst AC_CHECKBOX_REGEX = /^(\\s*)-\\s*\\[[ xX]\\]/;\nconst SOURCES_BULLET_REGEX = /^\\s*[-*]\\s+(.*)$/;\n/**\n * A `Word: value` bullet body is treated as a key/value metadata\n * pair, not a source. The key is a single token — a letter followed\n * by letters/digits/hyphens — then a colon and at least one space\n * (e.g. `Basename: foo`, `Partition: 2026-Q1`). Requiring a\n * space-free single-token key keeps prose bullets that merely contain\n * a mid-sentence colon (`See section 3: details`) from being dropped,\n * and URLs (`https://…`) are excluded because `:` is followed by `/`,\n * not whitespace.\n */\nconst METADATA_KEY_VALUE_REGEX = /^[A-Za-z][A-Za-z0-9-]*:\\s+\\S/;\n\n/**\n * Count the **top-level** checkbox lines under the first\n * `## Acceptance Criteria` heading in `body`. Returns 0 when the\n * heading is absent.\n *\n * Matches `- [ ]` / `- [x]` / `- [X]` (case-insensitive). Only\n * checkboxes at the shallowest indentation seen in the section are\n * counted — a checkbox with nested/indented sub-checkboxes (e.g. a\n * \"file N action-item issues\" criterion that lists each action item\n * as its own indented checkbox) counts as **1**, not 1+N. This keeps\n * single-deliverable issues with nested criteria from tripping the\n * scope gate.\n */\nfunction countAcceptanceCriteria(body: string): number {\n  return countSectionMatches(\n    body,\n    /^## acceptance criteria\\s*$/i,\n    countTopLevelCheckboxes,\n  );\n}\n\n/**\n * Count the source bullet list items under every `## Inputs`,\n * `## References`, or `## Sources` heading in `body`. Counts are\n * summed across all matching sections.\n *\n * `Key: value` metadata bullets (e.g. `- Basename: …`,\n * `- Partition: …`) are excluded — a bullet whose text is a `Word:`\n * key/value pair describes the session, not a source, and would\n * otherwise over-count the sources axis.\n */\nfunction countSources(body: string): number {\n  return countSectionMatches(\n    body,\n    /^## (?:inputs|references|sources)\\s*$/i,\n    countSourceBullets,\n  );\n}\n\n/**\n * Count checkboxes whose indentation equals the minimum indentation\n * of any checkbox in `sectionLines`. Nested checkboxes (deeper\n * indentation) are skipped so a parent criterion with sub-items\n * counts once.\n */\nfunction countTopLevelCheckboxes(sectionLines: ReadonlyArray<string>): number {\n  let minIndent = Infinity;\n  const indents: Array<number> = [];\n  for (const line of sectionLines) {\n    const match = AC_CHECKBOX_REGEX.exec(line);\n    if (match === null) {\n      continue;\n    }\n    const indent = match[1].length;\n    indents.push(indent);\n    if (indent < minIndent) {\n      minIndent = indent;\n    }\n  }\n  return indents.filter((indent) => indent === minIndent).length;\n}\n\n/**\n * Count bullet list items that name a source, skipping `Key: value`\n * metadata bullets.\n */\nfunction countSourceBullets(sectionLines: ReadonlyArray<string>): number {\n  let count = 0;\n  for (const line of sectionLines) {\n    const match = SOURCES_BULLET_REGEX.exec(line);\n    if (match === null) {\n      continue;\n    }\n    if (METADATA_KEY_VALUE_REGEX.test(match[1])) {\n      continue;\n    }\n    count += 1;\n  }\n  return count;\n}\n\n/**\n * Collect the lines belonging to every section whose heading matches\n * `headingRegex` (summed across sections) and delegate the count to\n * `lineCounter`. A section runs from its heading to the next `## `\n * heading. Centralising the section-walk keeps the AC axis (top-level\n * checkboxes) and the sources axis (non-metadata bullets) on one\n * heading-detection codepath while letting each axis apply its own\n * line rule.\n */\nfunction countSectionMatches(\n  body: string,\n  headingRegex: RegExp,\n  lineCounter: (sectionLines: ReadonlyArray<string>) => number,\n): number {\n  const lines = body.split(/\\r?\\n/);\n  let count = 0;\n  let inSection = false;\n  let sectionLines: Array<string> = [];\n  const flush = (): void => {\n    if (sectionLines.length > 0) {\n      count += lineCounter(sectionLines);\n      sectionLines = [];\n    }\n  };\n  for (const line of lines) {\n    if (headingRegex.test(line)) {\n      flush();\n      inSection = true;\n      continue;\n    }\n    if (inSection && /^## /.test(line)) {\n      flush();\n      inSection = false;\n      continue;\n    }\n    if (inSection) {\n      sectionLines.push(line);\n    }\n  }\n  flush();\n  return count;\n}\n","import { isTypeLabelOwnedByExcluded } from \"./bundle-ownership\";\nimport { AgentTierConfig } from \"../agent-config-options\";\n\n/**\n * Valid funnel-tier values. Lower numbers dispatch first when priority\n * is tied. See `DEFAULT_AGENT_TIERS` for the role of each tier.\n */\nexport const AGENT_TIER_VALUES = [0, 1, 2, 3, 4] as const;\nexport type AgentTier = (typeof AGENT_TIER_VALUES)[number];\n\n/**\n * Human-readable role name for each funnel tier. Rendered into the\n * orchestrator-conventions rule and surfaced in generated `PICK` lines\n * so agents and humans can read the sort key at a glance.\n */\nexport const AGENT_TIER_ROLES: Readonly<Record<AgentTier, string>> = {\n  0: \"routing\",\n  1: \"research\",\n  2: \"profiles\",\n  3: \"synthesis\",\n  4: \"support\",\n};\n\n/**\n * A single resolved agent-type → tier mapping. Returned by\n * `resolveAgentTiers()`; the rendered table in the orchestrator rule\n * content and the lookup table embedded in `check-blocked.sh` are\n * derived from this list.\n */\nexport interface ResolvedAgentTier {\n  /**\n   * GitHub `type:*` label value (e.g. `\"feat\"`, `\"research\"`,\n   * `\"company-profile\"`). The leading `type:` prefix is **not** part\n   * of the stored value — it is added when the resolver stringifies\n   * the lookup table.\n   */\n  readonly type: string;\n  /** Funnel tier 0–4 (lower dispatches first on a priority tie). */\n  readonly tier: AgentTier;\n  /** Human-readable tier role (routing / research / profiles / synthesis / support). */\n  readonly role: string;\n}\n\n/**\n * Canonical default mapping of GitHub `type:*` label values to funnel\n * tiers. Mirrors openhi's `DISPATCHER.md` Dispatch Table plus the\n * taxonomy documented in the Group D epic (#414, issue #473).\n *\n * - **Tier 0 — routing.** Unblocks other work. Picked first on a\n *   priority tie. Covers the issue-worker's own type labels\n *   (`feat`, `fix`, `chore`, `refactor`, `docs`, `release`,\n *   `hotfix`). Unknown labels also fall through here via\n *   `UNKNOWN_TYPE_FALLBACK_TIER` so an unclassified issue never\n *   blocks the queue.\n * - **Tier 1 — research.** Feeds downstream pipelines.\n * - **Tier 2 — profiles.** Consumes research.\n * - **Tier 3 — synthesis.** Produces deliverables.\n * - **Tier 4 — support.** Important but not pipeline-critical.\n *\n * Consumers extend or override this list via\n * `AgentConfigOptions.tiers` (see `resolveAgentTiers`). Every\n * registered agent type must resolve to exactly one tier; unmapped\n * types fail synth-time validation.\n */\nexport const DEFAULT_AGENT_TIERS: ReadonlyArray<ResolvedAgentTier> = [\n  // Tier 0 — routing (default branch for issue-worker type labels too,\n  // so issues without a pipeline type still sort sensibly).\n  { type: \"feat\", tier: 0, role: AGENT_TIER_ROLES[0] },\n  { type: \"fix\", tier: 0, role: AGENT_TIER_ROLES[0] },\n  { type: \"chore\", tier: 0, role: AGENT_TIER_ROLES[0] },\n  { type: \"refactor\", tier: 0, role: AGENT_TIER_ROLES[0] },\n  { type: \"docs\", tier: 0, role: AGENT_TIER_ROLES[0] },\n  { type: \"release\", tier: 0, role: AGENT_TIER_ROLES[0] },\n  { type: \"hotfix\", tier: 0, role: AGENT_TIER_ROLES[0] },\n\n  // Tier 1 — research.\n  { type: \"research\", tier: 1, role: AGENT_TIER_ROLES[1] },\n  { type: \"industry-discovery\", tier: 1, role: AGENT_TIER_ROLES[1] },\n  { type: \"standards-research\", tier: 1, role: AGENT_TIER_ROLES[1] },\n  { type: \"regulatory-research\", tier: 1, role: AGENT_TIER_ROLES[1] },\n\n  // Tier 2 — profiles.\n  { type: \"company-profile\", tier: 2, role: AGENT_TIER_ROLES[2] },\n  { type: \"people-profile\", tier: 2, role: AGENT_TIER_ROLES[2] },\n  { type: \"software-profile\", tier: 2, role: AGENT_TIER_ROLES[2] },\n  { type: \"customer-profile\", tier: 2, role: AGENT_TIER_ROLES[2] },\n\n  // Tier 3 — synthesis.\n  { type: \"business-model\", tier: 3, role: AGENT_TIER_ROLES[3] },\n  { type: \"bcm-document\", tier: 3, role: AGENT_TIER_ROLES[3] },\n  { type: \"requirement\", tier: 3, role: AGENT_TIER_ROLES[3] },\n\n  // Tier 4 — support.\n  { type: \"meeting-processing\", tier: 4, role: AGENT_TIER_ROLES[4] },\n  { type: \"agenda\", tier: 4, role: AGENT_TIER_ROLES[4] },\n  { type: \"maintenance\", tier: 4, role: AGENT_TIER_ROLES[4] },\n  { type: \"pr-review\", tier: 4, role: AGENT_TIER_ROLES[4] },\n  { type: \"docs-sync\", tier: 4, role: AGENT_TIER_ROLES[4] },\n];\n\n/**\n * Fallback tier applied to issues whose `type:*` label does not match\n * any entry in the resolved tier table. Using tier 0 (routing) means\n * an unclassified or newly-introduced issue is dispatched **before**\n * lower-tier work on a priority tie, which matches the openhi\n * dispatcher's \"routing unblocks other work\" rule. The synth-time\n * validator still rejects **registered** custom types that omit a\n * tier assignment — the fallback exists only for unknown labels\n * encountered at runtime.\n */\nexport const UNKNOWN_TYPE_FALLBACK_TIER: AgentTier = 0;\n\n/**\n * Resolve a (possibly absent) consumer-supplied `AgentTierConfig` into\n * a deduplicated list of `ResolvedAgentTier` entries.\n *\n * Precedence:\n *\n * 1. `config.tiers` fully **replaces** the default list when supplied.\n *    This is the escape hatch for repos that want a bespoke taxonomy.\n * 2. `config.customTypes` entries **extend** whatever list is in play\n *    (default or replacement). Later entries override earlier ones on\n *    `type` collision, so consumer overrides win over defaults.\n *\n * @throws `Error` when any entry references a tier outside 0–4, when a\n *         `type` is empty/whitespace, or when `config.tiers` is an\n *         empty array (use omission to mean \"keep the defaults\").\n */\nexport function resolveAgentTiers(\n  config?: AgentTierConfig,\n): ReadonlyArray<ResolvedAgentTier> {\n  const base =\n    config?.tiers !== undefined\n      ? validateTierList(config.tiers, \"tiers\")\n      : DEFAULT_AGENT_TIERS;\n\n  if (config?.tiers !== undefined && config.tiers.length === 0) {\n    throw new Error(\n      \"AgentTierConfig.tiers must be omitted (to keep defaults) or contain at least one entry; got an empty array\",\n    );\n  }\n\n  const merged = new Map<string, ResolvedAgentTier>();\n  for (const entry of base) {\n    merged.set(entry.type, entry);\n  }\n\n  if (config?.customTypes !== undefined) {\n    for (const entry of validateTierList(config.customTypes, \"customTypes\")) {\n      merged.set(entry.type, entry);\n    }\n  }\n\n  return [...merged.values()];\n}\n\n/**\n * Synth-time validation hook. Throws a descriptive `Error` when the\n * resolved tier list is malformed. Called by `AgentConfig` before\n * rendering so a misconfigured `AgentTierConfig` fails the build\n * instead of silently shipping broken sort keys.\n *\n * Malformed cases rejected here:\n *\n * - Duplicate `type` values **within** the same supplied list (the\n *   resolver dedupes between the default list and `customTypes`, so\n *   those collisions are fine; duplicates inside one list are not).\n * - Tier values outside 0–4.\n * - Empty or whitespace-only `type` strings.\n *\n * Returns the validated list unchanged so callers can write\n * `const tiers = validateAgentTierConfig(config)` in one line.\n */\nexport function validateAgentTierConfig(\n  config?: AgentTierConfig,\n): ReadonlyArray<ResolvedAgentTier> {\n  if (config?.tiers !== undefined) {\n    assertNoDuplicates(config.tiers, \"tiers\");\n  }\n  if (config?.customTypes !== undefined) {\n    assertNoDuplicates(config.customTypes, \"customTypes\");\n  }\n  return resolveAgentTiers(config);\n}\n\n/**\n * Render the funnel-tier subsection appended to the\n * `orchestrator-conventions` rule. Always returns a non-empty string\n * because the default tier list is non-empty — the orchestrator\n * always documents its sort order.\n *\n * When `excludeBundles` is non-empty, rows whose `type:*` label is\n * owned by an excluded bundle are dropped before rendering. Tiers\n * that end up with no surviving rows render an empty\n * `_(none registered)_` cell for consistency with the existing\n * render — the tier itself stays in the table so the dispatch\n * ordering is still documented end-to-end.\n */\nexport function renderAgentTierSection(\n  tiers: ReadonlyArray<ResolvedAgentTier>,\n  excludeBundles: ReadonlyArray<string> = [],\n): string {\n  const filtered = tiers.filter(\n    (entry) => !isTypeLabelOwnedByExcluded(entry.type, excludeBundles),\n  );\n\n  const grouped = new Map<AgentTier, Array<ResolvedAgentTier>>();\n  for (const entry of filtered) {\n    const bucket = grouped.get(entry.tier) ?? [];\n    bucket.push(entry);\n    grouped.set(entry.tier, bucket);\n  }\n\n  const lines: Array<string> = [\n    \"## Funnel-tier dispatch ordering\",\n    \"\",\n    \"The orchestrator sorts eligible issues by **priority desc → tier asc → issue\",\n    \"number asc**. Lower tier numbers win ties on priority so research feeders\",\n    \"never starve while downstream synthesis consumes attention.\",\n    \"\",\n    \"| Tier | Role | Registered agent types |\",\n    \"|------|------|------------------------|\",\n  ];\n\n  for (const tier of AGENT_TIER_VALUES) {\n    const bucket = grouped.get(tier) ?? [];\n    const typeList =\n      bucket.length === 0\n        ? \"_(none registered)_\"\n        : bucket.map((e) => `\\`type:${e.type}\\``).join(\", \");\n    lines.push(`| ${tier} | ${AGENT_TIER_ROLES[tier]} | ${typeList} |`);\n  }\n\n  lines.push(\n    \"\",\n    `Unknown \\`type:*\\` labels encountered at runtime fall through to tier ${UNKNOWN_TYPE_FALLBACK_TIER} (${AGENT_TIER_ROLES[UNKNOWN_TYPE_FALLBACK_TIER]}) — the routing bucket — so an unclassified issue never blocks the queue.`,\n  );\n\n  return lines.join(\"\\n\");\n}\n\n/**\n * Render a shell-script snippet that the `check-blocked.sh` procedure\n * uses to look up a tier for a given `type:*` label. Emitted as a\n * `case` statement so the generated script stays POSIX-shell\n * compatible (no associative arrays).\n *\n * The function returns the body of a shell function, not the\n * surrounding function wrapper, so bundle code can splice it inline\n * at the exact indent level it wants.\n */\nexport function renderAgentTierCaseStatement(\n  tiers: ReadonlyArray<ResolvedAgentTier>,\n): string {\n  const lines: Array<string> = [];\n  lines.push('  case \"$1\" in');\n  for (const entry of tiers) {\n    lines.push(`    ${entry.type}) echo ${entry.tier} ;;`);\n  }\n  lines.push(`    *) echo ${UNKNOWN_TYPE_FALLBACK_TIER} ;;`);\n  lines.push(\"  esac\");\n  return lines.join(\"\\n\");\n}\n\n/*******************************************************************************\n *\n * Internal helpers\n *\n ******************************************************************************/\n\nfunction validateTierList(\n  entries: ReadonlyArray<{ readonly type: string; readonly tier: number }>,\n  field: \"tiers\" | \"customTypes\",\n): ReadonlyArray<ResolvedAgentTier> {\n  return entries.map((entry) => {\n    const trimmed = entry.type?.trim();\n    if (!trimmed) {\n      throw new Error(\n        `AgentTierConfig.${field} entry has an empty or whitespace-only \\`type\\`; every entry must declare a non-empty type label`,\n      );\n    }\n    if (!isAgentTier(entry.tier)) {\n      throw new Error(\n        `AgentTierConfig.${field} entry for \\`type:${trimmed}\\` has tier ${entry.tier}; tiers must be one of ${AGENT_TIER_VALUES.join(\", \")}`,\n      );\n    }\n    return {\n      type: trimmed,\n      tier: entry.tier,\n      role: AGENT_TIER_ROLES[entry.tier],\n    };\n  });\n}\n\nfunction assertNoDuplicates(\n  entries: ReadonlyArray<{ readonly type: string }>,\n  field: \"tiers\" | \"customTypes\",\n): void {\n  const seen = new Set<string>();\n  for (const entry of entries) {\n    const trimmed = entry.type?.trim() ?? \"\";\n    if (!trimmed) {\n      // Emptiness is validated in validateTierList; skip here so the\n      // duplicate check never matches two empty strings.\n      continue;\n    }\n    if (seen.has(trimmed)) {\n      throw new Error(\n        `AgentTierConfig.${field} declares \\`type:${trimmed}\\` more than once; every type must appear at most once within a single list`,\n      );\n    }\n    seen.add(trimmed);\n  }\n}\n\nfunction isAgentTier(value: number): value is AgentTier {\n  return (AGENT_TIER_VALUES as ReadonlyArray<number>).includes(value);\n}\n","import { UnblockDependentsConfig } from \"../agent-config-options\";\n\n/**\n * Default for whether the unblock-dependents sweep runs at all. When\n * the consumer omits `UnblockDependentsConfig`, the bundle ships with\n * the sweep **enabled** so every `status:done` transition\n * automatically propagates into the dependency graph.\n *\n * @see UnblockDependentsConfig\n */\nexport const DEFAULT_UNBLOCK_DEPENDENTS_ENABLED = true;\n\n/**\n * Default comment body posted on a newly-unblocked issue. Variables\n * are substituted at runtime by the `unblock-dependents.sh` script:\n *\n * - `<CLOSED_ISSUE>` — the `#<n>` reference to the issue whose\n *   closure triggered the sweep (e.g. `#123`).\n *\n * The placeholder syntax deliberately avoids `{{curly-brace}}` form —\n * `AgentConfig`'s template resolver claims that namespace at rule\n * generation time, so a `{{closedIssue}}` placeholder would be\n * rewritten before the agent ever saw it.\n */\nexport const DEFAULT_UNBLOCK_COMMENT_TEMPLATE =\n  \"Dependencies resolved by <CLOSED_ISSUE> — unblocking.\";\n\n/**\n * Default comment body posted on a dependent whose other dependencies\n * are still open (partial unblock). Variables substituted at runtime:\n *\n * - `<CLOSED_ISSUE>` — the just-closed issue (`#<n>`).\n * - `<OPEN_DEPS>` — space-separated list of remaining open\n *   dependencies (e.g. `#45 #47`).\n *\n * Applied when `flagPartialUnblockWithAttention` is `true`; otherwise\n * no comment is posted and the dependent is left untouched.\n */\nexport const DEFAULT_PARTIAL_UNBLOCK_COMMENT_TEMPLATE =\n  \"Dependency <CLOSED_ISSUE> resolved, but still waiting on: <OPEN_DEPS>.\";\n\n/**\n * Fully-resolved unblock-dependents settings. Every field is defaulted\n * so downstream renderers can reason about a single canonical shape.\n */\nexport interface ResolvedUnblockDependents {\n  readonly enabled: boolean;\n  readonly commentTemplate: string;\n  readonly flagPartialUnblockWithAttention: boolean;\n  readonly partialUnblockCommentTemplate: string;\n}\n\n/**\n * Resolve a (possibly absent) `UnblockDependentsConfig` into a canonical\n * `ResolvedUnblockDependents` with every field filled in. Unset fields\n * cascade from their documented defaults.\n *\n * Malformed configs (empty / whitespace-only `commentTemplate`) throw\n * a descriptive `Error` — callers should not need to guard against it\n * at runtime.\n */\nexport function resolveUnblockDependents(\n  config?: UnblockDependentsConfig,\n): ResolvedUnblockDependents {\n  const commentTemplate =\n    config?.commentTemplate ?? DEFAULT_UNBLOCK_COMMENT_TEMPLATE;\n  assertNonEmpty(commentTemplate, \"commentTemplate\");\n\n  const partialUnblockCommentTemplate =\n    config?.partialUnblockCommentTemplate ??\n    DEFAULT_PARTIAL_UNBLOCK_COMMENT_TEMPLATE;\n  assertNonEmpty(\n    partialUnblockCommentTemplate,\n    \"partialUnblockCommentTemplate\",\n  );\n\n  return {\n    enabled: config?.enabled ?? DEFAULT_UNBLOCK_DEPENDENTS_ENABLED,\n    commentTemplate,\n    flagPartialUnblockWithAttention:\n      config?.flagPartialUnblockWithAttention ?? false,\n    partialUnblockCommentTemplate,\n  };\n}\n\n/**\n * Synth-time validation hook. Throws a descriptive `Error` when the\n * supplied `UnblockDependentsConfig` is malformed. Called by\n * `AgentConfig.preSynthesize` before any rendering so a misconfigured\n * sweep fails the build instead of silently shipping a broken\n * procedure script. Returns the resolved config unchanged so callers\n * can write `const ud = validateUnblockDependentsConfig(config)` in\n * one line.\n *\n * Malformed cases rejected here:\n *\n * - `commentTemplate` empty or whitespace-only.\n * - `partialUnblockCommentTemplate` empty or whitespace-only.\n */\nexport function validateUnblockDependentsConfig(\n  config?: UnblockDependentsConfig,\n): ResolvedUnblockDependents {\n  return resolveUnblockDependents(config);\n}\n\n/**\n * Render the markdown subsection appended to the\n * `orchestrator-conventions` rule. Always returns a non-empty string\n * so the orchestrator rule documents the contract even when the\n * consumer relies on the defaults.\n */\nexport function renderUnblockDependentsSection(\n  ud: ResolvedUnblockDependents,\n): string {\n  const lines: Array<string> = [\n    \"## Agent-driven unblocking\",\n    \"\",\n    \"After any agent applies `status:done` to an issue, it runs a\",\n    \"**targeted unblock sweep** so downstream issues that were only\",\n    \"waiting on that issue transition to `status:ready` immediately —\",\n    \"without waiting for the next orchestrator dispatch cycle. Without\",\n    \"this sweep, dependents could sit in `status:blocked` for minutes\",\n    \"to hours (the scheduled-task cadence) after their last dependency\",\n    \"closed.\",\n    \"\",\n  ];\n\n  if (!ud.enabled) {\n    lines.push(\n      \"**Agent-driven unblocking is disabled for this project.** Agents\",\n      \"do not run the targeted sweep after closing an issue; dependents\",\n      \"wait for the next orchestrator dispatch (Phase C) to pick up the\",\n      \"resolved dependency. Enable the sweep via\",\n      \"`AgentConfigOptions.unblockDependents.enabled = true` once the\",\n      \"pipeline tolerates automated label transitions.\",\n      \"\",\n    );\n    return lines.join(\"\\n\");\n  }\n\n  lines.push(\n    \"### When the sweep runs\",\n    \"\",\n    \"The merge-flow agents run the sweep as the last step of the\",\n    \"`status:done` transition they own. Other bundles that close an\",\n    \"issue directly must wire the sweep explicitly — there is no\",\n    \"global hook, so a new closing path that skips these call sites\",\n    \"silently defers unblocking to the next orchestrator dispatch.\",\n    \"Current wired hook points:\",\n    \"\",\n    \"- The `pr-reviewer` sub-agent, Phase 5 (branch cleanup), after it\",\n    \"  applies `status:done` to the linked issue on a successful merge.\",\n    \"\",\n    \"Any other agent that manually applies `status:done` should call\",\n    \"`unblock-dependents.sh <closed-issue>` as its last step. The\",\n    \"sweep is idempotent, so double-invocation is a no-op.\",\n    \"\",\n    \"### What the sweep does\",\n    \"\",\n    \"The `unblock-dependents.sh` procedure, given a just-closed issue\",\n    \"number, performs the following in one shell invocation:\",\n    \"\",\n    \"1. Searches open issues for `Depends on: #<closed>` references in\",\n    \"   their body.\",\n    \"2. Skips any match carrying `status:deferred`, emitting a\",\n    \"   `SKIP_DEFERRED` line. A human-parked issue is never promoted by\",\n    \"   a sweep, no matter how its dependencies resolve.\",\n    \"3. For each remaining match, re-reads every dependency listed across\",\n    \"   **all** `Depends on:` lines in the body (bodies routinely list\",\n    \"   one dependency per line) and checks whether they are all closed.\",\n    \"4. If **all** dependencies are closed, flips the dependent from\",\n    \"   `status:blocked` to `status:ready` and posts a one-line comment\",\n    \"   citing the resolving issue.\",\n    \"5. If **some** dependencies are still open, leaves the dependent\",\n    \"   as `status:blocked` and optionally posts a partial-unblock\",\n    \"   comment (see the **Partial unblock behaviour** subsection\",\n    \"   below).\",\n    \"\",\n    \"The sweep never flips an issue it cannot read cleanly. Dependents\",\n    \"without a parseable `Depends on:` line are logged and skipped.\",\n    \"\",\n    \"### Search cap\",\n    \"\",\n    \"The `gh issue list --search` call that finds blocked dependents\",\n    \"caps the result set at **100 issues**. The cap exists because\",\n    \"`gh issue list` pages the search with `--limit`; raising the limit\",\n    \"materialises the whole backlog into a single JSON payload, which\",\n    \"gets expensive on large repos and bumps into GitHub search-API\",\n    \"secondary rate limits. In practice 100 blocked dependents is far\",\n    \"more than any healthy pipeline carries at once.\",\n    \"\",\n    \"When the backlog of `status:blocked` issues referencing the\",\n    \"just-closed issue exceeds 100, the sweep quietly skips the\",\n    \"overflow. Operators with > 100 blocked dependents should unblock\",\n    \"the tail manually — either by running the sweep repeatedly (each\",\n    \"run picks up 100 more) or by flipping `status:blocked` →\",\n    \"`status:ready` directly on the outstanding issues.\",\n    \"\",\n    \"### Output format\",\n    \"\",\n    \"The script emits one line per processed dependent so agents can\",\n    \"summarize the sweep's outcome in their session log:\",\n    \"\",\n    \"```\",\n    'UNBLOCKED #<dep> — all deps closed (<closed-list>) — \"<title>\"',\n    'UNBLOCK_FAILED #<dep> — label flip failed (all deps closed: <closed-list>) — \"<title>\"',\n    'STILL_BLOCKED #<dep> — waiting on <open-list> — \"<title>\"',\n    'SKIP_DEFERRED #<dep> — status:deferred; human-parked, not promoting — \"<title>\"',\n    \"NO_DEPENDENTS #<closed>\",\n    \"```\",\n    \"\",\n    \"`UNBLOCKED` lines mean the sweep transitioned the dependent to\",\n    \"`status:ready`. `UNBLOCK_FAILED` lines mean every dependency was\",\n    \"closed but the `gh issue edit` call rejected the label flip (API\",\n    \"error, permissions, or the dependent went stale between the\",\n    \"search and the edit) — a human needs to retry or flip the label\",\n    \"manually. `STILL_BLOCKED` lines mean the dependent stays blocked\",\n    \"pending other open deps. `SKIP_DEFERRED` lines mean the dependent\",\n    \"carries `status:deferred` and was deliberately left blocked even\",\n    \"though its dependencies resolved — the sweep never promotes a\",\n    \"human-parked issue. `NO_DEPENDENTS` means no open issue\",\n    \"references the just-closed issue in a `Depends on:` line.\",\n    \"\",\n    \"### Partial unblock behaviour\",\n    \"\",\n  );\n\n  if (ud.flagPartialUnblockWithAttention) {\n    lines.push(\n      \"**Partial-unblock comments are enabled.** When a dependent has\",\n      \"other open dependencies beyond the just-closed issue, the sweep\",\n      \"posts a partial-unblock comment citing the remaining open deps.\",\n      \"This gives operators a trail of incremental progress on\",\n      \"multi-dependency chains without flooding the issue with one\",\n      \"comment per resolved dep.\",\n    );\n  } else {\n    lines.push(\n      \"**Partial-unblock comments are disabled (default).** When a\",\n      \"dependent has other open dependencies beyond the just-closed\",\n      \"issue, the sweep logs `STILL_BLOCKED` to stdout but does not\",\n      \"post a comment on the dependent. This keeps issue threads clean\",\n      \"on multi-dependency chains — operators see the final unblock\",\n      \"comment when the last dependency closes.\",\n      \"\",\n      \"Enable partial-unblock comments via\",\n      \"`AgentConfigOptions.unblockDependents.flagPartialUnblockWithAttention = true`.\",\n    );\n  }\n\n  lines.push(\n    \"\",\n    \"### Comment templates\",\n    \"\",\n    \"The sweep posts a comment on each fully-unblocked dependent.\",\n    \"Consumers may override the comment body via\",\n    \"`AgentConfigOptions.unblockDependents.commentTemplate`. The\",\n    \"template substitutes `<CLOSED_ISSUE>` (the `#<n>` reference of\",\n    \"the resolving issue) at comment-composition time.\",\n    \"\",\n    \"Default unblock comment:\",\n    \"\",\n    \"```markdown\",\n    ud.commentTemplate,\n    \"```\",\n  );\n\n  if (ud.flagPartialUnblockWithAttention) {\n    lines.push(\n      \"\",\n      \"Default partial-unblock comment (`<OPEN_DEPS>` is a\",\n      \"space-separated list of remaining open dependencies):\",\n      \"\",\n      \"```markdown\",\n      ud.partialUnblockCommentTemplate,\n      \"```\",\n    );\n  }\n\n  return lines.join(\"\\n\");\n}\n\n/**\n * Render the full `unblock-dependents.sh` script body for a given\n * resolved unblock-dependents config. The script takes a single\n * positional argument (the just-closed issue number) and emits one\n * line per processed dependent in the canonical\n * `UNBLOCKED` / `STILL_BLOCKED` / `NO_DEPENDENTS` format.\n *\n * Exported so `AgentConfig.preSynthesize` can emit the procedure\n * alongside `check-blocked.sh`.\n */\nexport function renderUnblockDependentsScript(\n  ud: ResolvedUnblockDependents,\n): string {\n  const lines: Array<string> = [\n    \"#!/usr/bin/env bash\",\n    \"# unblock-dependents.sh — Targeted dependency sweep after an issue closes.\",\n    \"#\",\n    \"# After any agent applies `status:done` to issue <N>, it calls\",\n    \"# this script with that issue number. The script searches open\",\n    \"# issues for `Depends on: #<N>` references in their body, checks\",\n    \"# whether *all* listed dependencies on each match are now closed,\",\n    \"# and flips fully-resolved dependents from `status:blocked` to\",\n    \"# `status:ready` with a citation comment.\",\n    \"#\",\n    \"# The sweep is idempotent: calling it twice for the same closed\",\n    \"# issue number is a no-op on the second pass because the first\",\n    \"# pass already flipped the labels.\",\n    \"#\",\n    \"# Usage:\",\n    \"#   .claude/procedures/unblock-dependents.sh <closed-issue-number>\",\n    \"#\",\n    \"# Exit codes:\",\n    \"#   0 — sweep completed (with or without matches)\",\n    \"#   1 — runtime error (e.g. gh command failed)\",\n    \"#   2 — argument missing or malformed\",\n    \"\",\n    \"set -uo pipefail\",\n    \"\",\n    \"# ── constants ────────────────────────────────────────────────────────\",\n    \"\",\n    `UNBLOCK_DEPENDENTS_ENABLED=${ud.enabled ? \"1\" : \"0\"}`,\n    `UNBLOCK_DEPENDENTS_FLAG_PARTIAL=${ud.flagPartialUnblockWithAttention ? \"1\" : \"0\"}`,\n    `UNBLOCK_COMMENT_TEMPLATE=${shellSingleQuote(ud.commentTemplate)}`,\n    `UNBLOCK_PARTIAL_COMMENT_TEMPLATE=${shellSingleQuote(ud.partialUnblockCommentTemplate)}`,\n    \"\",\n    \"# ── helpers ──────────────────────────────────────────────────────────\",\n    \"\",\n    '# Extract issue numbers from a \"Depends on:\" text. The argument may be a',\n    '# single line (\"Depends on: #1, #2, #3\") OR several Depends-on lines',\n    \"# joined into one string: bodies routinely list one dependency per line\",\n    \"# (issue #881), so callers union every matching line before calling this.\",\n    \"# Returns the space-separated union of every #<n> reference, or an empty\",\n    '# string when the text has no concrete references (e.g. a lone \"(none)\"',\n    '# sentinel). References are extracted directly, so a stray \"(none)\"',\n    \"# concatenated with a real dep line never suppresses the real dependency\",\n    \"# — only reference-free text counts as having no dependencies.\",\n    \"parse_deps() {\",\n    '  local line=\"$1\"',\n    \"  echo \\\"$line\\\" | grep -oE '#[0-9]+' | tr -d '#' | tr '\\\\n' ' ' || echo \\\"\\\"\",\n    \"}\",\n    \"\",\n    \"# Check whether a single dependency is resolved. Returns 0 (resolved)\",\n    \"# for a CLOSED issue or a MERGED PR, 1 otherwise. A Depends on: target\",\n    \"# may reference a PR (state MERGED/OPEN/CLOSED): an OPEN PR keeps\",\n    \"# blocking, MERGED resolves it, UNKNOWN (API error) stays conservative.\",\n    \"is_closed() {\",\n    \"  local state\",\n    '  state=$(gh issue view \"$1\" --json state --jq \\'.state\\' 2>/dev/null || echo \"UNKNOWN\")',\n    '  [[ \"$state\" == \"CLOSED\" || \"$state\" == \"MERGED\" ]]',\n    \"}\",\n    \"\",\n    \"# ── main ─────────────────────────────────────────────────────────────\",\n    \"\",\n    'closed_issue=\"${1:-}\"',\n    'if [[ -z \"$closed_issue\" ]]; then',\n    '  echo \"Usage: unblock-dependents.sh <closed-issue-number>\" >&2',\n    \"  exit 2\",\n    \"fi\",\n    \"\",\n    \"# Strip a leading '#' so callers can pass either `123` or `#123`.\",\n    'closed_issue=\"${closed_issue#\\\\#}\"',\n    \"\",\n    'if ! [[ \"$closed_issue\" =~ ^[0-9]+$ ]]; then',\n    '  echo \"Usage: unblock-dependents.sh <closed-issue-number>\" >&2',\n    \"  exit 2\",\n    \"fi\",\n    \"\",\n    'if [[ \"$UNBLOCK_DEPENDENTS_ENABLED\" != \"1\" ]]; then',\n    '  echo \"NO_DEPENDENTS #${closed_issue} (sweep disabled)\"',\n    \"  exit 0\",\n    \"fi\",\n    \"\",\n    \"# Find every open blocked issue whose body contains\",\n    \"# `Depends on:` and mentions the just-closed issue. The gh search\",\n    \"# is inclusive — we re-filter in the loop below against the exact\",\n    \"# `#<closed>` token to avoid substring false-positives (e.g.\",\n    \"# `#1234` matching a query for `#123`).\",\n    \"#\",\n    \"# The --limit 100 cap is intentional: raising it materialises the\",\n    \"# whole backlog into a single JSON payload (expensive on large\",\n    \"# repos) and bumps into GitHub search-API secondary rate limits.\",\n    \"# Operators with >100 blocked dependents should unblock the tail\",\n    \"# manually — re-running the sweep picks up the next 100, or flip\",\n    \"# `status:blocked` → `status:ready` directly on the overflow.\",\n    'dependents=$(gh issue list --label \"status:blocked\" --state open \\\\',\n    '  --search \"in:body \\\\\"Depends on:\\\\\"\" \\\\',\n    '  --json number,title,body,labels --limit 100 2>/dev/null || echo \"[]\")',\n    \"\",\n    \"count=$(echo \\\"$dependents\\\" | jq 'length')\",\n    'if [[ \"$count\" -eq 0 ]]; then',\n    '  echo \"NO_DEPENDENTS #${closed_issue}\"',\n    \"  exit 0\",\n    \"fi\",\n    \"\",\n    \"# Human-parked candidates (`status:deferred`). Collected jq-side into a\",\n    \"# space-delimited lookup string rather than threaded through the\",\n    \"# tab-separated records below: an extra TSV field would either sit after\",\n    \"# dep_line (displacing the mandatory-last optional field) or before it\",\n    \"# (reintroducing the #884 IFS tab-collapse bug). The skip itself happens\",\n    \"# inside the loop, after the closed-issue reference test, so an unrelated\",\n    \"# deferred issue in the search window never emits a line. No agent or\",\n    \"# sweep ever removes `status:deferred` — only a human promotes it.\",\n    'deferred_set=\" $(echo \"$dependents\" | jq -r \\'',\n    '  .[] | select(.labels | map(.name) | index(\"status:deferred\")) | .number',\n    \"' | tr '\\\\n' ' ')\\\"\",\n    \"\",\n    \"# Union every `Depends on:` line per candidate (a body may list one\",\n    \"# dependency per line) into a single space-joined dep string and stream\",\n    \"# as tab-separated number / title / dep-line tuples.\",\n    'matches=$(echo \"$dependents\" | jq -r \\'',\n    \"  .[] |\",\n    '  (.body | split(\"\\\\n\") | map(select(test(\"Depends on:\"; \"i\"))) | join(\" \")) as $dep_line |',\n    '  \"\\\\(.number)\\\\t\\\\(.title)\\\\t\\\\($dep_line)\"',\n    \"')\",\n    \"\",\n    \"found_any=false\",\n    \"while IFS=$'\\\\t' read -r num title dep_line; do\",\n    '  [[ -z \"$num\" ]] && continue',\n    '  [[ -z \"$dep_line\" ]] && continue',\n    \"\",\n    \"  # Extract the dependency list and test whether the closed issue\",\n    \"  # is actually referenced (exact `#<num>` match, not substring).\",\n    '  deps=$(parse_deps \"$dep_line\")',\n    '  if [[ -z \"${deps// /}\" ]]; then',\n    \"    continue\",\n    \"  fi\",\n    \"\",\n    \"  # Does this dependent actually reference the closed issue?\",\n    \"  referenced=false\",\n    \"  for dep in $deps; do\",\n    '    if [[ \"$dep\" == \"$closed_issue\" ]]; then',\n    \"      referenced=true\",\n    \"      break\",\n    \"    fi\",\n    \"  done\",\n    \"  if ! $referenced; then\",\n    \"    continue\",\n    \"  fi\",\n    \"\",\n    \"  found_any=true\",\n    \"\",\n    \"  # Deliberately-parked dependents never get promoted by a sweep, even\",\n    \"  # when every dependency has closed. Only a human clears\",\n    \"  # `status:deferred`.\",\n    '  if [[ \"$deferred_set\" == *\" ${num} \"* ]]; then',\n    '    echo \"SKIP_DEFERRED #${num} — status:deferred; human-parked, not promoting — \\\\\"${title}\\\\\"\"',\n    \"    continue\",\n    \"  fi\",\n    \"\",\n    \"  # Re-check every dep in the list. Fully-closed → unblock.\",\n    \"  all_closed=true\",\n    '  open_deps=\"\"',\n    '  closed_deps=\"\"',\n    \"  for dep in $deps; do\",\n    '    if is_closed \"$dep\"; then',\n    '      closed_deps=\"${closed_deps}#${dep} \"',\n    \"    else\",\n    \"      all_closed=false\",\n    '      open_deps=\"${open_deps}#${dep} \"',\n    \"    fi\",\n    \"  done\",\n    \"\",\n    \"  if $all_closed; then\",\n    \"    comment=${UNBLOCK_COMMENT_TEMPLATE//<CLOSED_ISSUE>/#${closed_issue}}\",\n    \"    # The edit is the label-flip that is the whole point of the sweep.\",\n    \"    # If it fails we must report the failure — otherwise the agent log\",\n    \"    # claims the dependent was unblocked when its status:blocked label\",\n    \"    # is still on. The comment is best-effort (its absence is recoverable\",\n    \"    # by re-running the sweep), so it stays soft-failed with `|| true`.\",\n    '    if gh issue edit \"$num\" \\\\',\n    '        --remove-label \"status:blocked\" \\\\',\n    '        --add-label \"status:ready\" >/dev/null 2>&1; then',\n    '      gh issue comment \"$num\" --body \"$comment\" >/dev/null 2>&1 || true',\n    '      echo \"UNBLOCKED #${num} — all deps closed (${closed_deps% }) — \\\\\"${title}\\\\\"\"',\n    \"    else\",\n    '      echo \"UNBLOCK_FAILED #${num} — label flip failed (all deps closed: ${closed_deps% }) — \\\\\"${title}\\\\\"\"',\n    \"    fi\",\n    \"  else\",\n    '    if [[ \"$UNBLOCK_DEPENDENTS_FLAG_PARTIAL\" == \"1\" ]]; then',\n    \"      partial=${UNBLOCK_PARTIAL_COMMENT_TEMPLATE//<CLOSED_ISSUE>/#${closed_issue}}\",\n    \"      partial=${partial//<OPEN_DEPS>/${open_deps% }}\",\n    '      gh issue comment \"$num\" --body \"$partial\" >/dev/null 2>&1 || true',\n    \"    fi\",\n    '    echo \"STILL_BLOCKED #${num} — waiting on ${open_deps% } — \\\\\"${title}\\\\\"\"',\n    \"  fi\",\n    'done <<< \"$matches\"',\n    \"\",\n    \"if ! $found_any; then\",\n    '  echo \"NO_DEPENDENTS #${closed_issue}\"',\n    \"fi\",\n  ];\n\n  return lines.join(\"\\n\");\n}\n\n/*******************************************************************************\n *\n * Internal helpers\n *\n ******************************************************************************/\n\nfunction assertNonEmpty(value: string, field: string): void {\n  if (typeof value !== \"string\" || value.trim().length === 0) {\n    throw new Error(\n      `UnblockDependentsConfig.${field} must be a non-empty string; got ${JSON.stringify(\n        value,\n      )}`,\n    );\n  }\n}\n\n/**\n * Escape a string for safe inclusion inside single quotes in a POSIX\n * shell script. Single quotes are closed, an escaped literal is\n * appended, and the single-quote context is reopened — the standard\n * POSIX-shell idiom.\n */\nfunction shellSingleQuote(value: string): string {\n  return `'${value.replace(/'/g, \"'\\\\''\")}'`;\n}\n","import {\n  renderPhaseTypeInvariantSection,\n  renderPhaseTypeInvariantShellHelpers,\n} from \"./bundle-ownership\";\nimport {\n  CLAIM_MARKER_LIST_JQ,\n  ISSUE_CLAIM_MARKER_TAG,\n  renderClaimVerificationSection,\n} from \"./claim-verification\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport { ResolvedRunRatio, resolveRunRatio } from \"./run-ratio\";\nimport {\n  ResolvedScheduledTasks,\n  renderScheduledTasksSection,\n  resolveScheduledTasks,\n} from \"./scheduled-tasks\";\nimport {\n  ResolvedScopeGate,\n  renderScopeGateSection,\n  renderScopeGateShellHelpers,\n  resolveScopeGate,\n} from \"./scope-gate\";\nimport { DEFAULT_SHARED_INDEX_PATHS } from \"./shared-editing\";\nimport {\n  AGENT_TIER_ROLES,\n  DEFAULT_AGENT_TIERS,\n  ResolvedAgentTier,\n  UNKNOWN_TYPE_FALLBACK_TIER,\n  renderAgentTierCaseStatement,\n  renderAgentTierSection,\n  resolveAgentTiers,\n} from \"./tiers\";\nimport {\n  ResolvedUnblockDependents,\n  renderUnblockDependentsScript,\n  renderUnblockDependentsSection,\n  resolveUnblockDependents,\n} from \"./unblock-dependents\";\nimport {\n  AgentRuleBundle,\n  AgentTierConfig,\n  RunRatioConfig,\n  ScheduledTasksConfig,\n  ScopeGateConfig,\n  UnblockDependentsConfig,\n} from \"../agent-config-options\";\nimport {\n  AGENT_MODEL,\n  AGENT_RULE_SCOPE,\n  AgentCommand,\n  AgentProcedure,\n  AgentSubAgent,\n} from \"../types\";\n\n/**\n * Fleet anti-collision (codedrifters/packages#868): a PR whose newest\n * `## Reviewer*` comment was created or last edited within this window is\n * treated as having a review already in flight, so the Phase B PR sweep\n * skips dispatching a second `pr-reviewer` on it. Overlapping fleet\n * runners otherwise re-dispatch a reviewer on the same PR every cycle.\n */\nexport const REVIEW_IN_FLIGHT_WINDOW_MINUTES = 15;\n\n/*******************************************************************************\n *\n * Shared delegation-active signal helper.\n *\n * Both the feedback-drain (`cmd_needs_worker` in pr-sweep.sh) and the\n * lease-reconcile (`cmd_lease_reconcile` in check-blocked.sh) must reason\n * about whether a `review:fixing` delegation is *demonstrably active* using\n * the same three per-PR signals, so the two can never diverge on what\n * \"active\" means. This factory renders one shell function,\n * `delegation_active_signals <pr-number> <head-oid>`, that is embedded\n * verbatim into BOTH scripts. Given a PR number and its `headRefOid`, it\n * echoes a single line of three fields joined by the ASCII Unit Separator\n * (`\\x1f`), in the order `fixlist_at`, `report_at`, `head_at`. A\n * non-whitespace delimiter is used deliberately: any field may be empty,\n * and a `read` with a whitespace IFS (tab included) collapses adjacent\n * empty fields, which would shift `head_at` into `report_at`. Each field\n * is an ISO-8601 timestamp or the empty string:\n *\n *   - fixlist_at — createdAt of the newest reviewer fix-list PR comment\n *     (heading `## Reviewer: fix list for @issue-worker`). Empty when no\n *     fix-list exists (e.g. a hand-applied lease). This is the lease's\n *     reference time.\n *   - report_at — createdAt of the newest worker-report PR comment (the\n *     stable HTML marker complete-feedback-handoff.sh embeds). Empty when\n *     no worker result has landed. `report_at > fixlist_at` ⇒ a worker\n *     result already landed.\n *   - head_at — committer date of the branch HEAD commit (headRefOid).\n *     `head_at > fixlist_at` ⇒ the branch advanced past the fix-list, i.e.\n *     a worker pushed. Empty when the commit lookup fails or no head-oid\n *     was supplied.\n *\n * The comments payload is fetched once and both comment-derived fields are\n * extracted from it. All comparisons are plain lexical string compares on\n * the ISO-8601 (UTC `Z`) timestamps GitHub returns, so both call sites\n * order timestamps identically. Callers apply their own interpretation of\n * the triple (skip/drain vs. re-arm/clear).\n *\n ******************************************************************************/\n\nfunction renderDelegationActiveSignalsHelper(): ReadonlyArray<string> {\n  return [\n    \"# delegation_active_signals <pr-number> <head-oid>\",\n    \"# Echo a \\\\x1f-separated triple: <fixlist_at><US><report_at><US><head_at>\",\n    \"# (US = ASCII Unit Separator; see the printf below for why not a tab).\",\n    \"# Each field is an ISO-8601 timestamp or empty. Shared by the\",\n    \"# feedback-drain (cmd_needs_worker) and the lease-reconcile\",\n    \"# (cmd_lease_reconcile) so both judge a delegation 'active' the same\",\n    \"# way. See the block comment above the renderer for field semantics.\",\n    \"delegation_active_signals() {\",\n    '  local pr_num=\"$1\"',\n    '  local head_oid=\"${2:-}\"',\n    \"\",\n    \"  # Pull the PR comments once; derive both the fix-list reference time\",\n    \"  # and the newest worker-report time from the same payload.\",\n    \"  local comments\",\n    '  comments=$(gh pr view \"$pr_num\" --json comments \\\\',\n    \"    --jq '.comments' 2>/dev/null || echo \\\"[]\\\")\",\n    \"\",\n    \"  # Newest fix-list comment createdAt (empty if none found).\",\n    \"  local fixlist_at\",\n    '  fixlist_at=$(echo \"$comments\" | jq -r \\'',\n    '    [.[] | select(.body | contains(\"## Reviewer: fix list for @issue-worker\"))]',\n    '    | sort_by(.createdAt) | last | .createdAt // \"\"\\' 2>/dev/null)',\n    \"\",\n    \"  # Newest worker-report createdAt (empty if none found). Keyed off the\",\n    \"  # stable HTML marker complete-feedback-handoff.sh embeds.\",\n    \"  local report_at\",\n    '  report_at=$(echo \"$comments\" | jq -r \\'',\n    '    [.[] | select(.body | contains(\"issue-worker feedback hand-off — review:needs-worker cleared\"))]',\n    '    | sort_by(.createdAt) | last | .createdAt // \"\"\\' 2>/dev/null)',\n    \"\",\n    \"  # Branch HEAD committer date (empty when no head-oid or lookup fails).\",\n    '  local head_at=\"\"',\n    '  if [[ -n \"$head_oid\" ]]; then',\n    '    head_at=$(gh api \"repos/{owner}/{repo}/commits/${head_oid}\" \\\\',\n    '      --jq \\'.commit.committer.date // \"\"\\' 2>/dev/null || echo \"\")',\n    \"  fi\",\n    \"\",\n    \"  # Emit the triple delimited by the ASCII Unit Separator (\\\\x1f), NOT a\",\n    \"  # tab: any field may be empty, and `read` with a whitespace IFS (tab\",\n    \"  # counts) collapses adjacent empty fields — which would shift head_at\",\n    \"  # into report_at. \\\\x1f is non-whitespace and never appears in a\",\n    \"  # timestamp, so callers `IFS=$'\\\\x1f' read -r fixlist_at report_at\",\n    \"  # head_at` recover all three fields even when the middle one is empty.\",\n    '  printf \\'%s\\\\x1f%s\\\\x1f%s\\\\n\\' \"$fixlist_at\" \"$report_at\" \"$head_at\"',\n    \"}\",\n  ];\n}\n\n/*******************************************************************************\n *\n * check-blocked.sh — Token-efficient issue triage for agent loops.\n *\n * The procedure content is parameterized by the resolved funnel-tier\n * table so consumer overrides propagate into the shell script's\n * tier_of() lookup. `buildCheckBlockedProcedure()` is the factory;\n * `checkBlockedProcedure` (exported below) is the default instance\n * that ships when no `AgentTierConfig` override is supplied.\n *\n ******************************************************************************/\n\nfunction buildCheckBlockedScript(\n  tiers: ReadonlyArray<ResolvedAgentTier>,\n  scopeGate: ResolvedScopeGate,\n  _runRatio: ResolvedRunRatio,\n): string {\n  const tierCase = renderAgentTierCaseStatement(tiers);\n  const scopeHelper = renderScopeGateShellHelpers(scopeGate);\n  const scopeHelperIndented = scopeHelper\n    .split(\"\\n\")\n    .map((line) => (line.length > 0 ? line : \"\"))\n    .join(\"\\n\");\n\n  return [\n    \"#!/usr/bin/env bash\",\n    \"# check-blocked.sh — Token-efficient issue triage for agent loops.\",\n    \"# Replaces inline body-parsing with shell pipelines that return only\",\n    \"# actionable summaries.\",\n    \"#\",\n    \"# Usage:\",\n    \"#   .claude/procedures/check-blocked.sh unblock\",\n    \"#   .claude/procedures/check-blocked.sh eligible\",\n    \"#   .claude/procedures/check-blocked.sh stale\",\n    \"#   .claude/procedures/check-blocked.sh orphaned\",\n    \"#   .claude/procedures/check-blocked.sh lease-reconcile\",\n    \"#   .claude/procedures/check-blocked.sh maintenance\",\n    \"#   .claude/procedures/check-blocked.sh prs\",\n    \"#   .claude/procedures/check-blocked.sh scope <issue-number>\",\n    \"#   .claude/procedures/check-blocked.sh label-invariant [--fix]\",\n    \"\",\n    \"set -uo pipefail\",\n    \"\",\n    \"# ── constants ────────────────────────────────────────────────────────\",\n    \"\",\n    \"STALE_IN_PROGRESS_HOURS=72\",\n    \"STALE_BLOCKED_HOURS=168\",\n    `SCOPE_GATE_ENABLED=${scopeGate.enabled ? \"1\" : \"0\"}`,\n    `SCOPE_GATE_AUTO_FILE=${scopeGate.autoFile ? \"1\" : \"0\"}`,\n    `SCOPE_AC_SMALL_MAX=${scopeGate.acceptanceCriteria.smallMax}`,\n    `SCOPE_AC_MEDIUM_MAX=${scopeGate.acceptanceCriteria.mediumMax}`,\n    `SCOPE_SOURCES_SMALL_MAX=${scopeGate.sources.smallMax}`,\n    `SCOPE_SOURCES_MEDIUM_MAX=${scopeGate.sources.mediumMax}`,\n    \"\",\n    \"# ── helpers ──────────────────────────────────────────────────────────\",\n    \"\",\n    '# Extract issue numbers from a \"Depends on:\" text. The argument may be a',\n    '# single line (\"Depends on: #1, #2, #3\") OR several Depends-on lines',\n    \"# joined into one string: bodies routinely list one dependency per line\",\n    \"# (issue #881), so callers union every matching line before calling this.\",\n    \"# Returns the space-separated union of every #<n> reference, or an empty\",\n    '# string when the text has no concrete references (e.g. a lone \"(none)\"',\n    '# sentinel). References are extracted directly, so a stray \"(none)\"',\n    \"# concatenated with a real dep line never suppresses the real dependency\",\n    \"# — only reference-free text counts as having no dependencies.\",\n    \"parse_deps() {\",\n    '  local line=\"$1\"',\n    \"  echo \\\"$line\\\" | grep -oE '#[0-9]+' | tr -d '#' | tr '\\\\n' ' ' || echo \\\"\\\"\",\n    \"}\",\n    \"\",\n    \"# Check whether a single dependency is resolved. Returns 0 (resolved)\",\n    \"# for a CLOSED issue or a MERGED PR, 1 otherwise. A Depends on: target\",\n    \"# may reference a PR (state MERGED/OPEN/CLOSED): an OPEN PR keeps\",\n    \"# blocking, MERGED resolves it, UNKNOWN (API error) stays conservative.\",\n    \"is_closed() {\",\n    \"  local state\",\n    '  state=$(gh issue view \"$1\" --json state --jq \\'.state\\' 2>/dev/null || echo \"UNKNOWN\")',\n    '  [[ \"$state\" == \"CLOSED\" || \"$state\" == \"MERGED\" ]]',\n    \"}\",\n    \"\",\n    \"# Map a bare type-label value (without the `type:` prefix) to its\",\n    \"# funnel tier. Echoes a single digit 0-4; unknown values fall through\",\n    `# to tier ${UNKNOWN_TYPE_FALLBACK_TIER} (${AGENT_TIER_ROLES[UNKNOWN_TYPE_FALLBACK_TIER]}) so an unclassified issue never blocks the queue.`,\n    \"tier_of() {\",\n    tierCase,\n    \"}\",\n    \"\",\n    scopeHelperIndented,\n    \"\",\n    renderPhaseTypeInvariantShellHelpers(),\n    \"\",\n    ...renderDelegationActiveSignalsHelper(),\n    \"\",\n    \"# ── subcommands ──────────────────────────────────────────────────────\",\n    \"\",\n    \"cmd_unblock() {\",\n    \"  # Fetch ALL open status:blocked issues, not just the first page (#823).\",\n    \"  # This is a label-filtered `gh issue list` (REST issues endpoint, which gh\",\n    \"  # paginates up to --limit) — NOT a --search query — so a large ceiling is\",\n    \"  # safe from the search-API secondary rate limits that cap unblock-dependents\",\n    \"  # at 100. An all-deps-closed issue must be reachable regardless of backlog\",\n    \"  # position.\",\n    \"  local issues\",\n    '  issues=$(gh issue list --label \"status:blocked\" --state open \\\\',\n    '    --json number,body,labels --limit 1000 2>/dev/null || echo \"[]\")',\n    \"\",\n    \"  local count\",\n    \"  count=$(echo \\\"$issues\\\" | jq 'length')\",\n    '  if [[ \"$count\" -eq 0 ]]; then',\n    '    echo \"TRIAGE_DONE unblocked=0 still_blocked=0 deferred_skipped=0\"',\n    \"    return 0\",\n    \"  fi\",\n    \"\",\n    \"  # Human-parked candidates (`status:deferred`). Collected jq-side into\",\n    \"  # a space-delimited lookup string rather than threaded through the\",\n    \"  # tab-separated records below: an extra TSV field would either sit\",\n    \"  # after dep_line (displacing the mandatory-last optional field) or\",\n    \"  # before it (reintroducing the #884 IFS tab-collapse bug). No agent\",\n    \"  # or sweep ever removes `status:deferred` — only a human promotes it.\",\n    \"  local deferred_set\",\n    '  deferred_set=\" $(echo \"$issues\" | jq -r \\'',\n    '    .[] | select(.labels | map(.name) | index(\"status:deferred\")) | .number',\n    \"  ' | tr '\\\\n' ' ')\\\"\",\n    \"\",\n    \"  local issue_data\",\n    '  issue_data=$(echo \"$issues\" | jq -r \\'',\n    \"    .[] |\",\n    '    (.body | split(\"\\\\n\") | map(select(test(\"Depends on:\"; \"i\"))) | join(\" \")) as $dep_line |',\n    '    \"\\\\(.number)\\\\t\\\\($dep_line)\"',\n    \"  ')\",\n    \"\",\n    \"  # Counters for the summary line. The orchestrator reads only\",\n    \"  # TRIAGE_DONE; the per-issue lines below are for log visibility,\",\n    \"  # mirroring unblock-dependents.sh.\",\n    \"  local unblocked_count=0\",\n    \"  local still_blocked_count=0\",\n    \"  local deferred_skipped_count=0\",\n    \"\",\n    \"  while IFS=$'\\\\t' read -r num dep_line; do\",\n    '    [[ -z \"$num\" ]] && continue',\n    \"\",\n    \"    # Deliberately-parked issues never get promoted by a sweep, even\",\n    \"    # when every dependency has closed. Only a human clears\",\n    \"    # `status:deferred`.\",\n    '    if [[ \"$deferred_set\" == *\" ${num} \"* ]]; then',\n    '      echo \"SKIP_DEFERRED #${num} — status:deferred; human-parked, not promoting\"',\n    \"      deferred_skipped_count=$((deferred_skipped_count + 1))\",\n    \"      continue\",\n    \"    fi\",\n    \"\",\n    '    if [[ -z \"$dep_line\" ]]; then',\n    '      echo \"BLOCKED #${num} — no Depends on field found\"',\n    \"      still_blocked_count=$((still_blocked_count + 1))\",\n    \"      continue\",\n    \"    fi\",\n    \"\",\n    \"    local deps\",\n    '    deps=$(parse_deps \"$dep_line\")',\n    '    if [[ -z \"${deps// /}\" ]]; then',\n    \"      # Empty dependency list — treat as eligible for unblocking.\",\n    '      if gh issue edit \"$num\" \\\\',\n    '          --remove-label \"status:blocked\" \\\\',\n    '          --add-label \"status:ready\" >/dev/null 2>&1; then',\n    '        gh issue comment \"$num\" \\\\',\n    '          --body \"Dependencies resolved — unblocking.\" >/dev/null 2>&1 || true',\n    '        echo \"UNBLOCKED #${num} — no dependencies\"',\n    \"        unblocked_count=$((unblocked_count + 1))\",\n    \"      else\",\n    '        echo \"UNBLOCK_FAILED #${num} — label flip failed (no dependencies)\"',\n    \"        still_blocked_count=$((still_blocked_count + 1))\",\n    \"      fi\",\n    \"      continue\",\n    \"    fi\",\n    \"\",\n    \"    local all_closed=true\",\n    '    local open_deps=\"\"',\n    '    local closed_deps=\"\"',\n    \"    for dep in $deps; do\",\n    '      if is_closed \"$dep\"; then',\n    '        closed_deps=\"${closed_deps}#${dep} \"',\n    \"      else\",\n    \"        all_closed=false\",\n    '        open_deps=\"${open_deps}#${dep} \"',\n    \"      fi\",\n    \"    done\",\n    \"\",\n    \"    if $all_closed; then\",\n    \"      # The label flip is the load-bearing edit; if it fails we must\",\n    \"      # report the failure so the orchestrator does not double-count.\",\n    \"      # The comment is best-effort (its absence is recoverable on the\",\n    \"      # next sweep), so a failed `gh issue comment` does not block the\",\n    \"      # unblock from being recorded as successful.\",\n    '      if gh issue edit \"$num\" \\\\',\n    '          --remove-label \"status:blocked\" \\\\',\n    '          --add-label \"status:ready\" >/dev/null 2>&1; then',\n    '        gh issue comment \"$num\" \\\\',\n    '          --body \"Dependencies resolved — unblocking.\" >/dev/null 2>&1 || true',\n    '        echo \"UNBLOCKED #${num} — all deps closed (${closed_deps% })\"',\n    \"        unblocked_count=$((unblocked_count + 1))\",\n    \"      else\",\n    '        echo \"UNBLOCK_FAILED #${num} — label flip failed (all deps closed: ${closed_deps% })\"',\n    \"        still_blocked_count=$((still_blocked_count + 1))\",\n    \"      fi\",\n    \"    else\",\n    '      echo \"STILL_BLOCKED #${num} — waiting on ${open_deps% }\"',\n    \"      still_blocked_count=$((still_blocked_count + 1))\",\n    \"    fi\",\n    '  done <<< \"$issue_data\"',\n    \"\",\n    \"  # Single summary line consumed by the orchestrator.\",\n    '  echo \"TRIAGE_DONE unblocked=${unblocked_count} still_blocked=${still_blocked_count} deferred_skipped=${deferred_skipped_count}\"',\n    \"}\",\n    \"\",\n    \"cmd_eligible() {\",\n    \"  # Bucketed scan: walk priority levels critical → high → medium → low →\",\n    \"  # trivial, fetching one bucket at a time. The first bucket with at\",\n    \"  # least one survivor (after the Depends-on filter) short-circuits the\",\n    \"  # loop — lower-priority buckets are never queried in the common case.\",\n    \"  # This guarantees that every higher-priority issue is visible even\",\n    \"  # when the global ready backlog exceeds 50, at the cost of up to one\",\n    \"  # extra `gh issue list` call per empty bucket above the first hit.\",\n    \"  local level\",\n    \"  for level in critical high medium low trivial; do\",\n    \"    local issues\",\n    '    issues=$(gh issue list --label \"status:ready\" --label \"priority:${level}\" --state open \\\\',\n    '      --search \"sort:created-asc\" \\\\',\n    '      --json number,title,body,labels --limit 50 2>/dev/null || echo \"[]\")',\n    \"\",\n    \"    local count\",\n    \"    count=$(echo \\\"$issues\\\" | jq 'length')\",\n    '    if [[ \"$count\" -eq 0 ]]; then',\n    \"      continue\",\n    \"    fi\",\n    \"\",\n    \"    # Dispatch exclusions. `gh issue list` has no negative-label filter\",\n    \"    # for a label-filtered (non-search) listing, so both exclusions run\",\n    \"    # jq-side over the labels already fetched above — no new TSV field\",\n    \"    # is needed, and the mandatory-last dep_line ordering is untouched.\",\n    \"    #   - `status:needs-attention` is additive (it no longer replaces the\",\n    \"    #     base status), so a scope-gate-flagged issue keeps `status:ready`\",\n    \"    #     and would re-surface in every scan until a human clears the flag\",\n    \"    #     (#901). It is never dispatchable, so drop it from the scan.\",\n    \"    #   - `status:deferred` is human-parked: captured for provenance and\",\n    \"    #     never auto-dispatched. `status:ready` + `status:deferred` is\",\n    \"    #     reachable (e.g. after an unblock or a manual edit), so exclude\",\n    \"    #     it here as the dispatch-side half of the #887 guard.\",\n    \"    local issue_data\",\n    '    issue_data=$(echo \"$issues\" | jq -r \\'',\n    \"      .[] |\",\n    \"      (.labels | map(.name)) as $names |\",\n    '      select($names | index(\"status:needs-attention\") | not) |',\n    '      select($names | index(\"status:deferred\") | not) |',\n    '      (.body | split(\"\\\\n\") | map(select(test(\"Depends on:\"; \"i\"))) | join(\" \")) as $dep_line |',\n    '      ($names | map(select(startswith(\"type:\"))) | .[0] // \"\") as $type_label |',\n    '      \"\\\\(.number)\\\\t\\\\(.title)\\\\t\\\\($type_label)\\\\t\\\\($dep_line)\"',\n    \"    ')\",\n    \"\",\n    '    local results=\"\"',\n    \"    # Field order: number, title, type_label, dep_line. dep_line is the\",\n    \"    # only optional field, so it MUST stay last: an absent Depends-on line\",\n    \"    # yields an empty trailing field, whereas an empty non-last field\",\n    \"    # collapses under IFS=tab and shifts every later field left, dropping\",\n    \"    # type_label off the end (#884). Matches the cmd_stale blocked scan.\",\n    \"    while IFS=$'\\\\t' read -r num title type_label dep_line; do\",\n    '      [[ -z \"$num\" ]] && continue',\n    \"\",\n    '      local deps=\"\"',\n    '      if [[ -n \"$dep_line\" ]]; then',\n    '        deps=$(parse_deps \"$dep_line\")',\n    \"      fi\",\n    \"\",\n    \"      # Check if any dep is still open.\",\n    \"      local has_open_dep=false\",\n    '      local open_deps=\"\"',\n    '      if [[ -n \"${deps// /}\" ]]; then',\n    \"        for dep in $deps; do\",\n    '          if ! is_closed \"$dep\"; then',\n    \"            has_open_dep=true\",\n    '            open_deps=\"${open_deps}#${dep} \"',\n    \"          fi\",\n    \"        done\",\n    \"      fi\",\n    \"\",\n    \"      if $has_open_dep; then\",\n    '        echo \"SKIP #${num} — dep ${open_deps% } still open\"',\n    \"        continue\",\n    \"      fi\",\n    \"\",\n    \"      # Funnel-tier sort key (0-4; 0 dispatches first within a bucket).\",\n    '      local type_value=\"${type_label#type:}\"',\n    \"      local tier_key\",\n    '      tier_key=$(tier_of \"$type_value\")',\n    \"\",\n    '      local label_info=\"\"',\n    '      [[ -n \"$type_label\" ]] && label_info=\" ${type_label}\"',\n    \"\",\n    '      results=\"${results}${tier_key}\\\\t${num}\\\\tPICK #${num} priority:${level} tier:${tier_key}${label_info} \\\\\"${title}\\\\\"\\\\n\"',\n    '    done <<< \"$issue_data\"',\n    \"\",\n    \"    # Within this bucket: sort by funnel tier asc → issue number asc\",\n    \"    # (FIFO). If any PICK lines survived the Depends-on filter, emit\",\n    \"    # them and short-circuit before querying lower-priority buckets.\",\n    '    if [[ -n \"$results\" ]]; then',\n    \"      printf '%b' \\\"$results\\\" | sort -t$'\\\\t' -k1,1n -k2,2n | cut -f3\",\n    \"      return 0\",\n    \"    fi\",\n    \"  done\",\n    \"\",\n    '  echo \"NO_READY_ISSUES\"',\n    \"}\",\n    \"\",\n    \"cmd_stale() {\",\n    \"  # Check in-progress issues\",\n    \"  # (#823) cover all in-progress issues, not just the first 50\",\n    \"  local ip_issues\",\n    '  ip_issues=$(gh issue list --label \"status:in-progress\" --state open \\\\',\n    '    --json number,title,updatedAt --limit 1000 2>/dev/null || echo \"[]\")',\n    \"\",\n    \"  local ip_count\",\n    \"  ip_count=$(echo \\\"$ip_issues\\\" | jq 'length')\",\n    \"\",\n    '  if [[ \"$ip_count\" -gt 0 ]]; then',\n    \"    local ip_threshold\",\n    \"    ip_threshold=$(date -u -v-${STALE_IN_PROGRESS_HOURS}H +%Y-%m-%dT%H:%M:%S 2>/dev/null \\\\\",\n    '      || date -u -d \"${STALE_IN_PROGRESS_HOURS} hours ago\" +%Y-%m-%dT%H:%M:%S 2>/dev/null)',\n    \"\",\n    \"    local ip_data\",\n    '    ip_data=$(echo \"$ip_issues\" | jq -r \\'.[] | \"\\\\(.number)\\\\t\\\\(.title)\\\\t\\\\(.updatedAt)\"\\')',\n    \"\",\n    \"    while IFS=$'\\\\t' read -r num title updated; do\",\n    '      [[ -z \"$num\" ]] && continue',\n    '      local updated_trimmed=\"${updated%%+*}\"',\n    '      updated_trimmed=\"${updated_trimmed%%Z*}\"',\n    '      if [[ \"$updated_trimmed\" < \"$ip_threshold\" ]]; then',\n    '        local date_part=\"${updated_trimmed%%T*}\"',\n    '        echo \"STALE #${num} — no activity since ${date_part} — \\\\\"${title}\\\\\"\"',\n    \"      fi\",\n    '    done <<< \"$ip_data\"',\n    \"  fi\",\n    \"\",\n    \"  # Check blocked issues\",\n    \"  # (#823) cover all blocked issues, not just the first 50\",\n    \"  local bl_issues\",\n    '  bl_issues=$(gh issue list --label \"status:blocked\" --state open \\\\',\n    '    --json number,title,updatedAt,body --limit 1000 2>/dev/null || echo \"[]\")',\n    \"\",\n    \"  local bl_count\",\n    \"  bl_count=$(echo \\\"$bl_issues\\\" | jq 'length')\",\n    \"\",\n    '  if [[ \"$bl_count\" -gt 0 ]]; then',\n    \"    local bl_threshold\",\n    \"    bl_threshold=$(date -u -v-${STALE_BLOCKED_HOURS}H +%Y-%m-%dT%H:%M:%S 2>/dev/null \\\\\",\n    '      || date -u -d \"${STALE_BLOCKED_HOURS} hours ago\" +%Y-%m-%dT%H:%M:%S 2>/dev/null)',\n    \"\",\n    \"    local bl_data\",\n    '    bl_data=$(echo \"$bl_issues\" | jq -r \\'',\n    \"      .[] |\",\n    '      (.body | split(\"\\\\n\") | map(select(test(\"Depends on:\"; \"i\"))) | join(\" \")) as $dep_line |',\n    '      \"\\\\(.number)\\\\t\\\\(.title)\\\\t\\\\(.updatedAt)\\\\t\\\\($dep_line)\"',\n    \"    ')\",\n    \"\",\n    \"    while IFS=$'\\\\t' read -r num title updated dep_line; do\",\n    '      [[ -z \"$num\" ]] && continue',\n    '      local updated_trimmed=\"${updated%%+*}\"',\n    '      updated_trimmed=\"${updated_trimmed%%Z*}\"',\n    '      if [[ \"$updated_trimmed\" < \"$bl_threshold\" ]]; then',\n    \"        # (#822) Only flag a blocked issue with NO resolvable open dependency.\",\n    \"        # A parseable `Depends on: #N` naming any OPEN issue means the block is\",\n    \"        # legitimate phase-chain progress (the unblock sweep clears it when the\",\n    \"        # dep closes) — do NOT flag. Reserve the >7d flag for issues with no\",\n    \"        # `Depends on:` line, or whose deps are all closed yet still blocked.\",\n    '        local deps=\"\"',\n    '        [[ -n \"$dep_line\" ]] && deps=$(parse_deps \"$dep_line\")',\n    \"        local has_open_dep=false\",\n    '        if [[ -n \"${deps// /}\" ]]; then',\n    \"          for dep in $deps; do\",\n    '            if ! is_closed \"$dep\"; then',\n    \"              has_open_dep=true\",\n    \"              break\",\n    \"            fi\",\n    \"          done\",\n    \"        fi\",\n    \"        if $has_open_dep; then\",\n    \"          continue\",\n    \"        fi\",\n    '        local date_part=\"${updated_trimmed%%T*}\"',\n    '        echo \"STALE_BLOCKED #${num} — blocked since ${date_part} — \\\\\"${title}\\\\\"\"',\n    \"      fi\",\n    '    done <<< \"$bl_data\"',\n    \"  fi\",\n    \"\",\n    '  if [[ \"$ip_count\" -eq 0 && \"$bl_count\" -eq 0 ]]; then',\n    '    echo \"NO_STALE_ISSUES\"',\n    \"  fi\",\n    \"}\",\n    \"\",\n    \"cmd_orphaned() {\",\n    \"  # Check for remote branches whose issues are closed or missing\",\n    \"  git fetch --prune origin 2>/dev/null\",\n    \"  local branches\",\n    '  branches=$(git branch -r --format=\"%(refname:short)\" | grep -v HEAD | sed \"s|origin/||\")',\n    \"\",\n    \"  local found_orphan=false\",\n    \"  while IFS= read -r branch; do\",\n    '    [[ -z \"$branch\" ]] && continue',\n    '    [[ \"$branch\" == \"main\" || \"$branch\" == \"master\" ]] && continue',\n    \"\",\n    \"    # Extract issue number from branch name (e.g., feat/42-add-login → 42)\",\n    \"    local issue_num\",\n    \"    issue_num=$(echo \\\"$branch\\\" | grep -oE '/[0-9]+' | tr -d '/' | head -1)\",\n    '    [[ -z \"$issue_num\" ]] && continue',\n    \"\",\n    \"    local state\",\n    '    state=$(gh issue view \"$issue_num\" --json state --jq \\'.state\\' 2>/dev/null || echo \"NOT_FOUND\")',\n    \"\",\n    '    if [[ \"$state\" == \"CLOSED\" ]]; then',\n    \"      found_orphan=true\",\n    '      echo \"ORPHAN_BRANCH ${branch} — issue #${issue_num} is closed\"',\n    '    elif [[ \"$state\" == \"NOT_FOUND\" ]]; then',\n    \"      found_orphan=true\",\n    '      echo \"ORPHAN_BRANCH ${branch} — issue #${issue_num} not found\"',\n    \"    fi\",\n    '  done <<< \"$branches\"',\n    \"\",\n    \"  # Check for open PRs whose linked issues are closed\",\n    \"  local prs\",\n    '  prs=$(gh pr list --state open --json number,title,body --limit 50 2>/dev/null || echo \"[]\")',\n    \"  local pr_data\",\n    '  pr_data=$(echo \"$prs\" | jq -r \\'',\n    \"    .[] |\",\n    '    (.body | capture(\"(?:Closes|Fixes|Resolves) #(?<num>[0-9]+)\") | .num) as $issue |',\n    '    \"\\\\(.number)\\\\t\\\\(.title)\\\\t\\\\($issue // \"\")\"',\n    \"  ' 2>/dev/null)\",\n    \"\",\n    \"  while IFS=$'\\\\t' read -r pr_num title issue_num; do\",\n    '    [[ -z \"$pr_num\" || -z \"$issue_num\" ]] && continue',\n    '    if is_closed \"$issue_num\"; then',\n    \"      found_orphan=true\",\n    '      echo \"ORPHAN_PR #${pr_num} — linked issue #${issue_num} is closed — \\\\\"${title}\\\\\"\"',\n    \"    fi\",\n    '  done <<< \"$pr_data\"',\n    \"\",\n    \"  if ! $found_orphan; then\",\n    '    echo \"NO_ORPHANED_RESOURCES\"',\n    \"  fi\",\n    \"}\",\n    \"\",\n    \"cmd_lease_reconcile() {\",\n    \"  # PR-lease auto-reconcile for the feedback-drain loop. Two stuck\",\n    \"  # states wedge a `review:fixing` PR despite the Phase B1 drain and\",\n    \"  # the atomic worker hand-off; this sweep clears both WITHOUT a human:\",\n    \"  #\",\n    \"  #   1. Orphaned lease — PR carries `review:fixing` but NOT\",\n    \"  #      `review:needs-worker`, the reviewer's fix-list comment is older\",\n    \"  #      than the stale in-progress threshold, and NO worker-report\",\n    \"  #      comment newer than the fix-list exists. A delegation was kicked\",\n    \"  #      off but no worker result ever landed.\",\n    \"  #   2. Consumed-but-uncleared wedge — PR still carries BOTH\",\n    \"  #      `review:needs-worker` AND `review:fixing`, but the branch HEAD\",\n    \"  #      commit is NEWER than the fix-list comment and there is NO\",\n    \"  #      worker-report. The worker did the work and pushed, then skipped\",\n    \"  #      the hand-off, so the marker that the lease-without-marker\",\n    \"  #      confirm trigger keys on was never cleared.\",\n    \"  #\",\n    \"  # AUDIT TRAIL / SAFETY: neither state is silently force-released.\",\n    \"  #   - Orphaned lease → RE-APPLY `review:needs-worker` (not a\",\n    \"  #     `status:needs-attention` flag) so the Phase B1 consume loop\",\n    \"  #     retries the delegation autonomously, AND post a synthetic note\",\n    \"  #     comment recording the re-arm. Re-arming (rather than flagging\",\n    \"  #     for a human) is the autonomy-preserving choice the issue's\",\n    \"  #     never-silently-force-released AC calls for: the lease itself is\",\n    \"  #     left untouched (so the loop stays idempotent), only the durable\",\n    \"  #     work marker is restored, and the note comment is the audit\",\n    \"  #     trail proving the re-arm was deliberate.\",\n    \"  #   - Consumed-but-uncleared → REMOVE `review:needs-worker` (the\",\n    \"  #     hand-off the worker skipped) and post a synthetic reconcile note\",\n    \"  #     comment, flipping the PR into the lease-without-marker state the\",\n    \"  #     reviewer's confirm pass keys on so it can merge. The\",\n    \"  #     `review:fixing` lease is left for that confirm pass to release,\",\n    \"  #     mirroring complete-feedback-handoff.sh.\",\n    \"  #\",\n    \"  # Signals — gathered by the shared `delegation_active_signals`\",\n    \"  # helper (defined once, embedded here AND in pr-sweep.sh's\",\n    \"  # cmd_needs_worker) so the reconcile and the feedback-drain judge a\",\n    \"  # delegation 'active' identically:\",\n    \"  #   - fix-list comment: the reviewer's most recent PR comment whose\",\n    \"  #     body contains the stable heading `## Reviewer: fix list for\",\n    \"  #     @issue-worker`. Its createdAt is the lease's reference time.\",\n    \"  #   - worker-report comment: the most recent PR comment whose body\",\n    \"  #     contains the stable HTML marker\",\n    \"  #     `<!-- issue-worker feedback hand-off — review:needs-worker\",\n    \"  #     cleared -->` posted by complete-feedback-handoff.sh. Presence +\",\n    \"  #     createdAt newer than the fix-list means a result landed.\",\n    \"  #   - branch HEAD: the PR head commit committer date, compared against\",\n    \"  #     the fix-list createdAt to detect a push that advanced past the\",\n    \"  #     delegation without a hand-off.\",\n    \"\",\n    \"  local orphaned_count=0\",\n    \"  local consumed_uncleared_count=0\",\n    \"\",\n    \"  # Enumerate every open PR carrying the `review:fixing` lease — both\",\n    \"  # stuck states require it. One API call; the per-PR comment/commit\",\n    \"  # reads happen only for this (typically tiny) candidate set.\",\n    \"  local fixing_prs\",\n    '  fixing_prs=$(gh pr list --state open --label \"review:fixing\" \\\\',\n    '    --json number,labels,headRefOid --limit 50 2>/dev/null || echo \"[]\")',\n    \"\",\n    \"  local fixing_count\",\n    \"  fixing_count=$(echo \\\"$fixing_prs\\\" | jq 'length' 2>/dev/null || echo 0)\",\n    '  if [[ \"${fixing_count:-0}\" -eq 0 ]]; then',\n    '    echo \"LEASE_RECONCILE orphaned=0 consumed_uncleared=0\"',\n    \"    return 0\",\n    \"  fi\",\n    \"\",\n    \"  # Stale threshold timestamp (UTC), reusing the same\",\n    \"  # STALE_IN_PROGRESS_HOURS=72 constant the stale-issue scan applies.\",\n    \"  local lease_threshold\",\n    \"  lease_threshold=$(date -u -v-${STALE_IN_PROGRESS_HOURS}H +%Y-%m-%dT%H:%M:%S 2>/dev/null \\\\\",\n    '    || date -u -d \"${STALE_IN_PROGRESS_HOURS} hours ago\" +%Y-%m-%dT%H:%M:%S 2>/dev/null)',\n    \"\",\n    \"  local pr_rows\",\n    '  pr_rows=$(echo \"$fixing_prs\" | jq -r \\'',\n    \"    .[] |\",\n    '    (.labels | map(.name) | index(\"review:needs-worker\") != null) as $has_marker |',\n    '    \"\\\\(.number)\\\\t\\\\($has_marker)\\\\t\\\\(.headRefOid)\"',\n    \"  ' 2>/dev/null)\",\n    \"\",\n    \"  while IFS=$'\\\\t' read -r pr_num has_marker head_oid; do\",\n    '    [[ -z \"$pr_num\" ]] && continue',\n    \"\",\n    \"    # Gather the shared delegation-active signals in one call — the same\",\n    \"    # helper the feedback-drain (cmd_needs_worker) uses, so the two never\",\n    \"    # disagree on whether a delegation is demonstrably active. Yields the\",\n    \"    # fix-list reference time, the newest worker-report time, and the\",\n    \"    # branch HEAD committer date.\",\n    \"    local signals fixlist_at report_at head_at\",\n    '    signals=$(delegation_active_signals \"$pr_num\" \"$head_oid\")',\n    \"    IFS=$'\\\\x1f' read -r fixlist_at report_at head_at <<< \\\"$signals\\\"\",\n    \"\",\n    \"    # No fix-list comment at all — we cannot reason about this lease\",\n    \"    # (e.g. a human applied `review:fixing` by hand). Leave it alone.\",\n    '    if [[ -z \"$fixlist_at\" ]]; then',\n    \"      continue\",\n    \"    fi\",\n    \"\",\n    \"    # A worker-report newer than the fix-list means a result landed; the\",\n    \"    # confirm pass owns it. Skip for BOTH states.\",\n    '    if [[ -n \"$report_at\" && \"$report_at\" > \"$fixlist_at\" ]]; then',\n    \"      continue\",\n    \"    fi\",\n    \"\",\n    '    if [[ \"$has_marker\" == \"true\" ]]; then',\n    \"      # ── Consumed-but-uncleared wedge ──────────────────────────────\",\n    \"      # Marker still set + no worker-report. Reconcile only when the\",\n    \"      # branch advanced past the fix-list (the worker pushed but skipped\",\n    \"      # the hand-off); otherwise this is a normal in-flight delegation.\",\n    '      if [[ -n \"$head_at\" && \"$head_at\" > \"$fixlist_at\" ]]; then',\n    '        if gh pr edit \"$pr_num\" --remove-label \"review:needs-worker\" >/dev/null 2>&1; then',\n    '          gh pr comment \"$pr_num\" \\\\',\n    '            --body \"Maintenance reconcile: branch HEAD advanced past the reviewer fix-list with no worker hand-off — clearing the orphaned \\\\`review:needs-worker\\\\` marker so the reviewer confirm pass can merge. The \\\\`review:fixing\\\\` lease is left for that pass to release.\" >/dev/null 2>&1 || true',\n    '          echo \"LEASE_CONSUMED_UNCLEARED PR #${pr_num} — cleared review:needs-worker (branch advanced past fix-list, no worker report)\"',\n    \"          consumed_uncleared_count=$((consumed_uncleared_count + 1))\",\n    \"        else\",\n    '          echo \"LEASE_RECONCILE_FAILED PR #${pr_num} — could not remove review:needs-worker\"',\n    \"        fi\",\n    \"      fi\",\n    \"    else\",\n    \"      # ── Orphaned lease ────────────────────────────────────────────\",\n    \"      # `review:fixing` without `review:needs-worker`, no worker-report\",\n    \"      # newer than the fix-list. Reclaim only when the fix-list comment\",\n    \"      # is older than the stale threshold — a recently delegated PR may\",\n    \"      # still be mid-consume.\",\n    '      local fixlist_trimmed=\"${fixlist_at%%+*}\"',\n    '      fixlist_trimmed=\"${fixlist_trimmed%%Z*}\"',\n    '      if [[ \"$fixlist_trimmed\" < \"$lease_threshold\" ]]; then',\n    '        if gh pr edit \"$pr_num\" --add-label \"review:needs-worker\" >/dev/null 2>&1; then',\n    '          gh pr comment \"$pr_num\" \\\\',\n    '            --body \"Maintenance reconcile: \\\\`review:fixing\\\\` lease orphaned (fix-list older than ${STALE_IN_PROGRESS_HOURS}h with no worker report) — re-applying the \\\\`review:needs-worker\\\\` marker so the feedback-drain loop retries the delegation. This is a deliberate re-arm, not a silent force-release; the \\\\`review:fixing\\\\` lease is left untouched.\" >/dev/null 2>&1 || true',\n    '          echo \"LEASE_ORPHANED PR #${pr_num} — re-applied review:needs-worker (fix-list stale, no worker report)\"',\n    \"          orphaned_count=$((orphaned_count + 1))\",\n    \"        else\",\n    '          echo \"LEASE_RECONCILE_FAILED PR #${pr_num} — could not re-apply review:needs-worker\"',\n    \"        fi\",\n    \"      fi\",\n    \"    fi\",\n    '  done <<< \"$pr_rows\"',\n    \"\",\n    \"  # Single summary line consumed by the orchestrator, matching the\",\n    \"  # MAINTENANCE_DONE convention.\",\n    '  echo \"LEASE_RECONCILE orphaned=${orphaned_count} consumed_uncleared=${consumed_uncleared_count}\"',\n    \"}\",\n    \"\",\n    \"cmd_maintenance() {\",\n    \"  # Phase D maintenance sweep: flag stale issues with\",\n    \"  # `status:needs-attention`, count orphan branches/PRs (no\",\n    \"  # auto-deletion), auto-reconcile stuck PR leases (re-arm orphaned\",\n    \"  # leases / clear consumed-but-uncleared markers, see\",\n    \"  # cmd_lease_reconcile), and emit a MAINTENANCE_DONE summary line\",\n    \"  # plus a LEASE_RECONCILE summary line so the orchestrator never\",\n    \"  # iterates raw stale/orphan/lease output. Mirrors the discipline of\",\n    \"  # cmd_unblock — per-issue / per-PR informational lines (FLAGGED #N,\",\n    \"  # ORPHAN_BRANCH …, LEASE_ORPHANED PR #N …) survive for log\",\n    \"  # visibility but are not load-bearing for the orchestrator.\",\n    \"  #\",\n    \"  # SAFETY: this subcommand NEVER auto-resets stale issues to\",\n    \"  # `status:ready`. It only adds `status:needs-attention`; the\",\n    \"  # existing `status:in-progress` or `status:blocked` label\",\n    \"  # stays in place so partial implementation work on a branch\",\n    \"  # remains visible to humans. The PR-lease reconcile likewise never\",\n    \"  # silently force-releases a `review:fixing` lease — it re-arms the\",\n    \"  # work marker (orphaned) or clears the consumed marker (wedge) and\",\n    \"  # always posts an audit-trail note comment.\",\n    \"\",\n    \"  local flagged_stale_count=0\",\n    \"  local flagged_blocked_count=0\",\n    \"  local orphan_branches_count=0\",\n    \"  local orphan_prs_count=0\",\n    \"\",\n    \"  # ── stale detection + flagging ──────────────────────────────\",\n    \"  local stale_output\",\n    \"  stale_output=$(cmd_stale)\",\n    \"\",\n    \"  while IFS= read -r line; do\",\n    '    [[ -z \"$line\" ]] && continue',\n    '    case \"$line\" in',\n    \"      'STALE #'*)\",\n    \"        # Extract the issue number after the '#' and before the ' '.\",\n    \"        local num=${line#STALE #}\",\n    \"        num=${num%% *}\",\n    \"        # (#822) Idempotent: never re-apply the human-clear-only flag to an\",\n    \"        # issue that already carries status:needs-attention.\",\n    \"        local existing_labels\",\n    '        existing_labels=$(gh issue view \"$num\" --json labels \\\\',\n    '          --jq \\'.labels | map(.name) | index(\"status:needs-attention\") != null\\' 2>/dev/null || echo \"false\")',\n    '        if [[ \"$existing_labels\" == \"true\" ]]; then',\n    '          echo \"SKIP_FLAGGED #${num} — already status:needs-attention (in-progress)\"',\n    '          echo \"$line\"',\n    \"          continue\",\n    \"        fi\",\n    '        if gh issue edit \"$num\" --add-label \"status:needs-attention\" >/dev/null 2>&1; then',\n    '          gh issue comment \"$num\" \\\\',\n    '            --body \"Flagged: in-progress for >3 days with no activity.\" >/dev/null 2>&1 || true',\n    '          echo \"FLAGGED_STALE #${num} — added status:needs-attention\"',\n    \"          flagged_stale_count=$((flagged_stale_count + 1))\",\n    \"        else\",\n    '          echo \"FLAG_FAILED #${num} — could not add status:needs-attention (stale)\"',\n    \"        fi\",\n    \"        # Surface the original informational line for log visibility.\",\n    '        echo \"$line\"',\n    \"        ;;\",\n    \"      'STALE_BLOCKED #'*)\",\n    \"        local num=${line#STALE_BLOCKED #}\",\n    \"        num=${num%% *}\",\n    \"        # (#822) Idempotent: never re-apply the human-clear-only flag to an\",\n    \"        # issue that already carries status:needs-attention.\",\n    \"        local existing_labels\",\n    '        existing_labels=$(gh issue view \"$num\" --json labels \\\\',\n    '          --jq \\'.labels | map(.name) | index(\"status:needs-attention\") != null\\' 2>/dev/null || echo \"false\")',\n    '        if [[ \"$existing_labels\" == \"true\" ]]; then',\n    '          echo \"SKIP_FLAGGED #${num} — already status:needs-attention (blocked)\"',\n    '          echo \"$line\"',\n    \"          continue\",\n    \"        fi\",\n    '        if gh issue edit \"$num\" --add-label \"status:needs-attention\" >/dev/null 2>&1; then',\n    '          gh issue comment \"$num\" \\\\',\n    '            --body \"Flagged: blocked for >7 days with no resolvable dependency — may need human intervention.\" >/dev/null 2>&1 || true',\n    '          echo \"FLAGGED_BLOCKED #${num} — added status:needs-attention\"',\n    \"          flagged_blocked_count=$((flagged_blocked_count + 1))\",\n    \"        else\",\n    '          echo \"FLAG_FAILED #${num} — could not add status:needs-attention (blocked)\"',\n    \"        fi\",\n    '        echo \"$line\"',\n    \"        ;;\",\n    \"      'NO_STALE_ISSUES')\",\n    \"        # Surface the no-op marker for log visibility; counters\",\n    \"        # stay at zero.\",\n    '        echo \"$line\"',\n    \"        ;;\",\n    \"    esac\",\n    '  done <<< \"$stale_output\"',\n    \"\",\n    \"  # ── orphan detection (count only — no auto-deletion) ────────\",\n    \"  local orphan_output\",\n    \"  orphan_output=$(cmd_orphaned)\",\n    \"\",\n    \"  while IFS= read -r line; do\",\n    '    [[ -z \"$line\" ]] && continue',\n    '    case \"$line\" in',\n    \"      'ORPHAN_BRANCH '*)\",\n    \"        orphan_branches_count=$((orphan_branches_count + 1))\",\n    '        echo \"$line\"',\n    \"        ;;\",\n    \"      'ORPHAN_PR '*)\",\n    \"        orphan_prs_count=$((orphan_prs_count + 1))\",\n    '        echo \"$line\"',\n    \"        ;;\",\n    \"      'NO_ORPHANED_RESOURCES')\",\n    '        echo \"$line\"',\n    \"        ;;\",\n    \"    esac\",\n    '  done <<< \"$orphan_output\"',\n    \"\",\n    \"  # ── PR-lease auto-reconcile (MUTATING — see cmd_lease_reconcile) ──\",\n    \"  # Run the lease sweep and surface its informational lines for log\",\n    \"  # visibility. cmd_lease_reconcile applies the label edits itself\",\n    \"  # (re-arm or clear `review:needs-worker`) and posts the audit-trail\",\n    \"  # note comment — mirroring how this maintenance sweep already\",\n    \"  # mutates issue labels directly. Its terminal LEASE_RECONCILE line is\",\n    \"  # captured and re-emitted alongside MAINTENANCE_DONE so the\",\n    \"  # orchestrator reads both summaries from one maintenance invocation.\",\n    \"  local lease_output\",\n    \"  lease_output=$(cmd_lease_reconcile)\",\n    '  local lease_summary=\"LEASE_RECONCILE orphaned=0 consumed_uncleared=0\"',\n    \"\",\n    \"  while IFS= read -r line; do\",\n    '    [[ -z \"$line\" ]] && continue',\n    '    case \"$line\" in',\n    \"      'LEASE_RECONCILE '*)\",\n    '        lease_summary=\"$line\"',\n    \"        ;;\",\n    \"      *)\",\n    '        echo \"$line\"',\n    \"        ;;\",\n    \"    esac\",\n    '  done <<< \"$lease_output\"',\n    \"\",\n    \"  # ── phase-label → type:<bundle> invariant (MUTATING) ────────\",\n    \"  # Run the label-invariant sweep in --fix mode and surface its\",\n    \"  # per-issue lines for log visibility. cmd_label_invariant applies\",\n    \"  # the label edits itself (a single atomic remove+add per issue, so\",\n    \"  # an issue is never observable carrying two type:* labels) and\",\n    \"  # flags the cases it must not guess at. Its terminal\",\n    \"  # LABEL_INVARIANT_DONE line is captured and re-emitted alongside\",\n    \"  # MAINTENANCE_DONE so the orchestrator reads every summary from\",\n    \"  # one maintenance invocation.\",\n    \"  local label_output\",\n    \"  label_output=$(cmd_label_invariant --fix)\",\n    '  local label_summary=\"LABEL_INVARIANT_DONE mode=fix checked=0 ok=0 violations=0 corrected=0 flagged=0\"',\n    \"\",\n    \"  while IFS= read -r line; do\",\n    '    [[ -z \"$line\" ]] && continue',\n    '    case \"$line\" in',\n    \"      'LABEL_INVARIANT_DONE '*)\",\n    '        label_summary=\"$line\"',\n    \"        ;;\",\n    \"      *)\",\n    '        echo \"$line\"',\n    \"        ;;\",\n    \"    esac\",\n    '  done <<< \"$label_output\"',\n    \"\",\n    \"  # ── needs-attention total ───────────────────────────────────\",\n    \"  local needs_attention_total\",\n    '  needs_attention_total=$(gh issue list --label \"status:needs-attention\" --state open \\\\',\n    \"    --json number --limit 100 2>/dev/null | jq 'length' 2>/dev/null || echo 0)\",\n    \"  needs_attention_total=${needs_attention_total:-0}\",\n    \"\",\n    \"  # Three summary lines consumed by the orchestrator: the\",\n    \"  # issue/orphan MAINTENANCE_DONE line, the PR-lease LEASE_RECONCILE\",\n    \"  # line, and the LABEL_INVARIANT_DONE line.\",\n    '  echo \"MAINTENANCE_DONE flagged_stale=${flagged_stale_count} flagged_blocked=${flagged_blocked_count} orphan_branches=${orphan_branches_count} orphan_prs=${orphan_prs_count} needs_attention_total=${needs_attention_total}\"',\n    '  echo \"$lease_summary\"',\n    '  echo \"$label_summary\"',\n    \"}\",\n    \"\",\n    \"cmd_prs() {\",\n    \"  local prs\",\n    \"  prs=$(gh pr list --state open --json number,title,isDraft,headRefName,labels,body \\\\\",\n    '    --limit 50 2>/dev/null || echo \"[]\")',\n    \"\",\n    \"  local count\",\n    \"  count=$(echo \\\"$prs\\\" | jq 'length')\",\n    '  if [[ \"$count\" -eq 0 ]]; then',\n    '    echo \"NO_OPEN_PRS\"',\n    \"    return 0\",\n    \"  fi\",\n    \"\",\n    \"  # Filter: not draft, no needs-attention label.\",\n    \"  local eligible\",\n    '  eligible=$(echo \"$prs\" | jq -r \\'',\n    \"    .[] |\",\n    \"    select(.isDraft == false) |\",\n    '    select(.labels | map(.name) | index(\"status:needs-attention\") | not) |',\n    '    (.body | capture(\"(?:Closes|Fixes|Resolves) #(?<num>[0-9]+)\") | .num) as $issue |',\n    '    \"\\\\(.number)\\\\t\\\\(.title)\\\\t\\\\(.headRefName)\\\\t\\\\($issue // \"\")\"',\n    \"  ' 2>/dev/null)\",\n    \"\",\n    '  if [[ -z \"$eligible\" ]]; then',\n    '    echo \"NO_ELIGIBLE_PRS\"',\n    \"    return 0\",\n    \"  fi\",\n    \"\",\n    \"  while IFS=$'\\\\t' read -r pr_num title branch issue_num; do\",\n    '    [[ -z \"$pr_num\" ]] && continue',\n    \"\",\n    '    if [[ -z \"$issue_num\" ]]; then',\n    '      echo \"SKIP PR #${pr_num} — no linked issue — \\\\\"${title}\\\\\"\"',\n    \"      continue\",\n    \"    fi\",\n    \"\",\n    \"    # Check CI status\",\n    \"    local failing_checks\",\n    '    failing_checks=$(gh pr checks \"$pr_num\" --json name,state \\\\',\n    '      --jq \\'[.[] | select(.state != \"SUCCESS\" and .state != \"SKIPPED\")] | length\\' 2>/dev/null || echo \"-1\")',\n    \"\",\n    '    if [[ \"$failing_checks\" == \"-1\" ]]; then',\n    '      echo \"SKIP PR #${pr_num} — could not read CI status — \\\\\"${title}\\\\\"\"',\n    \"      continue\",\n    \"    fi\",\n    \"\",\n    '    if [[ \"$failing_checks\" -gt 0 ]]; then',\n    '      echo \"SKIP PR #${pr_num} — ${failing_checks} CI check(s) not passing — \\\\\"${title}\\\\\"\"',\n    \"      continue\",\n    \"    fi\",\n    \"\",\n    \"    # Check if already approved\",\n    \"    local approved\",\n    '    approved=$(gh pr view \"$pr_num\" --json reviews \\\\',\n    '      --jq \\'[.reviews[] | select(.state == \"APPROVED\")] | length\\' 2>/dev/null || echo \"0\")',\n    '    if [[ \"$approved\" -gt 0 ]]; then',\n    '      echo \"SKIP PR #${pr_num} — already approved — \\\\\"${title}\\\\\"\"',\n    \"      continue\",\n    \"    fi\",\n    \"\",\n    '    echo \"REVIEW PR #${pr_num} issue:#${issue_num} branch:${branch} — \\\\\"${title}\\\\\"\"',\n    '  done <<< \"$eligible\"',\n    \"}\",\n    \"\",\n    \"cmd_label_invariant() {\",\n    \"  # Phase-label → type:<bundle> invariant sweep.\",\n    \"  #\",\n    \"  # Every phased-pipeline bundle pairs its <bundle>:<phase> labels\",\n    \"  # with exactly one type:<bundle> label. An agent that reconstructs\",\n    \"  # a gh issue create call from prose can stamp a conventional-commit\",\n    \"  # type label derived from the title prefix instead, producing an\",\n    \"  # issue that carries the phase label but the WRONG type label —\",\n    \"  # invisible to the --label type:<bundle> duplicate-check idiom and\",\n    \"  # mis-tiered by the funnel-tier sort in cmd_eligible.\",\n    \"  #\",\n    \"  # Default mode is REPORT-ONLY (the consumer-runnable audit); pass\",\n    \"  # --fix to apply corrections. cmd_maintenance runs the --fix mode\",\n    \"  # as part of the Phase D sweep.\",\n    \"  #\",\n    \"  # CORRECTION POLICY. An issue must carry EXACTLY ONE type:* label\",\n    \"  # (cmd_eligible derives its funnel-tier sort key from the FIRST\",\n    \"  # one, and the label conventions mandate exactly one), so the\",\n    \"  # correction REPLACES rather than merely adds:\",\n    \"  #\",\n    \"  #   no type:* at all              → add the implied type label\",\n    \"  #   only conventional-commit      → remove them, add the implied\",\n    \"  #     type labels present           label (single atomic edit)\",\n    \"  #   implied label already there   → remove the stray conventional\",\n    \"  #     alongside a conventional one   label, leaving exactly one\",\n    \"  #   a type:* owned by ANOTHER     → FLAG status:needs-attention;\",\n    \"  #     bundle                         never guess which to drop\",\n    \"  #   phase labels imply 2+ types   → FLAG status:needs-attention\",\n    \"  #\",\n    \"  # Only a conventional-commit type label is ever removed — the set\",\n    \"  # is_conventional_type_label() recognises. A type:* label owned by\",\n    \"  # a different bundle is a genuine conflict a human must resolve.\",\n    \"  # status:needs-attention is applied ADDITIVELY; the base status:*\",\n    \"  # label always stays (see the additive-flag rule).\",\n    \"  local apply=0\",\n    '  if [[ \"${1:-}\" == \"--fix\" ]]; then',\n    \"    apply=1\",\n    \"  fi\",\n    '  local mode=\"report\"',\n    '  [[ \"$apply\" -eq 1 ]] && mode=\"fix\"',\n    \"\",\n    \"  local issues\",\n    \"  issues=$(gh issue list --state open --json number,labels \\\\\",\n    '    --limit 1000 2>/dev/null || echo \"[]\")',\n    \"\",\n    \"  # Filter jq-side and emit a TWO-field record. The label list is\",\n    \"  # last AND guaranteed non-empty by the select, so no field can\",\n    \"  # collapse under IFS=tab and shift the record left (#884). The\",\n    \"  # title is deliberately not threaded through — every output line\",\n    \"  # keys off the issue number.\",\n    \"  local issue_data\",\n    '  issue_data=$(echo \"$issues\" | jq -r \\'',\n    \"    .[] |\",\n    \"    (.labels | map(.name)) as $names |\",\n    \"    select($names | length > 0) |\",\n    '    \"\\\\(.number)\\\\t\\\\($names | join(\",\"))\"',\n    \"  ' 2>/dev/null)\",\n    \"\",\n    \"  local checked_count=0\",\n    \"  local ok_count=0\",\n    \"  local corrected_count=0\",\n    \"  local flagged_count=0\",\n    \"\",\n    \"  while IFS=$'\\\\t' read -r num labels_csv; do\",\n    '    [[ -z \"$num\" ]] && continue',\n    \"\",\n    \"    local labels_nl\",\n    \"    labels_nl=$(printf '%s' \\\"$labels_csv\\\" | tr ',' '\\\\n')\",\n    \"\",\n    \"    local resolution assignment\",\n    \"    local outcome='' type_label='' phase_labels='' candidates=''\",\n    \"    resolution=$(printf '%s\\\\n' \\\"$labels_nl\\\" | phase_type_of)\",\n    \"    while IFS= read -r assignment; do\",\n    '      case \"$assignment\" in',\n    \"        OUTCOME=*) outcome=${assignment#OUTCOME=} ;;\",\n    \"        TYPE_LABEL=*) type_label=${assignment#TYPE_LABEL=} ;;\",\n    \"        CANDIDATE_TYPE_LABELS=*) candidates=${assignment#CANDIDATE_TYPE_LABELS=} ;;\",\n    \"        PHASE_LABELS=*) phase_labels=${assignment#PHASE_LABELS=} ;;\",\n    \"      esac\",\n    '    done <<< \"$resolution\"',\n    \"\",\n    \"    # No recognised phase label — the invariant does not apply.\",\n    \"    # Consumer-specific `foo:bar` labels are deliberately not policed.\",\n    '    [[ \"$outcome\" == \"none\" ]] && continue',\n    \"    checked_count=$((checked_count + 1))\",\n    \"\",\n    \"    # Idempotent flagging: read the existing flag off the labels we\",\n    \"    # already fetched rather than spending another API call.\",\n    \"    local already_flagged=0\",\n    '    case \",${labels_csv},\" in',\n    '      *\",status:needs-attention,\"*) already_flagged=1 ;;',\n    \"    esac\",\n    \"\",\n    '    if [[ \"$outcome\" == \"ambiguous\" ]]; then',\n    '      echo \"LABEL_AMBIGUOUS #${num} phase=\\\\\"${phase_labels}\\\\\" candidates=\\\\\"${candidates}\\\\\"\"',\n    \"      flagged_count=$((flagged_count + 1))\",\n    '      if [[ \"$apply\" -eq 1 && \"$already_flagged\" -eq 0 ]]; then',\n    '        if gh issue edit \"$num\" --add-label \"status:needs-attention\" >/dev/null 2>&1; then',\n    '          gh issue comment \"$num\" \\\\',\n    '            --body \"Label invariant: phase label(s) ${phase_labels} imply more than one bundle type label (${candidates}). Flagged for human triage — an ambiguous pairing is never auto-corrected.\" >/dev/null 2>&1 || true',\n    '          echo \"LABEL_FLAGGED #${num} — added status:needs-attention (ambiguous)\"',\n    \"        else\",\n    '          echo \"LABEL_FLAG_FAILED #${num} — could not add status:needs-attention (ambiguous)\"',\n    \"        fi\",\n    \"      fi\",\n    \"      continue\",\n    \"    fi\",\n    \"\",\n    \"    # Partition the issue's existing type:* labels against the\",\n    \"    # implied one.\",\n    \"    local label\",\n    \"    local has_expected=0\",\n    \"    local conv_types=''\",\n    \"    local foreign_types=''\",\n    \"    while IFS= read -r label; do\",\n    '      [ -z \"$label\" ] && continue',\n    '      case \"$label\" in',\n    \"        type:*) ;;\",\n    \"        *) continue ;;\",\n    \"      esac\",\n    '      if [ \"$label\" = \"$type_label\" ]; then',\n    \"        has_expected=1\",\n    \"        continue\",\n    \"      fi\",\n    '      if is_conventional_type_label \"$label\"; then',\n    '        conv_types=\"${conv_types}${label} \"',\n    \"      else\",\n    '        foreign_types=\"${foreign_types}${label} \"',\n    \"      fi\",\n    '    done <<< \"$labels_nl\"',\n    \"\",\n    '    if [[ \"$has_expected\" -eq 1 && -z \"${conv_types}${foreign_types}\" ]]; then',\n    '      echo \"LABEL_OK #${num} type=${type_label}\"',\n    \"      ok_count=$((ok_count + 1))\",\n    \"      continue\",\n    \"    fi\",\n    \"\",\n    \"    # A type:* label owned by a DIFFERENT bundle is a conflict the\",\n    \"    # sweep must not guess at: removing it would destroy routing\",\n    \"    # information, and adding alongside it would leave two bundle\",\n    \"    # type labels and a non-deterministic funnel tier.\",\n    '    if [[ -n \"$foreign_types\" ]]; then',\n    '      echo \"LABEL_CONFLICT #${num} phase=\\\\\"${phase_labels}\\\\\" expected=${type_label} foreign=\\\\\"${foreign_types% }\\\\\"\"',\n    \"      flagged_count=$((flagged_count + 1))\",\n    '      if [[ \"$apply\" -eq 1 && \"$already_flagged\" -eq 0 ]]; then',\n    '        if gh issue edit \"$num\" --add-label \"status:needs-attention\" >/dev/null 2>&1; then',\n    '          gh issue comment \"$num\" \\\\',\n    '            --body \"Label invariant: phase label(s) ${phase_labels} require ${type_label}, but this issue carries ${foreign_types% }, which is owned by another bundle. Flagged for human triage — the sweep only removes conventional-commit type labels.\" >/dev/null 2>&1 || true',\n    '          echo \"LABEL_FLAGGED #${num} — added status:needs-attention (conflicting bundle type)\"',\n    \"        else\",\n    '          echo \"LABEL_FLAG_FAILED #${num} — could not add status:needs-attention (conflict)\"',\n    \"        fi\",\n    \"      fi\",\n    \"      continue\",\n    \"    fi\",\n    \"\",\n    \"    # Correctable: add the implied label and/or drop the\",\n    \"    # conventional-commit label(s) shadowing it, in ONE edit so the\",\n    \"    # issue is never observable carrying two type:* labels.\",\n    '    local removing=\"${conv_types% }\"',\n    \"    local adding=''\",\n    '    [[ \"$has_expected\" -eq 0 ]] && adding=\"$type_label\"',\n    '    echo \"LABEL_VIOLATION #${num} phase=\\\\\"${phase_labels}\\\\\" expected=${type_label} add=\\\\\"${adding}\\\\\" remove=\\\\\"${removing}\\\\\"\"',\n    '    if [[ \"$apply\" -eq 0 ]]; then',\n    \"      continue\",\n    \"    fi\",\n    \"\",\n    \"    local -a edit_args=()\",\n    \"    local stray\",\n    \"    for stray in $removing; do\",\n    '      edit_args+=(--remove-label \"$stray\")',\n    \"    done\",\n    '    [[ -n \"$adding\" ]] && edit_args+=(--add-label \"$adding\")',\n    '    if [[ \"${#edit_args[@]}\" -eq 0 ]]; then',\n    \"      continue\",\n    \"    fi\",\n    '    if gh issue edit \"$num\" \"${edit_args[@]}\" >/dev/null 2>&1; then',\n    '      gh issue comment \"$num\" \\\\',\n    '        --body \"Label invariant: phase label(s) ${phase_labels} require ${type_label}. Corrected — added: ${adding:-(none)}; removed: ${removing:-(none)}.\" >/dev/null 2>&1 || true',\n    '      echo \"LABEL_CORRECTED #${num} added=\\\\\"${adding}\\\\\" removed=\\\\\"${removing}\\\\\"\"',\n    \"      corrected_count=$((corrected_count + 1))\",\n    \"    else\",\n    '      echo \"LABEL_CORRECT_FAILED #${num} — label edit failed\"',\n    \"    fi\",\n    '  done <<< \"$issue_data\"',\n    \"\",\n    \"  local violations_count=$((checked_count - ok_count))\",\n    '  echo \"LABEL_INVARIANT_DONE mode=${mode} checked=${checked_count} ok=${ok_count} violations=${violations_count} corrected=${corrected_count} flagged=${flagged_count}\"',\n    \"}\",\n    \"\",\n    \"cmd_scope() {\",\n    '  local issue_num=\"${1:-}\"',\n    '  if [[ -z \"$issue_num\" ]]; then',\n    '    echo \"Usage: check-blocked.sh scope <issue-number>\" >&2',\n    \"    return 2\",\n    \"  fi\",\n    '  if [[ \"$SCOPE_GATE_ENABLED\" != \"1\" ]]; then',\n    '    echo \"SCOPE #${issue_num} disabled\"',\n    \"    return 0\",\n    \"  fi\",\n    \"  # Fetch the body and labels in a single API call so we resolve\",\n    \"  # any per-phase-label override against the issue's actual labels.\",\n    \"  local issue_json\",\n    '  issue_json=$(gh issue view \"$issue_num\" --json body,labels 2>/dev/null || echo \"\")',\n    '  if [[ -z \"$issue_json\" ]]; then',\n    '    echo \"SCOPE #${issue_num} unknown — could not read issue body\"',\n    \"    return 1\",\n    \"  fi\",\n    \"  local body\",\n    \"  body=$(printf '%s' \\\"$issue_json\\\" | jq -r '.body // \\\"\\\"')\",\n    '  if [[ -z \"$body\" ]]; then',\n    '    echo \"SCOPE #${issue_num} unknown — could not read issue body\"',\n    \"    return 1\",\n    \"  fi\",\n    \"  local labels\",\n    \"  labels=$(printf '%s' \\\"$issue_json\\\" | jq -r '.labels[]?.name // empty')\",\n    \"  # Resolve the effective thresholds. `bundle_override_for` reads\",\n    \"  # labels on stdin and emits `KEY=VALUE` assignments (one per line)\",\n    \"  # for the four `_EFFECTIVE_*` variables plus `MATCHED_LABEL`.\",\n    \"  local override_output\",\n    \"  override_output=$(printf '%s\\\\n' \\\"$labels\\\" | bundle_override_for)\",\n    \"  local matched_label=''\",\n    \"  local _EFFECTIVE_AC_SMALL_MAX=$SCOPE_AC_SMALL_MAX\",\n    \"  local _EFFECTIVE_AC_MEDIUM_MAX=$SCOPE_AC_MEDIUM_MAX\",\n    \"  local _EFFECTIVE_SOURCES_SMALL_MAX=$SCOPE_SOURCES_SMALL_MAX\",\n    \"  local _EFFECTIVE_SOURCES_MEDIUM_MAX=$SCOPE_SOURCES_MEDIUM_MAX\",\n    \"  while IFS= read -r assignment; do\",\n    '    [ -z \"$assignment\" ] && continue',\n    '    case \"$assignment\" in',\n    \"      MATCHED_LABEL=*) matched_label=${assignment#MATCHED_LABEL=} ;;\",\n    \"      _EFFECTIVE_AC_SMALL_MAX=*) _EFFECTIVE_AC_SMALL_MAX=${assignment#_EFFECTIVE_AC_SMALL_MAX=} ;;\",\n    \"      _EFFECTIVE_AC_MEDIUM_MAX=*) _EFFECTIVE_AC_MEDIUM_MAX=${assignment#_EFFECTIVE_AC_MEDIUM_MAX=} ;;\",\n    \"      _EFFECTIVE_SOURCES_SMALL_MAX=*) _EFFECTIVE_SOURCES_SMALL_MAX=${assignment#_EFFECTIVE_SOURCES_SMALL_MAX=} ;;\",\n    \"      _EFFECTIVE_SOURCES_MEDIUM_MAX=*) _EFFECTIVE_SOURCES_MEDIUM_MAX=${assignment#_EFFECTIVE_SOURCES_MEDIUM_MAX=} ;;\",\n    \"    esac\",\n    '  done <<<\"$override_output\"',\n    \"  # Export the effective thresholds so scope_of() picks them up.\",\n    \"  export _EFFECTIVE_AC_SMALL_MAX _EFFECTIVE_AC_MEDIUM_MAX\",\n    \"  export _EFFECTIVE_SOURCES_SMALL_MAX _EFFECTIVE_SOURCES_MEDIUM_MAX\",\n    \"  local scope counts\",\n    \"  # scope_of writes counts to stderr (ac=N sources=N); capture both.\",\n    '  scope=$(printf \\'%s\\' \"$body\" | scope_of 2> >(read -r counts; echo \"$counts\" >&2))',\n    \"  # Re-run to capture counts deterministically (stderr redirection in\",\n    \"  # subshells is fiddly across bash versions; this is the simplest\",\n    \"  # portable path).\",\n    \"  local stderr_capture\",\n    \"  stderr_capture=$(printf '%s' \\\"$body\\\" | scope_of 2>&1 >/dev/null || true)\",\n    \"  local ac_count sources_count\",\n    \"  ac_count=$(echo \\\"$stderr_capture\\\" | grep -oE 'ac=[0-9]+' | head -1 | cut -d= -f2)\",\n    \"  sources_count=$(echo \\\"$stderr_capture\\\" | grep -oE 'sources=[0-9]+' | head -1 | cut -d= -f2)\",\n    \"  ac_count=${ac_count:-0}\",\n    \"  sources_count=${sources_count:-0}\",\n    '  if [ -n \"$matched_label\" ]; then',\n    \"    printf 'SCOPE #%s %s ac=%s sources=%s ac_limit=%s sources_limit=%s auto_file=%s matched_label=%s\\\\n' \\\\\",\n    '      \"$issue_num\" \"$scope\" \"$ac_count\" \"$sources_count\" \\\\',\n    '      \"$_EFFECTIVE_AC_MEDIUM_MAX\" \"$_EFFECTIVE_SOURCES_MEDIUM_MAX\" \\\\',\n    '      \"$SCOPE_GATE_AUTO_FILE\" \"$matched_label\"',\n    \"  else\",\n    \"    printf 'SCOPE #%s %s ac=%s sources=%s ac_limit=%s sources_limit=%s auto_file=%s\\\\n' \\\\\",\n    '      \"$issue_num\" \"$scope\" \"$ac_count\" \"$sources_count\" \\\\',\n    '      \"$_EFFECTIVE_AC_MEDIUM_MAX\" \"$_EFFECTIVE_SOURCES_MEDIUM_MAX\" \\\\',\n    '      \"$SCOPE_GATE_AUTO_FILE\"',\n    \"  fi\",\n    \"}\",\n    \"\",\n    \"# ── main ─────────────────────────────────────────────────────────────\",\n    \"\",\n    'case \"${1:-help}\" in',\n    '  unblock)     shift; cmd_unblock \"$@\" ;;',\n    '  eligible)    shift; cmd_eligible \"$@\" ;;',\n    '  stale)       shift; cmd_stale \"$@\" ;;',\n    '  orphaned)    shift; cmd_orphaned \"$@\" ;;',\n    '  lease-reconcile) shift; cmd_lease_reconcile \"$@\" ;;',\n    '  maintenance) shift; cmd_maintenance \"$@\" ;;',\n    '  prs)         shift; cmd_prs \"$@\" ;;',\n    '  scope)       shift; cmd_scope \"$@\" ;;',\n    '  label-invariant) shift; cmd_label_invariant \"$@\" ;;',\n    \"  help|*)\",\n    '    echo \"Usage: check-blocked.sh <unblock|eligible|stale|orphaned|lease-reconcile|maintenance|prs|scope|label-invariant>\"',\n    \"    exit 1\",\n    \"    ;;\",\n    \"esac\",\n  ].join(\"\\n\");\n}\n\n/**\n * Build the check-blocked.sh procedure definition for a given resolved\n * tier table and scope gate. `AgentConfig.preSynthesize` calls this\n * with the consumer's resolved configs so the emitted script's\n * `tier_of()` lookup and `scope_of()` thresholds match whatever the\n * rendered orchestrator-conventions rule documents.\n *\n * Scope-gate settings default to the bundle's built-in defaults\n * (small: ≤3 AC + ≤2 sources; medium: ≤6 AC + ≤5 sources;\n * auto-file off) when the caller omits them.\n *\n * The `runRatio` parameter is retained for API compatibility but is no\n * longer rendered into the script — the orchestrator runs a single\n * linear cycle on every invocation, so the run counter / tick\n * subcommand were retired.\n */\nexport function buildCheckBlockedProcedure(\n  tiers: ReadonlyArray<ResolvedAgentTier>,\n  scopeGate: ResolvedScopeGate = resolveScopeGate(),\n  runRatio: ResolvedRunRatio = resolveRunRatio(),\n): AgentProcedure {\n  return {\n    name: \"check-blocked.sh\",\n    description:\n      \"Token-efficient issue triage script with subcommands: eligible, unblock, stale, orphaned, lease-reconcile, maintenance, prs, scope, label-invariant. Sorts eligible issues by priority desc → funnel tier asc → issue number asc, excluding issues carrying `status:needs-attention` or `status:deferred`; the scope subcommand classifies a single issue against the scope-gate thresholds; the unblock subcommand applies the `status:blocked` → `status:ready` label flip itself, posts the canned unblock comment, skips human-parked `status:deferred` candidates with a `SKIP_DEFERRED` line, and emits a single `TRIAGE_DONE unblocked=N still_blocked=M deferred_skipped=K` summary line; the lease-reconcile subcommand auto-reconciles stuck `review:fixing` PR leases — re-applying `review:needs-worker` on an orphaned lease (fix-list stale, no worker report) so the Phase B1 drain retries, and removing `review:needs-worker` on a consumed-but-uncleared wedge (branch HEAD advanced past the fix-list, marker still set, no worker report) so the reviewer confirm pass can merge, always posting an audit-trail note comment and emitting a single `LEASE_RECONCILE orphaned=N consumed_uncleared=M` summary line; the maintenance subcommand flags stale issues with `status:needs-attention` (never auto-resets to `status:ready`), counts orphan branches/PRs, folds in the lease-reconcile sweep and the label-invariant auto-correction, and emits a `MAINTENANCE_DONE flagged_stale=N flagged_blocked=M orphan_branches=A orphan_prs=B needs_attention_total=T` summary line followed by the `LEASE_RECONCILE` and `LABEL_INVARIANT_DONE` lines; the label-invariant subcommand enforces the phase-label → `type:<bundle>` pairing derived from the canonical `BUNDLE_OWNERSHIP` map — report-only by default, auto-correcting with `--fix` (replacing a shadowing conventional-commit `type:*` rather than merely adding, so the issue keeps exactly one `type:*`) and flagging `status:needs-attention` when the pairing is ambiguous or collides with another bundle's type label, emitting a single `LABEL_INVARIANT_DONE mode=M checked=N ok=O violations=V corrected=C flagged=F` summary line.\",\n    content: buildCheckBlockedScript(tiers, scopeGate, runRatio),\n  };\n}\n\nconst checkBlockedProcedure = buildCheckBlockedProcedure(\n  DEFAULT_AGENT_TIERS,\n  resolveScopeGate(),\n  resolveRunRatio(),\n);\n\n/*******************************************************************************\n *\n * unblock-dependents.sh — Targeted post-close dependency sweep.\n *\n * Called by every agent that applies `status:done` to an issue. The\n * script searches open issues for `Depends on: #<just-closed>` and\n * flips fully-resolved dependents from `status:blocked` to\n * `status:ready`.\n *\n * `buildUnblockDependentsProcedure()` is the factory that parameterises\n * the rendered script with a resolved `ResolvedUnblockDependents`;\n * `unblockDependentsProcedure` (declared below) is the default\n * instance that ships when the consumer supplies no override.\n *\n ******************************************************************************/\n\nexport function buildUnblockDependentsProcedure(\n  unblockDependents: ResolvedUnblockDependents = resolveUnblockDependents(),\n): AgentProcedure {\n  return {\n    name: \"unblock-dependents.sh\",\n    description:\n      \"Targeted dependency sweep called after an issue closes. Given a just-closed issue number, scans open `status:blocked` issues for `Depends on: #<n>` references and flips fully-resolved dependents to `status:ready` with a citation comment. Idempotent.\",\n    content: renderUnblockDependentsScript(unblockDependents),\n  };\n}\n\nconst unblockDependentsProcedure = buildUnblockDependentsProcedure(\n  resolveUnblockDependents(),\n);\n\n/*******************************************************************************\n *\n * pr-sweep.sh — PR enumeration for the orchestrator's PR phases.\n *\n * Two modes, selected by the first positional argument:\n *\n * `review` (default) — Phase B PR-eligibility filter. The orchestrator\n * shells out to decide which open PRs the `pr-reviewer` sub-agent\n * should be invoked against. The script does **not** enable\n * auto-merge, apply labels, or otherwise mutate PR state — it only\n * emits one `PR_ELIGIBLE` / `PR_SKIP` line per open PR so the\n * orchestrator never iterates raw `gh pr list` JSON in-context.\n *\n * Review-mode skip rules (do not dispatch the reviewer):\n *\n * - `isDraft: true` → `reason=draft`\n * - Carries `review:human-required` label → `reason=human-required`\n * - Carries `review:awaiting-human` label → `reason=awaiting-human`\n * - Newest `## Reviewer*` comment younger than the review-in-flight\n *   window → `reason=review-in-flight`. Fleet anti-collision\n *   (codedrifters/packages#868): a sibling runner's reviewer is already\n *   looking at the PR this cycle, so a second dispatch is redundant.\n *   The age is measured from the newest reviewer comment's `updatedAt`\n *   (falling back to `createdAt`) so an in-place sticky-note edit counts\n *   as fresh activity, computed entirely in jq (`now - fromdateiso8601`)\n *   for portability.\n *\n * Review-mode output (one line per open PR, in PR-number order):\n *\n *   PR_ELIGIBLE #123\n *   PR_SKIP #124 reason=draft\n *   PR_SKIP #125 reason=human-required\n *   PR_SKIP #126 reason=awaiting-human\n *   PR_SKIP #127 reason=review-in-flight\n *\n * When there are zero open PRs, review mode emits a single\n * `NO_OPEN_PRS` line and exits 0.\n *\n * `needs-worker` — Phase B1 feedback-drain enumeration. Lists every\n * open PR carrying the durable `review:needs-worker` marker and drains\n * it — dispatching a top-level `issue-worker` per PR to consume the\n * reviewer's fix-list — ordered highest-priority-first (linked-issue\n * `priority:*`, tie-broken by PR number ascending).\n *\n * A PR carrying `review:needs-worker` but NOT `review:fixing` is an idle\n * marker (no worker dispatched) and always drains. A PR that ALSO carries\n * the `review:fixing` lease drains UNLESS a worker is *demonstrably\n * active* — judged by the shared `delegation_active_signals` helper (the\n * SAME fix-list / worker-report / branch-HEAD signals cmd_lease_reconcile\n * applies), so the two never diverge:\n *\n * - no reviewer fix-list comment           → `PR_SKIP reason=no-fixlist`\n * - worker-report newer than the fix-list  → `PR_SKIP reason=reported`\n * - branch HEAD newer than the fix-list    → `PR_SKIP reason=in-flight`\n * - otherwise (delegated but idle)         → **DRAIN**\n *\n * The bare presence of `review:fixing` no longer skips: the reviewer\n * acquires the lease and applies the marker atomically in one pass, then\n * holds the lease across sessions, so a lease with no worker activity yet\n * is a delegated-but-idle PR whose FIRST worker must be dispatched.\n * Skipping it on the bare lease wedged the PR forever (the deadlock this\n * mode's predicate fixes).\n *\n * Needs-worker-mode output (skip lines in PR-number order, then drain\n * lines in priority order):\n *\n *   PR_SKIP #124 reason=in-flight\n *   PR_DRAIN #58\n *   PR_DRAIN #42\n *\n * When no open PR carries the marker (or every marked PR is\n * demonstrably-active with no drain candidate), needs-worker mode emits a\n * single `NO_NEEDS_WORKER_PRS` line and exits 0.\n *\n ******************************************************************************/\n\nfunction buildPrSweepScript(): string {\n  return [\n    \"#!/usr/bin/env bash\",\n    \"# pr-sweep.sh — Token-efficient PR enumeration for the orchestrator's\",\n    \"# PR-handling phases. Two modes:\",\n    \"#\",\n    \"#   review       (default) — Phase B PR review sweep. Emits one\",\n    \"#                 PR_ELIGIBLE / PR_SKIP line per open PR; the\",\n    \"#                 orchestrator dispatches `pr-reviewer` per eligible PR.\",\n    \"#   needs-worker — Phase B1 feedback-drain. Emits one DRAIN line per\",\n    \"#                 open PR carrying the `review:needs-worker` marker,\",\n    \"#                 ordered highest-priority-first so the orchestrator\",\n    \"#                 dispatches `issue-worker` per PR to consume the\",\n    \"#                 reviewer's fix-list. A PR that also holds the\",\n    \"#                 `review:fixing` lease still drains unless a worker is\",\n    \"#                 demonstrably active (see the needs-worker skip rules).\",\n    \"#\",\n    \"# Review-mode skip rules:\",\n    \"#   - isDraft = true                          → reason=draft\",\n    \"#   - review:human-required label             → reason=human-required\",\n    \"#   - review:awaiting-human label             → reason=awaiting-human\",\n    \"#   - newest ## Reviewer* comment younger than the review-in-flight\",\n    \"#     window (a sibling runner's review is already in flight this\",\n    \"#     cycle)                                   → reason=review-in-flight\",\n    \"#\",\n    \"# Needs-worker-mode skip rules (PR carries review:needs-worker but is\",\n    \"# not eligible to drain this cycle). A PR with NO review:fixing lease\",\n    \"# always drains — an idle marker means no worker has been dispatched.\",\n    \"# A PR that ALSO carries review:fixing drains UNLESS a worker is\",\n    \"# demonstrably active, judged by the SAME signals the lease-reconcile\",\n    \"# uses (fix-list / worker-report / branch-HEAD timestamps):\",\n    \"#   - no reviewer fix-list comment              → reason=no-fixlist\",\n    \"#     (nothing to drain — e.g. a hand-applied lease; be conservative)\",\n    \"#   - worker-report newer than the fix-list     → reason=reported\",\n    \"#     (a worker result already landed — the reviewer confirm pass owns it)\",\n    \"#   - branch HEAD newer than the fix-list       → reason=in-flight\",\n    \"#     (a worker pushed — actively fixing / consumed-uncleared; the\",\n    \"#      lease-reconcile owns it)\",\n    \"#   - otherwise (delegated but idle, no worker has touched it) → DRAIN.\",\n    \"#     This is the deadlock fix: the FIRST worker of a delegation is\",\n    \"#     dispatched instead of being skipped forever on the bare lease.\",\n    \"#\",\n    \"# Usage:\",\n    \"#   .claude/procedures/pr-sweep.sh [review|needs-worker]\",\n    \"\",\n    \"set -uo pipefail\",\n    \"\",\n    \"# Review-in-flight window in seconds — a PR whose newest reviewer\",\n    \"# comment is younger than this is treated as under active review by a\",\n    \"# sibling runner (fleet anti-collision).\",\n    `REVIEW_IN_FLIGHT_WINDOW_SECONDS=${REVIEW_IN_FLIGHT_WINDOW_MINUTES * 60}`,\n    \"\",\n    \"# ── helpers ──────────────────────────────────────────────────────────\",\n    \"\",\n    \"# Resolve the linked issue's priority for a PR so the needs-worker\",\n    \"# drain can order highest-priority-first. Echoes a single sort key\",\n    \"# 0-5 (0 = critical … 4 = trivial, 5 = no/unknown priority) so an\",\n    \"# unprioritised PR always sorts last but is never dropped.\",\n    \"priority_key_for_pr() {\",\n    '  local pr_num=\"$1\"',\n    \"  local issue_num\",\n    '  issue_num=$(gh pr view \"$pr_num\" --json body \\\\',\n    '    --jq \\'(.body | capture(\"(?:Closes|Fixes|Resolves) #(?<num>[0-9]+)\") | .num) // \"\"\\' \\\\',\n    '    2>/dev/null || echo \"\")',\n    '  if [[ -z \"$issue_num\" ]]; then',\n    '    echo \"5\"',\n    \"    return\",\n    \"  fi\",\n    \"  local labels\",\n    '  labels=$(gh issue view \"$issue_num\" --json labels \\\\',\n    \"    --jq '.labels[].name' 2>/dev/null || echo \\\"\\\")\",\n    '  case \"$labels\" in',\n    '    *priority:critical*) echo \"0\" ;;',\n    '    *priority:high*)     echo \"1\" ;;',\n    '    *priority:medium*)   echo \"2\" ;;',\n    '    *priority:low*)      echo \"3\" ;;',\n    '    *priority:trivial*)  echo \"4\" ;;',\n    '    *)                   echo \"5\" ;;',\n    \"  esac\",\n    \"}\",\n    \"\",\n    \"# Fleet anti-collision: echo the age in\",\n    \"# whole seconds of a PR's newest `## Reviewer*` comment, or `none` when\",\n    \"# the PR has no reviewer comment yet (or the read fails). The age is\",\n    \"# derived from the newest reviewer comment's `updatedAt` (fall back to\",\n    \"# `createdAt`) so an in-place edit of the sticky `## Reviewer notes`\",\n    \"# comment counts as fresh activity, and it is computed inside jq\",\n    \"# (`now - fromdateiso8601`, clamped at 0) so no non-portable `date`\",\n    \"# parsing is needed. The raw JSON is piped through the caller's jq (not\",\n    \"# gh's `--jq`), mirroring cmd_review's `gh pr list` handling.\",\n    \"newest_reviewer_comment_age_seconds() {\",\n    '  local pr_num=\"$1\"',\n    \"  local json\",\n    '  json=$(gh pr view \"$pr_num\" --json comments 2>/dev/null) || { echo \"none\"; return; }',\n    '  [[ -z \"$json\" ]] && { echo \"none\"; return; }',\n    '  echo \"$json\" | jq -r \\'',\n    \"    [ .comments[]?\",\n    '      | select(.body | startswith(\"## Reviewer\"))',\n    \"      | (.updatedAt // .createdAt)\",\n    \"      | fromdateiso8601\",\n    \"    ] as $ts\",\n    '    | if ($ts | length) == 0 then \"none\"',\n    \"      else ((now - ($ts | max)) | floor | if . < 0 then 0 else . end) end\",\n    '  \\' 2>/dev/null || echo \"none\"',\n    \"}\",\n    \"\",\n    ...renderDelegationActiveSignalsHelper(),\n    \"\",\n    \"# ── modes ────────────────────────────────────────────────────────────\",\n    \"\",\n    \"cmd_review() {\",\n    \"  local prs\",\n    \"  prs=$(gh pr list --state open --json number,isDraft,labels \\\\\",\n    '    --limit 50 2>/dev/null || echo \"[]\")',\n    \"\",\n    \"  local count\",\n    \"  count=$(echo \\\"$prs\\\" | jq 'length')\",\n    '  if [[ \"$count\" -eq 0 ]]; then',\n    '    echo \"NO_OPEN_PRS\"',\n    \"    return 0\",\n    \"  fi\",\n    \"\",\n    \"  # First pass (jq, no per-PR reads): classify each PR from the labels\",\n    \"  # and draft flag already in the list JSON, sorted by PR number\",\n    \"  # ascending so the output order is deterministic across runs. A PR\",\n    \"  # that clears every cheap label/draft skip rule is a CANDIDATE — the\",\n    \"  # review-in-flight check (which needs a per-PR comment read) is\",\n    \"  # applied per-candidate in the loop below. Emit `kind\\\\tnumber\\\\treason`.\",\n    \"  local rows\",\n    '  rows=$(echo \"$prs\" | jq -r \\'',\n    \"    sort_by(.number) |\",\n    \"    .[] |\",\n    \"    (.labels | map(.name)) as $labels |\",\n    \"    if .isDraft then\",\n    '      \"SKIP\\\\t\\\\(.number)\\\\tdraft\"',\n    '    elif ($labels | index(\"review:human-required\")) then',\n    '      \"SKIP\\\\t\\\\(.number)\\\\thuman-required\"',\n    '    elif ($labels | index(\"review:awaiting-human\")) then',\n    '      \"SKIP\\\\t\\\\(.number)\\\\tawaiting-human\"',\n    \"    else\",\n    '      \"CANDIDATE\\\\t\\\\(.number)\\\\t\"',\n    \"    end\",\n    \"  ')\",\n    \"\",\n    \"  while IFS=$'\\\\t' read -r kind pr_num reason; do\",\n    '    [[ -z \"$pr_num\" ]] && continue',\n    '    if [[ \"$kind\" == \"SKIP\" ]]; then',\n    '      echo \"PR_SKIP #${pr_num} reason=${reason}\"',\n    \"      continue\",\n    \"    fi\",\n    \"    # CANDIDATE — dispatch the reviewer UNLESS a sibling runner's review\",\n    \"    # is already in flight, i.e. the newest `## Reviewer*` comment is\",\n    \"    # younger than the review-in-flight window (fleet anti-collision).\",\n    \"    local age\",\n    '    age=$(newest_reviewer_comment_age_seconds \"$pr_num\")',\n    \"    # `age` is `none` (no reviewer comment / read failed) or a\",\n    \"    # non-negative integer; only a numeric age inside the window skips.\",\n    '    if [[ \"$age\" =~ ^[0-9]+$ && \"$age\" -lt \"$REVIEW_IN_FLIGHT_WINDOW_SECONDS\" ]]; then',\n    '      echo \"PR_SKIP #${pr_num} reason=review-in-flight\"',\n    \"    else\",\n    '      echo \"PR_ELIGIBLE #${pr_num}\"',\n    \"    fi\",\n    '  done <<< \"$rows\"',\n    \"}\",\n    \"\",\n    \"cmd_needs_worker() {\",\n    \"  # Phase B1 feedback-drain: enumerate open PRs carrying the durable\",\n    \"  # `review:needs-worker` marker and dispatch `issue-worker` per PR to\",\n    \"  # consume the reviewer's fix-list, ordered highest-priority-first.\",\n    \"  #\",\n    \"  # A PR without the `review:fixing` lease is an idle marker — no worker\",\n    \"  # has been dispatched — so it DRAINs directly. A PR that ALSO carries\",\n    \"  # `review:fixing` is a delegation; it DRAINs UNLESS a worker is\",\n    \"  # demonstrably active, judged by the shared `delegation_active_signals`\",\n    \"  # helper (the SAME signals cmd_lease_reconcile uses). Crucially, the\",\n    \"  # bare presence of `review:fixing` no longer skips: the reviewer\",\n    \"  # acquires the lease and applies the marker in ONE atomic pass and\",\n    \"  # then holds the lease across sessions, so a lease with no worker\",\n    \"  # activity yet is a delegated-but-idle PR whose FIRST worker must be\",\n    \"  # dispatched — skipping it on the bare lease wedged the PR forever.\",\n    \"  local prs\",\n    \"  prs=$(gh pr list --state open --label 'review:needs-worker' \\\\\",\n    '    --json number,labels,headRefOid --limit 50 2>/dev/null || echo \"[]\")',\n    \"\",\n    \"  local count\",\n    \"  count=$(echo \\\"$prs\\\" | jq 'length')\",\n    '  if [[ \"$count\" -eq 0 ]]; then',\n    '    echo \"NO_NEEDS_WORKER_PRS\"',\n    \"    return 0\",\n    \"  fi\",\n    \"\",\n    \"  # First pass: classify each PR. A PR with no `review:fixing` lease is\",\n    \"  # an idle marker → DRAIN directly (head-oid unused). A PR that also\",\n    \"  # carries `review:fixing` is a CANDIDATE — the demonstrably-active\",\n    \"  # predicate is applied per-PR in the loop below (it needs comment /\",\n    \"  # commit reads, so it cannot live in jq). Emit `kind\\\\tnumber\\\\thead`.\",\n    \"  local candidates\",\n    '  candidates=$(echo \"$prs\" | jq -r \\'',\n    \"    sort_by(.number) |\",\n    \"    .[] |\",\n    \"    (.labels | map(.name)) as $labels |\",\n    '    if ($labels | index(\"review:fixing\")) then',\n    '      \"CANDIDATE\\\\t\\\\(.number)\\\\t\\\\(.headRefOid)\"',\n    \"    else\",\n    '      \"DRAIN\\\\t\\\\(.number)\\\\t\"',\n    \"    end\",\n    \"  ')\",\n    \"\",\n    '  local drain_rows=\"\"',\n    '  local emitted_any=\"\"',\n    \"  while IFS=$'\\\\t' read -r kind pr_num head_oid; do\",\n    '    [[ -z \"$pr_num\" ]] && continue',\n    \"\",\n    '    if [[ \"$kind\" == \"CANDIDATE\" ]]; then',\n    \"      # `review:fixing` present — drain UNLESS a worker is demonstrably\",\n    \"      # active. Mirror cmd_lease_reconcile's skip conditions exactly so\",\n    \"      # the drain and the reconcile never diverge on what 'active' means.\",\n    \"      local signals fixlist_at report_at head_at\",\n    '      signals=$(delegation_active_signals \"$pr_num\" \"$head_oid\")',\n    \"      IFS=$'\\\\x1f' read -r fixlist_at report_at head_at <<< \\\"$signals\\\"\",\n    \"\",\n    '      if [[ -z \"$fixlist_at\" ]]; then',\n    \"        # No reviewer fix-list (e.g. a hand-applied lease). Nothing to\",\n    \"        # drain — be conservative and leave it for a human / reconcile.\",\n    '        echo \"PR_SKIP #${pr_num} reason=no-fixlist\"',\n    '        emitted_any=\"1\"',\n    \"        continue\",\n    \"      fi\",\n    '      if [[ -n \"$report_at\" && \"$report_at\" > \"$fixlist_at\" ]]; then',\n    \"        # A worker result already landed — the reviewer confirm pass\",\n    \"        # owns this PR now, not the drain.\",\n    '        echo \"PR_SKIP #${pr_num} reason=reported\"',\n    '        emitted_any=\"1\"',\n    \"        continue\",\n    \"      fi\",\n    '      if [[ -n \"$head_at\" && \"$head_at\" > \"$fixlist_at\" ]]; then',\n    \"        # Branch advanced past the fix-list → a worker pushed. Actively\",\n    \"        # fixing (or consumed-uncleared); the lease-reconcile owns it.\",\n    '        echo \"PR_SKIP #${pr_num} reason=in-flight\"',\n    '        emitted_any=\"1\"',\n    \"        continue\",\n    \"      fi\",\n    \"      # else: delegated but idle — no worker has touched it. Fall\",\n    \"      # through to DRAIN. THIS is the deadlock fix.\",\n    \"    fi\",\n    \"\",\n    \"    # DRAIN (idle marker, or a delegated-but-idle candidate that fell\",\n    \"    # through) — resolve the linked issue's priority so the drain order\",\n    \"    # is highest-priority-first, tie-broken by PR number ascending\",\n    \"    # (FIFO, mirroring the queue scan's number-asc tie-break).\",\n    \"    local pkey\",\n    '    pkey=$(priority_key_for_pr \"$pr_num\")',\n    '    drain_rows=\"${drain_rows}${pkey}\\\\t${pr_num}\\\\n\"',\n    '  done <<< \"$candidates\"',\n    \"\",\n    '  if [[ -n \"$drain_rows\" ]]; then',\n    \"    # Sort by priority key asc → PR number asc, then emit one\",\n    \"    # PR_DRAIN line per PR in that order.\",\n    \"    printf '%b' \\\"$drain_rows\\\" \\\\\",\n    \"      | sort -t$'\\\\t' -k1,1n -k2,2n \\\\\",\n    \"      | while IFS=$'\\\\t' read -r _pkey pr_num; do\",\n    '          [[ -z \"$pr_num\" ]] && continue',\n    '          echo \"PR_DRAIN #${pr_num}\"',\n    \"        done\",\n    '    emitted_any=\"1\"',\n    \"  fi\",\n    \"\",\n    '  if [[ -z \"$emitted_any\" ]]; then',\n    '    echo \"NO_NEEDS_WORKER_PRS\"',\n    \"  fi\",\n    \"}\",\n    \"\",\n    \"# ── main ─────────────────────────────────────────────────────────────\",\n    \"\",\n    'case \"${1:-review}\" in',\n    '  review)       shift || true; cmd_review \"$@\" ;;',\n    '  needs-worker) shift || true; cmd_needs_worker \"$@\" ;;',\n    \"  *)\",\n    '    echo \"Usage: pr-sweep.sh <review|needs-worker>\" >&2',\n    \"    exit 1\",\n    \"    ;;\",\n    \"esac\",\n  ].join(\"\\n\");\n}\n\n/**\n * Build the pr-sweep.sh procedure definition. The script's skip rules\n * are hard-coded to the labels documented in the bundle; the factory\n * exists so a future config can parameterise additional skip labels\n * without changing the call sites. Two modes are exposed via the first\n * positional argument: `review` (default, Phase B eligibility) and\n * `needs-worker` (Phase B1 feedback-drain enumeration).\n */\nexport function buildPrSweepProcedure(): AgentProcedure {\n  return {\n    name: \"pr-sweep.sh\",\n    description:\n      \"Token-efficient PR enumeration for the orchestrator. In `review` mode (default) it emits one `PR_ELIGIBLE #<n>` or `PR_SKIP #<n> reason=<draft|human-required|awaiting-human|review-in-flight>` line per open PR so the orchestrator dispatches `pr-reviewer` per eligible PR. `review-in-flight` skips a PR whose newest `## Reviewer*` comment is younger than the fleet review-in-flight window, so overlapping runners do not both dispatch a reviewer on the same PR. In `needs-worker` mode it lists open PRs carrying the `review:needs-worker` marker and drains them, emitting `PR_DRAIN #<n>` lines ordered highest-priority-first so the orchestrator dispatches `issue-worker` per PR. A PR without the `review:fixing` lease is an idle marker and always drains; a PR that also holds `review:fixing` drains UNLESS a worker is demonstrably active (judged by the shared `delegation_active_signals` helper cmd_lease_reconcile also uses) — skipping as `reason=no-fixlist` / `reason=reported` / `reason=in-flight`. `NO_NEEDS_WORKER_PRS` when none.\",\n    content: buildPrSweepScript(),\n  };\n}\n\nconst prSweepProcedure = buildPrSweepProcedure();\n\n/*******************************************************************************\n *\n * complete-feedback-handoff.sh — Atomic feedback-mode hand-off completion.\n *\n * Called by the `issue-worker` in Phase 6.5 as the FIRST action after a\n * successful feedback-mode push. It performs the two-part hand-off in a\n * SINGLE invocation so a clean push can never land without the hand-off\n * completing:\n *\n *   1. Posts the structured `## Worker report` comment on the PR (the\n *      record the reviewer's confirm pass reads to react on source\n *      comments and re-evaluate AC / CI).\n *   2. Removes the durable `review:needs-worker` marker (leaving the\n *      `review:fixing` lease for the reviewer's confirm pass).\n *\n * The script exits NON-ZERO if either the comment post or the label\n * removal fails, so the worker treats the unit of work as incomplete and\n * retries rather than stopping after a partial hand-off. A partial result\n * (some fix-list items `failed`) is reported per-item and STILL clears the\n * marker — a partial outcome must not wedge the PR.\n *\n * Usage:\n *   complete-feedback-handoff.sh <pr-number> <commit-sha> <items-json>\n *\n * `<items-json>` is a JSON array of per-item outcomes keyed by the\n * fix-list `comment_id`, each `{\"comment_id\",\"outcome\",\"detail\"}` where\n * `outcome` is `applied` or `failed`. It is rendered into the worker\n * report so the reviewer can react on the correct source comment.\n *\n ******************************************************************************/\n\nfunction buildCompleteFeedbackHandoffScript(): string {\n  return [\n    \"#!/usr/bin/env bash\",\n    \"# complete-feedback-handoff.sh — Atomic feedback-mode hand-off for the\",\n    \"# issue-worker (Phase 6.5). Posts the structured worker-report comment\",\n    \"# AND removes the `review:needs-worker` marker in ONE invocation,\",\n    \"# exiting non-zero on any failure so a successful push can never land\",\n    \"# without the hand-off completing.\",\n    \"#\",\n    \"# The marker is cleared even when some (or all) fix-list items failed —\",\n    \"# a partial result is reported per-item but must not wedge the PR. The\",\n    \"# `review:fixing` lease is left in place for the reviewer's confirm pass.\",\n    \"#\",\n    \"# Usage:\",\n    \"#   complete-feedback-handoff.sh <pr-number> <commit-sha> <items-json>\",\n    \"#\",\n    \"#   <items-json> — JSON array of per-item outcomes keyed by the\",\n    \"#     fix-list `comment_id`:\",\n    '#       [{\"comment_id\":\"IC_abc\",\"outcome\":\"applied\",\"detail\":\"\"},',\n    '#        {\"comment_id\":\"IC_def\",\"outcome\":\"failed\",\"detail\":\"reason\"}]',\n    \"#     `outcome` is `applied` or `failed`.\",\n    \"\",\n    \"set -uo pipefail\",\n    \"\",\n    'pr_number=\"${1:-}\"',\n    'commit_sha=\"${2:-}\"',\n    'items_json=\"${3:-}\"',\n    \"\",\n    'if [[ -z \"$pr_number\" || -z \"$commit_sha\" || -z \"$items_json\" ]]; then',\n    '  echo \"Usage: complete-feedback-handoff.sh <pr-number> <commit-sha> <items-json>\" >&2',\n    \"  exit 2\",\n    \"fi\",\n    \"\",\n    \"# Validate the items JSON up front — a malformed payload must fail\",\n    \"# loudly before we mutate any PR state.\",\n    'if ! echo \"$items_json\" | jq -e \\'type == \"array\"\\' >/dev/null 2>&1; then',\n    '  echo \"complete-feedback-handoff: <items-json> is not a JSON array\" >&2',\n    \"  exit 2\",\n    \"fi\",\n    \"\",\n    \"# ── Build the structured worker report ───────────────────────────────\",\n    \"# One markdown checklist line per item (✓ applied / ✗ failed), keyed by\",\n    \"# comment_id so the reviewer's confirm pass reacts on the right source\",\n    \"# comment. Includes the pushed commit SHA and an overall outcome\",\n    \"# (`complete` when every item applied, `partial` when any failed).\",\n    'applied_count=$(echo \"$items_json\" | jq \\'[.[] | select(.outcome == \"applied\")] | length\\')',\n    'failed_count=$(echo \"$items_json\" | jq \\'[.[] | select(.outcome == \"failed\")] | length\\')',\n    \"\",\n    'overall=\"complete\"',\n    'if [[ \"$failed_count\" -gt 0 ]]; then',\n    '  overall=\"partial\"',\n    \"fi\",\n    \"\",\n    'item_lines=$(echo \"$items_json\" | jq -r \\'',\n    \"  .[] |\",\n    '  if .outcome == \"applied\" then',\n    '    \"- [x] `\\\\(.comment_id)` — applied\"',\n    \"  else\",\n    '    \"- [ ] `\\\\(.comment_id)` — **failed**\" + (if (.detail // \"\") != \"\" then \" (\\\\(.detail))\" else \"\" end)',\n    \"  end\",\n    \"')\",\n    \"\",\n    \"report=$(cat <<EOF\",\n    \"## Worker report\",\n    \"\",\n    \"Feedback-mode fix-list applied on commit \\\\`${commit_sha}\\\\`.\",\n    \"\",\n    \"**Outcome:** ${overall} (${applied_count} applied, ${failed_count} failed)\",\n    \"\",\n    \"${item_lines}\",\n    \"\",\n    \"<!-- issue-worker feedback hand-off — review:needs-worker cleared -->\",\n    \"EOF\",\n    \")\",\n    \"\",\n    \"# ── 1. Post the worker-report comment ────────────────────────────────\",\n    \"# The report is ALWAYS posted, even when every item failed — the\",\n    \"# reviewer's confirm pass needs the record to react and fall through to\",\n    \"# the human-required hand-off rather than silently wedging.\",\n    'if ! echo \"$report\" | gh pr comment \"$pr_number\" --body-file -; then',\n    '  echo \"complete-feedback-handoff: failed to post worker-report comment on PR #${pr_number}\" >&2',\n    \"  exit 1\",\n    \"fi\",\n    \"\",\n    \"# ── 2. Clear the durable review:needs-worker marker ──────────────────\",\n    \"# Removing the marker (not the `review:fixing` lease) flips the PR into\",\n    \"# the lease-without-marker state the reviewer's confirm pass keys on.\",\n    \"# Cleared unconditionally on a partial result so the PR never wedges.\",\n    \"if ! gh pr edit \\\"$pr_number\\\" --remove-label 'review:needs-worker'; then\",\n    '  echo \"complete-feedback-handoff: failed to remove review:needs-worker from PR #${pr_number}\" >&2',\n    \"  exit 1\",\n    \"fi\",\n    \"\",\n    'echo \"HANDOFF_DONE pr=#${pr_number} outcome=${overall} applied=${applied_count} failed=${failed_count}\"',\n  ].join(\"\\n\");\n}\n\n/**\n * Build the complete-feedback-handoff.sh procedure definition. The\n * issue-worker calls it in Phase 6.5 as the first post-push action so the\n * worker-report comment and the `review:needs-worker` marker removal\n * happen atomically — a successful push can never land with the marker\n * still set and no report posted.\n */\nexport function buildCompleteFeedbackHandoffProcedure(): AgentProcedure {\n  return {\n    name: \"complete-feedback-handoff.sh\",\n    description:\n      \"Atomic feedback-mode hand-off for the issue-worker (Phase 6.5). Given `<pr-number> <commit-sha> <items-json>`, it posts the structured `## Worker report` comment (per-item outcomes keyed by fix-list `comment_id`, `applied` / `failed`) AND removes the `review:needs-worker` marker in one invocation, exiting non-zero on any failure so a clean push can never land without the hand-off completing. The marker is cleared even when some or all items failed (overall outcome `partial`) so a partial result never wedges the PR; the `review:fixing` lease is left for the reviewer's confirm pass.\",\n    content: buildCompleteFeedbackHandoffScript(),\n  };\n}\n\nconst completeFeedbackHandoffProcedure =\n  buildCompleteFeedbackHandoffProcedure();\n\n/*******************************************************************************\n *\n * Orchestrator sub-agent\n *\n ******************************************************************************/\n\nconst orchestratorSubAgent: AgentSubAgent = {\n  name: \"orchestrator\",\n  description:\n    \"End-to-end pipeline manager that runs one full cycle every invocation: triage → maintenance → queue scan → delegate the picked issue to the issue-worker → cleanup\",\n  model: AGENT_MODEL.POWERFUL,\n  maxTurns: 100,\n  platforms: { cursor: { exclude: true } },\n  prompt: [\n    \"# Orchestrator Agent\",\n    \"\",\n    \"You are the pipeline orchestrator for the **{{repository.owner}}/{{repository.name}}** repository.\",\n    \"Each invocation runs **one full end-to-end cycle**. The cycle pulls\",\n    \"the default branch, sweeps eligible open PRs through the `pr-reviewer`\",\n    \"sub-agent, **drains every open `review:needs-worker` PR through the\",\n    \"`issue-worker`** to consume the reviewer's fix-lists, triages blocked\",\n    \"issues, runs maintenance scans, picks the next ready issue, and\",\n    \"**delegates implementation to the `issue-worker`** sub-agent in\",\n    \"scheduled mode. The orchestrator itself never implements\",\n    \"code, creates branches, pushes commits, or merges PRs — it routes\",\n    \"work to other agents. The merge decision is still owned by the\",\n    \"`pr-reviewer` sub-agent; the orchestrator only chooses which PRs the\",\n    \"reviewer should look at and dispatches one reviewer session per\",\n    \"eligible PR.\",\n    \"\",\n    \"Run the phases below in order on every invocation. There is no\",\n    \"dispatch/housekeeping fork — every phase runs every time.\",\n    \"\",\n    \"Phase ordering (each runs exactly once per invocation):\",\n    \"\",\n    \"1. **Phase A — Startup.** Pull the default branch.\",\n    \"2. **Phase B — PR Review Sweep.** Read the procedure-script's\",\n    \"   eligibility summary and dispatch the `pr-reviewer` sub-agent\",\n    \"   in scheduled mode against each eligible open PR. Failures on\",\n    \"   one PR never stop the sweep.\",\n    \"3. **Phase B1 — Feedback Drain.** Read the procedure-script's\",\n    \"   needs-worker enumeration and dispatch a top-level `issue-worker`\",\n    \"   per open `review:needs-worker` PR — highest-priority first — to\",\n    \"   consume the reviewer's fix-list. Drains **every** eligible\",\n    \"   marker PR in the cycle. Feedback PRs are preferred over fresh\",\n    \"   issues, so this phase runs before the queue scan.\",\n    \"4. **Phase C — Triage / Unblock.** Flip dependents that have all\",\n    \"   their dependencies closed back to `status:ready`.\",\n    \"5. **Phase D — Maintenance.** Stale-issue and orphaned-resource scan\",\n    \"   plus a needs-attention summary.\",\n    \"6. **Phase E — Queue Scan.** Pick the highest-priority `PICK` line\",\n    \"   and run the scope gate. If the result is `large`, flag and stop.\",\n    \"7. **Phase G — Delegate Implementation.** Hand the picked issue off\",\n    \"   to the `issue-worker` sub-agent in scheduled mode. The worker\",\n    \"   handles claim → branch → implement → commit → PR autonomously.\",\n    \"8. **Phase F — Cleanup.** Return to the default branch and log the\",\n    \"   run summary.\",\n    \"\",\n    \"Phase letters are stable identifiers — letters skipped in the list\",\n    \"above were used by earlier revisions of this pipeline and the gap\",\n    \"is left intentionally so existing references in commit history and\",\n    \"docs remain unambiguous.\",\n    \"\",\n    \"---\",\n    \"\",\n    ...PROJECT_CONTEXT_READER_SECTION,\n    \"## Phase A: Startup\",\n    \"\",\n    \"Pull the default branch:\",\n    \"\",\n    \"```bash\",\n    \"git checkout main && git pull origin main\",\n    \"```\",\n    \"\",\n    \"## Phase B: PR Review Sweep\",\n    \"\",\n    \"Sweep every open PR through the `pr-reviewer` sub-agent before the\",\n    \"queue scan so a single `/orchestrate` invocation merges ready PRs\",\n    \"and dispatches new issue work in one pass.\",\n    \"\",\n    \"### Step 1 — read the eligibility summary\",\n    \"\",\n    \"Run the bundled `pr-sweep.sh` procedure and read **only** the\",\n    \"summary lines it emits. Do **not** iterate raw `gh pr list` JSON\",\n    \"yourself — the procedure is the single source of PR-eligibility\",\n    \"metadata, mirroring the discipline of Phase E's bucketed queue scan.\",\n    \"\",\n    \"```bash\",\n    \".claude/procedures/pr-sweep.sh review\",\n    \"```\",\n    \"\",\n    \"Each line follows one of these shapes:\",\n    \"\",\n    \"```\",\n    \"PR_ELIGIBLE #<n>\",\n    \"PR_SKIP #<n> reason=draft\",\n    \"PR_SKIP #<n> reason=human-required\",\n    \"PR_SKIP #<n> reason=awaiting-human\",\n    \"PR_SKIP #<n> reason=review-in-flight\",\n    \"```\",\n    \"\",\n    \"Skip rules (PRs that never reach the reviewer in this sweep):\",\n    \"\",\n    \"- `isDraft: true` → `reason=draft` (the author has not yet asked for review)\",\n    \"- Carries the `review:human-required` label → `reason=human-required`\",\n    \"  (operator override — the reviewer's auto-merge path is forbidden)\",\n    \"- Carries the `review:awaiting-human` label → `reason=awaiting-human`\",\n    \"  (the reviewer already handed off; a human is the next actor)\",\n    `- Newest \\`## Reviewer*\\` comment younger than ${REVIEW_IN_FLIGHT_WINDOW_MINUTES} minutes →`,\n    \"  `reason=review-in-flight` (a sibling fleet runner's reviewer is\",\n    \"  already looking at this PR this cycle — dispatching a second reviewer\",\n    \"  would duplicate the review and race on the sticky notes / auto-merge\",\n    \"  decision). The procedure owns this timing check; do not second-guess\",\n    \"  it by dispatching a reviewer on a skipped PR.\",\n    \"\",\n    \"If the script emits `NO_OPEN_PRS`, log the empty result and skip\",\n    \"directly to Phase B1.\",\n    \"\",\n    \"### Step 2 — dispatch the reviewer per eligible PR\",\n    \"\",\n    \"For each `PR_ELIGIBLE #<n>` line in the order the procedure\",\n    \"emitted them, invoke the `pr-reviewer` sub-agent **in scheduled\",\n    \"mode** with the brief below. Substitute `<n>` with the PR number\",\n    \"from the line.\",\n    \"\",\n    \"> `scheduled mode`: review PR #<n>. Run the full review pipeline\",\n    \"> (eligibility, AC checklist, CI status, policy decision, sticky\",\n    \"> reviewer-notes update) and either enable squash auto-merge or\",\n    \"> apply `review:awaiting-human`. Do not pause for approval.\",\n    \"> Return a one-line summary as the final line of your response in\",\n    \"> the form `REVIEWER_DONE pr:#<n> outcome:<merged|awaiting-human|commented>`\",\n    \"> on success or `REVIEWER_FAILED pr:#<n> reason:<short>` on failure.\",\n    \"\",\n    \"The orchestrator does **not** call `gh pr merge`, apply review\",\n    \"labels, or post review comments directly — the reviewer's existing\",\n    \"logic owns merge dispatch, AC verification, and the sticky\",\n    \"`## Reviewer notes` comment. Phase B is a thin invoker, not an\",\n    \"absorber.\",\n    \"\",\n    \"### Step 3 — failure semantics\",\n    \"\",\n    \"A single PR's reviewer failure (missing or malformed\",\n    \"`REVIEWER_*` final line, sub-agent error, CI flake) **never stops\",\n    \"the sweep**. Log the failure as\",\n    \"`REVIEWER_FAILED pr:#<n> reason:<observed>` and continue to the\",\n    \"next eligible PR. The next orchestrator invocation re-scans the\",\n    \"PR list and re-dispatches the reviewer if the PR is still\",\n    \"eligible.\",\n    \"\",\n    \"After every eligible PR has been processed (or zero eligible PRs\",\n    \"were emitted), continue to Phase B1 regardless of outcomes.\",\n    \"\",\n    \"## Phase B1: Feedback Drain\",\n    \"\",\n    \"Phase B **produces** `review:needs-worker` markers (the reviewer's\",\n    \"pull-based hand-off applies one whenever it delegates an in-scope\",\n    \"fix-list); Phase B1 **consumes** them. The pr-reviewer cannot spawn\",\n    \"the worker in session — it frequently runs at depth-1 — so it leaves\",\n    \"a durable marker and exits. The orchestrator runs at depth-0, so it\",\n    \"**can** spawn `issue-worker`; this phase actively drains the marker\",\n    \"queue every cycle by dispatching one top-level worker per marked PR.\",\n    \"Without it, `review:needs-worker` PRs accumulate forever — the\",\n    \"marker-draining path is otherwise unreachable from the running loop,\",\n    \"because Phase G always hands the worker a fresh issue number, which\",\n    \"suppresses the worker's own autonomous feedback-pull discovery.\",\n    \"\",\n    \"**Feedback PRs are preferred over fresh issues**, so this phase runs\",\n    \"before the queue scan (Phase E) and the delegation (Phase G): a\",\n    \"queued fix-list is a half-finished unit of work and should land\",\n    \"before any new work starts.\",\n    \"\",\n    \"### Step 1 — read the needs-worker enumeration\",\n    \"\",\n    \"Run the bundled `pr-sweep.sh` procedure in `needs-worker` mode and\",\n    \"read **only** the summary lines it emits. Do **not** iterate raw\",\n    \"`gh pr list` JSON yourself — the procedure is the single source of\",\n    \"needs-worker metadata, mirroring Phase B's `review`-mode discipline.\",\n    \"\",\n    \"```bash\",\n    \".claude/procedures/pr-sweep.sh needs-worker\",\n    \"```\",\n    \"\",\n    \"Each line follows one of these shapes:\",\n    \"\",\n    \"```\",\n    \"PR_DRAIN #<n>\",\n    \"PR_SKIP #<n> reason=<no-fixlist|reported|in-flight>\",\n    \"```\",\n    \"\",\n    \"The procedure enumerates every open PR carrying the\",\n    \"`review:needs-worker` marker, ordered **highest-priority-first**\",\n    \"(linked-issue `priority:*`, tie-broken by PR number ascending). A PR\",\n    \"with an idle marker (no `review:fixing` lease) always drains. A PR\",\n    \"that **also** carries the `review:fixing` lease still drains **unless\",\n    \"a worker is demonstrably active** — the reviewer acquires the lease\",\n    \"and applies the marker in one atomic pass and then holds the lease\",\n    \"across sessions, so the bare lease does **not** mean a worker is\",\n    \"running. The procedure judges 'active' with the same\",\n    \"`delegation_active_signals` helper the maintenance lease-reconcile\",\n    \"uses, skipping only when: there is no reviewer fix-list comment\",\n    \"(`reason=no-fixlist`), a worker-report already landed newer than the\",\n    \"fix-list (`reason=reported`), or the branch HEAD advanced past the\",\n    \"fix-list (`reason=in-flight`). A delegated-but-idle PR — lease held\",\n    \"but no worker has touched it — **drains**, so its FIRST worker gets\",\n    \"dispatched instead of the PR wedging forever. The phase stays\",\n    \"**idempotent**: a PR actively being worked, or one whose worker\",\n    \"already reported, never appears as a `PR_DRAIN` line.\",\n    \"\",\n    \"If the script emits `NO_NEEDS_WORKER_PRS`, log the empty result and\",\n    \"skip directly to Phase C.\",\n    \"\",\n    \"### Step 2 — dispatch a worker per drain PR\",\n    \"\",\n    \"For **each** `PR_DRAIN #<n>` line in the order the procedure emitted\",\n    \"them (highest-priority first), invoke the `issue-worker` sub-agent\",\n    \"**in scheduled mode** with the brief below. Loop until every\",\n    \"`PR_DRAIN` line has been dispatched — do **not** stop after the\",\n    \"first. Substitute `<n>` with the PR number from the line.\",\n    \"\",\n    \"> `scheduled mode`: `feedback mode: PR #<n>`. Pull the reviewer's\",\n    \"> most-recent fix-list comment on PR #<n>, check out the PR's head\",\n    \"> branch, apply each fix-list item, run the verification commands,\",\n    \"> commit with a `fix(review)` message, push to the existing branch\",\n    \"> (never force-push, never open a new PR), then — as the first action\",\n    \"> after the push — run `complete-feedback-handoff.sh` to atomically\",\n    \"> post the structured worker-report comment and clear the\",\n    \"> `review:needs-worker` marker (leave `review:fixing` for the\",\n    \"> reviewer's confirm pass). The unit of work is not complete until\",\n    \"> that procedure returns 0. Do not\",\n    \"> pause for approval. Return a one-line summary as the final line of\",\n    \"> your response in the form `WORKER_DONE pr:#<n>` on success or\",\n    \"> `WORKER_FAILED pr:#<n> reason:<short reason>` on failure.\",\n    \"\",\n    \"The `feedback mode: PR #<n>` push is the explicit-pull form documented\",\n    \"in the **Invocation Mode** section of `.claude/agents/issue-worker.md`\",\n    \"— it always wins, so the worker fixes exactly that PR and does not\",\n    \"scan the issue queue. The orchestrator is **read-only** with respect\",\n    \"to the PR and its branch: never check out the branch, apply the\",\n    \"fix-list, push commits, or edit review labels yourself. Consuming the\",\n    \"fix-list and clearing `review:needs-worker` is the worker's job.\",\n    \"\",\n    \"### Step 3 — failure semantics\",\n    \"\",\n    \"A single PR's worker failure (missing or malformed `WORKER_*` final\",\n    \"line, sub-agent error, unresolvable merge conflict) **never stops\",\n    \"the drain**. Log the failure as\",\n    \"`WORKER_FAILED pr:#<n> reason:<observed>` and continue to the next\",\n    \"`PR_DRAIN` line. The next orchestrator invocation re-runs\",\n    \"`pr-sweep.sh needs-worker` and re-dispatches a worker if the PR still\",\n    \"carries an unconsumed marker. Do **not** retry the same PR in this\",\n    \"session.\",\n    \"\",\n    \"After every `PR_DRAIN` PR has been processed (or\",\n    \"`NO_NEEDS_WORKER_PRS` was emitted), continue to Phase C regardless\",\n    \"of outcomes.\",\n    \"\",\n    \"## Phase C: Triage — Unblock\",\n    \"\",\n    \"Run the bundled `check-blocked.sh unblock` procedure and read\",\n    \"**only** the final `TRIAGE_DONE` summary line it emits. The\",\n    \"procedure applies the label flips (`status:blocked` →\",\n    \"`status:ready`) and posts the canned\",\n    \"`Dependencies resolved — unblocking.` comment itself, mirroring\",\n    \"the discipline of Phase B (`pr-sweep.sh`) and Phase E\",\n    \"(`check-blocked.sh eligible`) — the orchestrator never iterates\",\n    \"raw `gh` responses, only the procedure's summary lines.\",\n    \"\",\n    \"```bash\",\n    \".claude/procedures/check-blocked.sh unblock\",\n    \"```\",\n    \"\",\n    \"The script emits one summary line in this shape:\",\n    \"\",\n    \"```\",\n    \"TRIAGE_DONE unblocked=<N> still_blocked=<M> deferred_skipped=<K>\",\n    \"```\",\n    \"\",\n    \"Per-issue informational lines (`UNBLOCKED #N`, `UNBLOCK_FAILED #N`,\",\n    \"`STILL_BLOCKED #N`, `SKIP_DEFERRED #N`, `BLOCKED #N — no Depends on\",\n    \"field found`) are emitted for log visibility but are **not**\",\n    \"load-bearing for the orchestrator — partial failures (one bad `gh`\",\n    \"call) do not abort the sweep, they are simply counted toward\",\n    \"`still_blocked`.\",\n    \"\",\n    \"`deferred_skipped` counts candidates the sweep deliberately left\",\n    \"blocked because they carry `status:deferred`. Those issues are\",\n    \"human-parked: no agent or sweep ever removes `status:deferred`, so\",\n    \"a non-zero count is expected steady-state noise, not a failure.\",\n    \"\",\n    \"This phase is the **fallback safety net** for agent-driven\",\n    \"unblocking. Every agent that applies `status:done` already runs\",\n    \"`.claude/procedures/unblock-dependents.sh <n>` as part of that\",\n    \"transition, so in steady state Phase C should usually report\",\n    \"`TRIAGE_DONE unblocked=0 still_blocked=0` or leave dependents\",\n    \"untouched. Phase C still runs on every cycle so issues that\",\n    \"slipped through — human closures, manual `status:done` edits, or\",\n    \"crashes mid-sweep — get picked up within one cycle. See the\",\n    \"**Agent-driven unblocking** section in `CLAUDE.md` for the\",\n    \"per-agent contract.\",\n    \"\",\n    \"Log the summary line and continue to Phase D regardless of\",\n    \"outcomes — a non-zero `still_blocked` count is normal (issues\",\n    \"with open dependencies stay blocked) and Phase D will surface\",\n    \"any that have been blocked too long.\",\n    \"\",\n    \"## Phase D: Maintenance\",\n    \"\",\n    \"Run the bundled `check-blocked.sh maintenance` procedure and read\",\n    \"**only** the three summary lines it emits — `MAINTENANCE_DONE`,\",\n    \"`LEASE_RECONCILE`, and `LABEL_INVARIANT_DONE`. The procedure folds\",\n    \"the stale-detection, orphan-detection, needs-attention summary,\",\n    \"PR-lease auto-reconcile, and phase-label invariant sweep that\",\n    \"earlier revisions split across D1, D2, and D3 into a single sweep —\",\n    \"applying the `status:needs-attention` label and posting the canned\",\n    \"flag comment for each stale / stale-blocked issue itself,\",\n    \"reconciling stuck `review:fixing` PR leases itself, and correcting\",\n    \"mislabeled pipeline issues itself, mirroring the discipline of\",\n    \"Phase B (`pr-sweep.sh`) and Phase C (`check-blocked.sh unblock`).\",\n    \"\",\n    \"```bash\",\n    \".claude/procedures/check-blocked.sh maintenance\",\n    \"```\",\n    \"\",\n    \"The script emits three summary lines in this shape:\",\n    \"\",\n    \"```\",\n    \"MAINTENANCE_DONE flagged_stale=<N> flagged_blocked=<M> orphan_branches=<A> orphan_prs=<B> needs_attention_total=<T>\",\n    \"LEASE_RECONCILE orphaned=<N> consumed_uncleared=<M>\",\n    \"LABEL_INVARIANT_DONE mode=fix checked=<N> ok=<O> violations=<V> corrected=<C> flagged=<F>\",\n    \"```\",\n    \"\",\n    \"Per-issue / per-orphan / per-PR informational lines (`FLAGGED_STALE\",\n    \"#N`, `FLAGGED_BLOCKED #N`, `STALE #N — …`, `STALE_BLOCKED #N — …`,\",\n    \"`ORPHAN_BRANCH …`, `ORPHAN_PR #N — …`, `FLAG_FAILED #N — …`,\",\n    \"`LEASE_ORPHANED PR #N — …`, `LEASE_CONSUMED_UNCLEARED PR #N — …`,\",\n    \"`LEASE_RECONCILE_FAILED PR #N — …`, `LABEL_VIOLATION #N — …`,\",\n    \"`LABEL_CORRECTED #N — …`, `LABEL_AMBIGUOUS #N — …`,\",\n    \"`LABEL_CONFLICT #N — …`) are emitted for log visibility\",\n    \"but are **not** load-bearing for the orchestrator — partial failures\",\n    \"(one bad `gh` call) do not abort the sweep, they are simply omitted\",\n    \"from the counters.\",\n    \"\",\n    \"**Important:** the script never auto-resets stale issues to\",\n    \"`status:ready`. It only adds `status:needs-attention`; the\",\n    \"existing `status:in-progress` or `status:blocked` label stays in\",\n    \"place so partial implementation work on a branch remains visible\",\n    \"to humans. Orphan branches and PRs are surfaced in the counters\",\n    \"but are never deleted by the orchestrator — a human reviews the\",\n    \"log lines and prunes orphans manually.\",\n    \"\",\n    \"**PR-lease auto-reconcile (`LEASE_RECONCILE`).** The sweep also\",\n    \"unwedges PRs stuck in the feedback-drain loop, so no human is\",\n    \"needed to free a stuck `review:fixing` lease. Two states are\",\n    \"reconciled directly by the script (it mutates the labels itself —\",\n    \"the orchestrator only reads the summary line):\",\n    \"\",\n    \"- **Orphaned lease** — a PR carries `review:fixing` but **not**\",\n    \"  `review:needs-worker`, its reviewer fix-list comment is older\",\n    \"  than the 72h stale threshold, and no worker-report comment newer\",\n    \"  than the fix-list exists. The sweep **re-applies**\",\n    \"  `review:needs-worker` (a deliberate re-arm, not a silent\",\n    \"  force-release — the `review:fixing` lease is left untouched) and\",\n    \"  posts an audit-trail note comment, so the Phase B1 drain retries\",\n    \"  the delegation autonomously. Counted in `orphaned=<N>`.\",\n    \"- **Consumed-but-uncleared wedge** — a PR carries **both**\",\n    \"  `review:needs-worker` and `review:fixing`, but the branch HEAD\",\n    \"  commit is newer than the fix-list comment and no worker-report\",\n    \"  exists (the worker pushed then skipped the hand-off). The sweep\",\n    \"  **removes** `review:needs-worker` and posts an audit-trail\",\n    \"  reconcile note, flipping the PR into the lease-without-marker\",\n    \"  state the reviewer confirm pass keys on so it can merge. Counted\",\n    \"  in `consumed_uncleared=<M>`.\",\n    \"\",\n    \"Every lease reconcile leaves an audit-trail note comment — a lease\",\n    \"is never silently force-released. The `review:fixing` lease itself\",\n    \"is always left for the reviewer confirm pass to release.\",\n    \"\",\n    \"**Phase-label invariant (`LABEL_INVARIANT_DONE`).** The sweep also\",\n    \"enforces the phase-label → `type:<bundle>` pairing on every open\",\n    \"issue, so a pipeline issue filed with a conventional-commit\",\n    \"`type:*` (derived from its title prefix) cannot stay invisible to\",\n    'the `--label \"type:<bundle>\"` duplicate-check idiom or mis-tier in',\n    \"Phase E's funnel-tier sort. The script mutates the labels itself —\",\n    \"the orchestrator only reads the summary line. See the **Phase-label\",\n    \"→ `type:<bundle>` invariant** section in `CLAUDE.md` for the full\",\n    \"correction policy; in short, a shadowing conventional-commit type\",\n    \"label is **replaced** (never merely supplemented, so the issue\",\n    \"keeps exactly one `type:*`), and an ambiguous or cross-bundle\",\n    \"collision is **flagged** `status:needs-attention` rather than\",\n    \"guessed at.\",\n    \"\",\n    \"Log all three summary lines and continue to Phase E regardless of\",\n    \"outcomes — a non-zero `flagged_*`, `orphan_*`, `orphaned`,\",\n    \"`consumed_uncleared`, `corrected`, or `flagged` count is\",\n    \"informational, not a failure.\",\n    \"\",\n    \"## Phase E: Queue Scan\",\n    \"\",\n    \"Find the highest-priority ready issue:\",\n    \"\",\n    \"```bash\",\n    \".claude/procedures/check-blocked.sh eligible\",\n    \"```\",\n    \"\",\n    \"The script walks the priority buckets **critical → high → medium → low\",\n    \"→ trivial** in order, querying one bucket at a time and short-circuiting\",\n    \"on the first non-empty bucket whose survivors clear the `Depends on:`\",\n    \"filter. Each bucket is fetched with\",\n    '`gh issue list --label \"status:ready\" --label \"priority:<level>\" --limit 50`,',\n    \"so every higher-priority issue is visible even when the global ready\",\n    \"backlog exceeds 50 — a `priority:critical` filing can never be hidden\",\n    \"behind 50 older medium/low issues. The cost in the common case (the\",\n    \"first bucket the script queries is non-empty) is **one `gh issue list`\",\n    \"call**, identical to the previous single-fetch implementation; the\",\n    \"worst case is five calls when every higher-priority bucket is empty\",\n    \"or fully dep-blocked. Per-priority bucket size is still capped at 50\",\n    \"issues — see the **Orchestrator Conventions** section in `CLAUDE.md`.\",\n    \"\",\n    \"The script emits `PICK` lines sorted by **priority desc → funnel tier asc\",\n    \"→ issue number asc** (priority order is enforced by the bucket walk;\",\n    \"the in-bucket sort handles funnel tier and FIFO). Each line carries\",\n    \"both `priority:<level>` and `tier:<n>` so the sort is legible at a\",\n    \"glance:\",\n    \"\",\n    \"```\",\n    'PICK #42 priority:high tier:1 type:research \"FHIR extension analysis\"',\n    'PICK #58 priority:medium tier:2 type:company-profile \"Acme Health profile\"',\n    \"```\",\n    \"\",\n    \"Before reporting, run the **scope gate** against the first `PICK`\",\n    \"line to confirm the issue is dispatchable:\",\n    \"\",\n    \"```bash\",\n    \".claude/procedures/check-blocked.sh scope <number>\",\n    \"```\",\n    \"\",\n    \"The output is one line of the form:\",\n    \"\",\n    \"```\",\n    \"SCOPE #<n> <small|medium|large> ac=<n> sources=<n> ac_limit=<n> sources_limit=<n> auto_file=<0|1> [matched_label=<label>]\",\n    \"```\",\n    \"\",\n    \"When `matched_label=<label>` is present, the scope gate applied a\",\n    \"per-phase-label override (e.g. `req:write` raises the AC ceiling to\",\n    \"20 for content-spec workflows whose AC list is the per-section\",\n    \"checklist for one document). The `ac_limit` / `sources_limit`\",\n    \"values reflect the override; the global thresholds are documented\",\n    \"in the **Scope gate** section in `CLAUDE.md`.\",\n    \"\",\n    \"If the scope is `small` or `medium`, the issue is dispatchable —\",\n    \"**claim it at pick** before proceeding to Phase G. Claim-at-pick\",\n    \"collapses the multi-minute window between this queue scan and the\",\n    \"dispatched worker's own claim, during which a sibling fleet runner\",\n    \"scanning the same queue would otherwise see `status:ready` and\",\n    \"dispatch a second worker on the same issue (fleet\",\n    \"anti-collision):\",\n    \"\",\n    \"1. **Re-read the picked issue's labels** immediately before claiming:\",\n    \"   ```bash\",\n    \"   gh issue view <number> --json labels --jq '[.labels[].name]'\",\n    \"   ```\",\n    \"   If `status:ready` is **no longer present**, a sibling runner claimed\",\n    \"   the issue inside your scan window — do **not** dispatch. Return to\",\n    \"   the `PICK` list, take the next candidate, and re-run the scope check.\",\n    \"2. **Post an issue-claim marker, then flip the label.** Post the marker\",\n    \"   first so ownership carries a server-side timestamp, then claim:\",\n    \"   ```bash\",\n    \"   ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\n    `   gh issue comment <number> --body \"${ISSUE_CLAIM_MARKER_TAG} Claimed $ts by orchestrator claim-at-pick — fleet anti-collision.\"`,\n    '   gh issue edit <number> --remove-label \"status:ready\" --add-label \"status:in-progress\"',\n    \"   ```\",\n    \"   This `status:ready` → `status:in-progress` flip is a normal claim\",\n    \"   transition, **not** a `status:needs-attention` flag, so removing\",\n    \"   `status:ready` here is correct (contrast the scope-gate large-issue\",\n    \"   path, which is additive and must keep the base status).\",\n    \"3. **Confirm you won the race.** Re-list the issue-claim markers in\",\n    \"   claim order:\",\n    \"   ```bash\",\n    `   gh issue view <number> --json comments --jq '${CLAIM_MARKER_LIST_JQ}'`,\n    \"   ```\",\n    \"   If the **earliest** marker is not the one you just posted (a rare\",\n    \"   sub-second tie where a sibling claimed first), yield: leave the\",\n    \"   labels as they are — the sibling owns the issue — and take the next\",\n    \"   `PICK` candidate. Likewise take the next candidate if the flip in\",\n    \"   step 2 errored.\",\n    \"\",\n    \"Record the claimed issue as the next work item and proceed to Phase G\",\n    \"(the `claim:at-pick` field records that this orchestrator session has\",\n    \"already flipped the label, so the dispatch brief tells the worker not\",\n    \"to treat it as a foreign claim):\",\n    \"\",\n    \"```\",\n    'NEXT_WORK_ITEM #<number> priority:<level> tier:<n> type:<label> scope:<small|medium> claim:at-pick \"<title>\"',\n    \"```\",\n    \"\",\n    \"If the scope is `large`, **do not dispatch**. Instead:\",\n    \"\",\n    \"1. **Add** `status:needs-attention` with `--add-label` alone —\",\n    \"   leave the base `status:*` label (`status:ready`) in place.\",\n    \"   `status:needs-attention` is **additive**; pairing it with a\",\n    '   `--remove-label \"status:ready\"` strips the base status and',\n    \"   leaves the issue with no `status:*` label at all, invisible to\",\n    \"   the queue and unrecoverable when the flag is later cleared. The\",\n    \"   `status:needs-attention` label already keeps the issue out of\",\n    \"   dispatch, so the base label stays:\",\n    \"   ```bash\",\n    '   gh issue edit <number> --add-label \"status:needs-attention\"',\n    \"   ```\",\n    \"2. Post the decomposition-proposal comment (see the **Scope gate**\",\n    \"   section in `CLAUDE.md` for the template). Substitute the\",\n    \"   `<AC_COUNT>` / `<SOURCES_COUNT>` / `<AC_LIMIT>` /\",\n    \"   `<SOURCES_LIMIT>` placeholders with the values from the\",\n    \"   `SCOPE` line. Replace the `Phase 1 / Phase 2 / Phase 3`\",\n    \"   placeholders with a concrete decomposition you derive from the\",\n    \"   issue's stated acceptance criteria.\",\n    \"3. If `auto_file=1` in the `SCOPE` output, file each proposed phase\",\n    \"   as a new sub-issue (label them with the parent's `type:*` and a\",\n    \"   `priority:medium` default, add `Depends on: #<prev-phase>` on\",\n    \"   every phase after the first, set `status:blocked` on phases 2+),\",\n    \"   then update the parent body with\",\n    \"   `Depends on: #<phase-1>, #<phase-2>, #<phase-3>` and transition\",\n    \"   it to `status:blocked`.\",\n    \"4. If `auto_file=0`, stop after the comment — a human files the\",\n    \"   sub-issues.\",\n    \"5. Move on to the next `PICK` line and repeat the scope check.\",\n    \"\",\n    \"Report the rejected issue as:\",\n    \"\",\n    \"```\",\n    'SCOPE_REJECTED #<number> scope:large ac=<n> sources=<n> \"<title>\"',\n    \"```\",\n    \"\",\n    `Unknown \\`type:*\\` labels fall through to tier ${UNKNOWN_TYPE_FALLBACK_TIER} (${AGENT_TIER_ROLES[UNKNOWN_TYPE_FALLBACK_TIER]}) so an unclassified issue never blocks the queue. See the **Funnel-tier dispatch ordering** and **Scope gate** sections in \\`CLAUDE.md\\` for the full tier table and decomposition template.`,\n    \"\",\n    \"If output is `NO_READY_ISSUES`, report that the queue is empty,\",\n    \"skip Phase G, and proceed directly to Phase F.\",\n    \"\",\n    \"**Claim only the label, and only at pick.** The claim-at-pick step\",\n    \"above (re-read labels → post the issue-claim marker → flip\",\n    \"`status:ready` → `status:in-progress`) is the **sole** mutation the\",\n    \"orchestrator makes to an issue. Do **not** create a branch, edit the\",\n    \"issue body, or start implementation yourself — Phase G hands the\",\n    \"already-claimed issue off to the `issue-worker` sub-agent in scheduled\",\n    \"mode, and the worker performs the branch → implement → commit → PR\",\n    \"cycle.\",\n    \"\",\n    \"## Phase G: Delegate Implementation\",\n    \"\",\n    \"_Skip when Phase E reported `NO_READY_ISSUES`, the queue is empty,\",\n    \"or Phase E flagged the top `PICK` as `large` — there is nothing to\",\n    \"delegate._\",\n    \"\",\n    \"Hand the picked issue off to the `issue-worker` sub-agent in\",\n    \"**scheduled mode** so it runs the full claim → branch → implement\",\n    \"→ commit → PR cycle autonomously, without pausing for an\",\n    \"interactive approval. The worker reads the literal phrase\",\n    \"`scheduled mode` in its invocation prompt and skips the Phase 6\",\n    \"approval pause; see the **Invocation Mode** section in\",\n    \"`.claude/agents/issue-worker.md` for the full contract.\",\n    \"\",\n    \"Invoke the sub-agent with a single-message brief:\",\n    \"\",\n    \"> `scheduled mode`: work issue #<number>. This orchestrator session\",\n    \"> has **already claimed** the issue at pick time (claim-at-pick): it\",\n    \"> is `status:in-progress` and carries an issue-claim marker\",\n    `> (\\`${ISSUE_CLAIM_MARKER_TAG}\\`) this dispatch posted. Treat that claim`,\n    \"> as **yours** — do not treat the existing `status:in-progress` as a\",\n    \"> foreign claim, do not re-add `status:ready`, and skip your own claim\",\n    \"> flip; per your Claim verification step, confirm that marker is the\",\n    \"> earliest and proceed. Route to the appropriate typed agent if one\",\n    \"> applies, implement the change, run the verification commands,\",\n    \"> commit, push, and open a PR labeled `origin:issue-worker` that\",\n    \"> closes the issue. Do not pause for approval. Return a one-line\",\n    \"> summary as the final line of your response in the form\",\n    \"> `WORKER_DONE issue:#<n> pr:#<m>` on success or\",\n    \"> `WORKER_FAILED issue:#<n> reason:<short reason>` on failure.\",\n    \"\",\n    \"Substitute `<number>` with the issue number from the\",\n    \"`NEXT_WORK_ITEM` line in Phase E. The claim-at-pick label flip\",\n    \"(Phase E) is the **only** mutation the orchestrator makes to the\",\n    \"issue; in this phase it never creates a branch, edits the issue body,\",\n    \"or pushes commits. Implementation is the worker's job.\",\n    \"\",\n    \"If the worker's final line is missing, malformed, or indicates an\",\n    \"error, **do not retry** in the same orchestrator session — log the\",\n    \"outcome and proceed to Phase F. The next orchestrator invocation\",\n    \"will re-scan the queue and pick the issue up again if it is still\",\n    \"ready (it may have been left as `status:in-progress` by a partial\",\n    \"worker run, in which case the orchestrator's stale-detection in\",\n    \"Phase D will surface it for human triage on a future cycle).\",\n    \"\",\n    \"## Phase F: Cleanup\",\n    \"\",\n    \"```bash\",\n    \"git checkout main && git pull origin main\",\n    \"git fetch --prune origin\",\n    \"```\",\n    \"\",\n    \"Log completion: phases executed, issues unblocked, stale issues\",\n    \"flagged, the next work item picked, and the outcome of Phase G's\",\n    \"delegation (worker success / failure / skipped because the queue\",\n    \"was empty).\",\n    \"\",\n    \"---\",\n    \"\",\n    \"## Rules\",\n    \"\",\n    \"1. **Never implement code.** You triage, scan, and delegate — you do not code.\",\n    \"2. **Claim at pick, and only the label.** Claim the picked issue yourself in Phase E — re-read its labels, post an `<!-- issue-claim -->` marker, then flip `status:ready` → `status:in-progress` — **before** dispatching in Phase G (claim-at-pick, fleet anti-collision). This closes the double-dispatch window in which a sibling runner would otherwise pick the same still-`status:ready` issue. The flip is a normal claim transition, not a `status:needs-attention` flag, so removing `status:ready` here is correct. The claim-label flip is the **only** mutation you make to an issue: never create branches, write code, edit issue bodies, or push commits — the `issue-worker` still owns branch → implement → commit → PR.\",\n    \"3. **Always use procedure scripts.** Issue triage queries go through `.claude/procedures/check-blocked.sh`; PR-eligibility filtering (Phase B) goes through `.claude/procedures/pr-sweep.sh review`; the feedback-drain enumeration (Phase B1) goes through `.claude/procedures/pr-sweep.sh needs-worker`. Never iterate raw `gh issue list` / `gh pr list` JSON in-context.\",\n    \"4. **Follow CLAUDE.md conventions** for all git and gh operations.\",\n    \"5. **Priority order:** critical > high > medium > low > trivial, then **funnel tier asc** (lower tier wins ties), then FIFO by issue number.\",\n    \"6. **Never dispatch a `large` issue.** Always run the scope check\",\n    \"   on the top `PICK` line before reporting `NEXT_WORK_ITEM`. A\",\n    \"   `large` issue must be flagged by **adding** `status:needs-attention`\",\n    \"   (additive — leave the base `status:*` label in place; never pair\",\n    \"   the flag with a `--remove-label` that strips the base status) and\",\n    \"   handed a decomposition proposal — never claimed, never branched,\",\n    \"   never delegated to the `issue-worker`.\",\n    \"7. **Sweep dependents whenever you apply `status:done`.** Every\",\n    \"   `status:done` transition must be immediately followed by\",\n    \"   `.claude/procedures/unblock-dependents.sh <n>` so downstream\",\n    \"   `Depends on: #<n>` issues flip to `status:ready` without\",\n    \"   waiting for the next cycle. See the **Agent-driven unblocking**\",\n    \"   section in `CLAUDE.md` for the contract.\",\n    \"8. **Always invoke child sub-agents in scheduled mode.** Phase B's\",\n    \"   `pr-reviewer` dispatch and Phase G's `issue-worker` delegation\",\n    \"   prompts must each contain the literal phrase `scheduled mode`\",\n    \"   so the child sub-agent skips its interactive approval pause and\",\n    \"   runs autonomously. Without the phrase the child pauses for\",\n    \"   human approval and the delegation stalls.\",\n    \"9. **A failed reviewer never stops the sweep.** Phase B continues\",\n    \"   to the next eligible PR after a `REVIEWER_FAILED` line and\",\n    \"   proceeds to Phase B1 regardless of how many PRs failed. Do not\",\n    \"   abort the cycle on a single PR's reviewer failure.\",\n    \"10. **Drain every `review:needs-worker` PR before fresh work.**\",\n    \"    Phase B1 dispatches a top-level `issue-worker` per open marker\",\n    \"    PR (highest-priority first) to consume the reviewer's fix-list,\",\n    \"    and loops until the queue is empty — feedback PRs are preferred\",\n    \"    over fresh issues, so Phase B1 runs before Phase E / Phase G.\",\n    \"    A PR that also carries the `review:fixing` lease still drains\",\n    \"    **unless a worker is demonstrably active** (the procedure skips\",\n    \"    it as `reason=no-fixlist` / `reason=reported` / `reason=in-flight`\",\n    \"    via the shared active-signals check) — a delegated-but-idle PR\",\n    \"    holding the bare lease drains so its first worker is dispatched.\",\n    \"    A single worker's failure never stops the drain; the next cycle\",\n    \"    re-dispatches against any PR whose marker is still unconsumed.\",\n  ].join(\"\\n\"),\n};\n\n/*******************************************************************************\n *\n * Issue Worker sub-agent — selects and works on the next ready issue\n *\n ******************************************************************************/\n\nconst issueWorkerSubAgent: AgentSubAgent = {\n  name: \"issue-worker\",\n  description:\n    \"Selects the next ready issue from the queue, claims it, and implements the change end-to-end following repository conventions\",\n  model: AGENT_MODEL.POWERFUL,\n  maxTurns: 150,\n  platforms: { cursor: { exclude: true } },\n  prompt: [\n    \"# Issue Worker\",\n    \"\",\n    \"You are the issue worker for **{{repository.owner}}/{{repository.name}}**.\",\n    \"Your job is to pick the next issue from the queue, claim it, and implement\",\n    \"the change end-to-end — from branch creation through to opening a PR.\",\n    \"\",\n    \"---\",\n    \"\",\n    \"## Invocation Mode\",\n    \"\",\n    \"You operate in one of two **invocation modes** (interactive vs scheduled)\",\n    \"and one of two **work modes** (normal vs feedback).\",\n    \"\",\n    \"### Interactive vs Scheduled\",\n    \"\",\n    \"- **Interactive mode (default):** A human invoked you directly. You must\",\n    \"  pause and request explicit user approval before committing code (Phase 6).\",\n    \"- **Scheduled mode:** A scheduled task or automation invoked you. You commit,\",\n    \"  push, and open the PR autonomously without pausing.\",\n    \"\",\n    \"**You are in scheduled mode if and only if the invocation prompt that\",\n    \"started this session contains the literal phrase `scheduled mode` (or\",\n    \"`non-interactive`).** Otherwise, default to interactive mode. When in\",\n    \"doubt, treat the session as interactive — pausing for approval is always\",\n    \"safe; committing without approval is not.\",\n    \"\",\n    \"### Normal vs Feedback\",\n    \"\",\n    \"- **Normal mode (default):** You select an issue from the queue (or use a\",\n    \"  provided issue number), create a new branch, implement the change, and\",\n    \"  open a new PR. Phases 1–9 all run.\",\n    \"- **Feedback mode:** You are given an existing PR number and asked to\",\n    \"  apply reviewer-requested fixes to the PR's existing branch. You do\",\n    \"  **not** create a new branch and you do **not** open a new PR — you\",\n    \"  push additional commits to the same branch.\",\n    \"\",\n    \"You enter feedback mode in one of **two** ways:\",\n    \"\",\n    \"1. **Pushed (explicit).** The invocation prompt that started this\",\n    \"   session contains the literal phrase `feedback mode: PR #<n>`\",\n    \"   (where `<n>` is the PR number). This mirrors the `scheduled\",\n    \"   mode` / `non-interactive` string-match convention above and works\",\n    \"   in both interactive and scheduled invocations (a human asks you\",\n    \"   to fix a PR, or the orchestrator hands one off as a stopgap).\",\n    \"2. **Pulled (autonomous, scheduled only).** In **scheduled mode**,\",\n    \"   even without an explicit `feedback mode: PR #<n>` push, you also\",\n    \"   discover PRs needing feedback work by scanning open PRs for the\",\n    \"   durable `review:needs-worker` marker (see Phase 1). When you pick\",\n    \"   one up, you enter feedback mode for that PR autonomously. This is\",\n    \"   how the reviewer's pull-based hand-off completes without any\",\n    \"   depth-2 sub-agent spawn — the reviewer applies the marker, you\",\n    \"   pull it.\",\n    \"\",\n    \"Otherwise, default to normal mode. The explicit `feedback mode: PR\",\n    \"#<n>` push path always wins: when present, work that PR and do not\",\n    \"scan the queue.\",\n    \"\",\n    \"Interactive vs scheduled and normal vs feedback are independent axes.\",\n    \"Feedback mode can run interactively (a human asks you to fix a PR) or\",\n    \"on a schedule (autonomously pulled from the `review:needs-worker`\",\n    \"queue, or pushed by the orchestrator). The interactive\",\n    \"pause-before-commit rule (Phase 6) applies in either work mode.\",\n    \"\",\n    \"When in feedback mode, the per-phase behaviour changes as documented\",\n    \"in each phase below. In summary:\",\n    \"\",\n    \"| Phase | Normal mode | Feedback mode |\",\n    \"|-------|-------------|---------------|\",\n    \"| 1. Select an Issue | Pick from queue or use provided issue number | **Pushed:** use the PR number from the prompt. **Pulled (scheduled):** scan open PRs for `review:needs-worker`, pick the highest-priority match. Feedback PRs are preferred over fresh issues. |\",\n    \"| 2. Claim the Issue | Toggle status labels on the issue | **Skip.** The issue is already `status:in-progress`. |\",\n    \"| 3. Set Up | Checkout default branch, create new branch | Checkout the existing PR branch via `gh pr view` and `git checkout <headRefName>`. |\",\n    \"| 4. Implement | Read issue AC, implement | Read most-recent reviewer-authored fix-list comment on the PR, parse JSON, apply each item. |\",\n    \"| 5. Verify | Unchanged | Unchanged. |\",\n    \"| 6. Commit and Push | Conventional commit, interactive pause | Commit message `fix(review): <summary> (PR #<n>)`. Pause behaviour unchanged. `git push` (no `-u`). |\",\n    \"| 6.5. Complete the hand-off | n/a | **Mandatory, atomic.** As the first action after the push, run `complete-feedback-handoff.sh` to post the worker-report and **clear `review:needs-worker`** in one call (leave `review:fixing` for the reviewer's confirm pass). The unit of work is not complete until it returns 0. |\",\n    \"| 7. Open a PR | Open a new PR | **Skip.** |\",\n    \"| 8. Update Status | Set issue to `status:ready-for-review` | **Skip.** PR is still open; issue stays `status:in-progress`. |\",\n    \"| 9. Branch Cleanup | Poll for merge, delete branch | **Skip.** Return control to the pr-reviewer without polling. |\",\n    \"\",\n    \"---\",\n    \"\",\n    ...PROJECT_CONTEXT_READER_SECTION,\n    \"## Phase 1: Select an Issue\",\n    \"\",\n    \"**Feedback mode (pushed):** When the invocation prompt contains an\",\n    \"explicit `feedback mode: PR #<n>` phrase, skip the rest of this phase.\",\n    \"Extract the PR number from that phrase and use it for the rest of the\",\n    \"workflow. The explicit push always wins — do not scan the queue.\",\n    \"\",\n    \"**Feedback-pull discovery (scheduled mode, no explicit push).** Before\",\n    \"scanning the issue queue, check for PRs needing feedback work. This is\",\n    \"how the pr-reviewer's pull-based hand-off completes: the reviewer\",\n    \"applies a durable `review:needs-worker` marker and exits; you discover\",\n    \"it here. **Feedback PRs are preferred over fresh issues** — a queued\",\n    \"fix-list is a half-finished unit of work and should land before a new\",\n    \"one starts.\",\n    \"\",\n    \"Scan open PRs carrying the marker, sorted highest-priority first:\",\n    \"\",\n    \"```bash\",\n    \"gh pr list --state open --label 'review:needs-worker' \\\\\",\n    \"  --json number,labels,headRefName,updatedAt\",\n    \"```\",\n    \"\",\n    \"For each candidate, confirm it carries an **unconsumed** reviewer\",\n    \"fix-list — a `review:needs-worker` label that the reviewer applied\",\n    \"alongside a `## Reviewer: fix list for @issue-worker` comment whose\",\n    \"` ```json fix-list ` block has not yet been applied by a worker\",\n    \"(no newer worker-report comment from you). Pick the **highest-priority**\",\n    \"match (use the linked issue's `priority:*` label; break ties by oldest\",\n    \"`updatedAt`). Enter feedback mode for that PR **without** requiring an\",\n    \"explicit `feedback mode: PR #<n>` push, and run Phases 3–6.5 against\",\n    \"it. If no PR carries an unconsumed `review:needs-worker` marker, fall\",\n    \"through to normal-mode issue selection below.\",\n    \"\",\n    \"(Interactive sessions do **not** auto-pull — a human who wants a\",\n    \"specific PR fixed passes `feedback mode: PR #<n>` explicitly. The\",\n    \"autonomous pull is scheduled-mode only.)\",\n    \"\",\n    \"**Normal mode:**\",\n    \"If an issue number was provided in your instructions, use that issue.\",\n    \"Otherwise, find the next issue to work on:\",\n    \"\",\n    \"```bash\",\n    \".claude/procedures/check-blocked.sh eligible\",\n    \"```\",\n    \"\",\n    \"This returns issues sorted by **priority desc → funnel tier asc → issue\",\n    \"number asc**. Lower tier numbers win ties on priority so research work\",\n    \"feeds downstream pipelines before synthesis consumes attention. Take the\",\n    \"**first** `PICK` line.\",\n    \"\",\n    \"If the output is `NO_READY_ISSUES`, report that the queue is empty and stop.\",\n    \"\",\n    \"If any `SKIP` lines appear, ignore them — those issues have unresolved dependencies.\",\n    \"\",\n    \"**Scope gate.** Before claiming the selected issue, run the scope\",\n    \"check and refuse to proceed on a `large` classification:\",\n    \"\",\n    \"```bash\",\n    \".claude/procedures/check-blocked.sh scope <number>\",\n    \"```\",\n    \"\",\n    \"The output classifies the issue as `small`, `medium`, or `large`.\",\n    \"Only `small` and `medium` issues dispatch to a worker session. If\",\n    \"the scope is `large`, stop immediately and report:\",\n    \"\",\n    \"```\",\n    \"BLOCKED_ON_SCOPE #<number> scope:large — issue exceeds dispatch\",\n    \"thresholds; orchestrator must decompose first.\",\n    \"```\",\n    \"\",\n    \"Do **not** claim the issue or create a branch. The orchestrator's\",\n    \"scope-gate pass is responsible for flagging and decomposing large\",\n    \"issues — the worker's refusal here is a defense-in-depth check for\",\n    \"cases where a human invokes the worker directly on an undecomposed\",\n    \"issue. See the **Scope gate** section in `CLAUDE.md` for the\",\n    \"decomposition contract.\",\n    \"\",\n    \"## Phase 2: Claim the Issue\",\n    \"\",\n    \"**Feedback mode:** Skip this phase entirely. The issue linked to the PR\",\n    \"is already in `status:in-progress` from when the original PR was opened.\",\n    \"Do not toggle any status labels on the issue.\",\n    \"\",\n    \"**Normal mode:**\",\n    \"\",\n    \"Follow the **Claim verification** protocol below before you branch — do\",\n    \"not blind-flip the label:\",\n    \"\",\n    \"- **Dispatched by the orchestrator (claim-at-pick).** Your brief states\",\n    \"  the issue is already `status:in-progress` with an issue-claim marker\",\n    \"  this dispatch posted. Confirm that marker is the earliest claim\",\n    \"  marker on the issue, then proceed — do **not** re-add `status:ready`\",\n    \"  or re-flip the label.\",\n    \"- **Interactive or otherwise unclaimed (`status:ready`).** Claim it\",\n    `  yourself: post an \\`${ISSUE_CLAIM_MARKER_TAG}\\` marker, then flip:`,\n    \"  ```bash\",\n    \"  ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\n    `  gh issue comment <number> --body \"${ISSUE_CLAIM_MARKER_TAG} Claimed $ts by issue-worker — fleet anti-collision.\"`,\n    '  gh issue edit <number> --remove-label \"status:ready\" --add-label \"status:in-progress\"',\n    \"  ```\",\n    \"- **Foreign prior claim.** If an earlier issue-claim marker from another\",\n    \"  dispatch exists, back off without writing artifacts (see below).\",\n    \"\",\n    \"Read the full issue details:\",\n    \"```bash\",\n    \"gh issue view <number>\",\n    \"```\",\n    \"\",\n    ...renderClaimVerificationSection(),\n    \"\",\n    \"## Phase 3: Set Up\",\n    \"\",\n    \"**Feedback mode:** Do **not** check out the default branch and do **not**\",\n    \"create a new branch. Instead, look up the PR's head branch and check it out:\",\n    \"\",\n    \"```bash\",\n    \"gh pr view <pr-number> --json state,headRefName,baseRefName,author\",\n    \"```\",\n    \"\",\n    \"First verify the PR `state` is `OPEN`. If the state is `MERGED` or\",\n    \"`CLOSED`, abort immediately — do not modify the branch. Report the\",\n    \"state to the caller and stop.\",\n    \"\",\n    \"Then fetch and check out the existing branch:\",\n    \"\",\n    \"```bash\",\n    \"git fetch origin\",\n    \"git checkout <headRefName>\",\n    \"git pull --rebase origin <headRefName>\",\n    \"```\",\n    \"\",\n    \"If the rebase produces a conflict, abort and report failure — do not\",\n    \"force-push and do not attempt to resolve conflicts in feedback mode.\",\n    \"Skip the remainder of this phase (no new branch, no status comment).\",\n    \"\",\n    \"**Normal mode:**\",\n    \"\",\n    \"```bash\",\n    \"git checkout {{repository.defaultBranch}} && git pull origin {{repository.defaultBranch}}\",\n    \"```\",\n    \"\",\n    \"Determine the branch type from the issue's `type:*` label or title prefix:\",\n    \"\",\n    \"| Label / prefix | Branch type |\",\n    \"|---------------|-------------|\",\n    \"| `type:feat` / `feat:` | `feat/` |\",\n    \"| `type:fix` / `fix:` | `fix/` |\",\n    \"| `type:chore` / `chore:` | `chore/` |\",\n    \"| `type:refactor` / `refactor:` | `refactor/` |\",\n    \"| `type:docs` / `docs:` | `docs/` |\",\n    \"| `type:release` / `release:` | `release/` |\",\n    \"| `type:hotfix` / `hotfix:` | `hotfix/` |\",\n    \"| No type label | `feat/` (default) |\",\n    \"\",\n    \"Create a branch following the naming convention:\",\n    \"```bash\",\n    \"git checkout -b <type>/<issue-number>-<slug>\",\n    \"```\",\n    \"\",\n    \"The slug should be a short (3-5 word) kebab-case summary derived from the issue title.\",\n    \"\",\n    \"Link the branch to the issue:\",\n    \"```bash\",\n    \"gh issue comment <number> --body 'Branch: `<branch-name>`'\",\n    \"```\",\n    \"\",\n    \"## Phase 4: Implement\",\n    \"\",\n    \"**Feedback mode:** Read PR comments and apply the reviewer's fix list.\",\n    \"\",\n    \"1. List the PR's issue comments newest-first and pick the **most recent**\",\n    \"   comment authored by the reviewer account that contains a fenced\",\n    \"   code block with the language tag `fix-list`:\",\n    \"\",\n    \"   ```bash\",\n    \"   gh pr view <pr-number> --json comments\",\n    \"   ```\",\n    \"\",\n    \"2. Extract the JSON body of the ` ```json fix-list ` block. The reviewer\",\n    \"   writes the comment in this exact shape:\",\n    \"\",\n    \"   ````markdown\",\n    \"   ## Reviewer: fix list for @issue-worker\",\n    \"\",\n    \"   - [ ] @<author> — <instruction summary> (<file>:<line>)\",\n    \"\",\n    \"   ```json fix-list\",\n    \"   {\",\n    '     \"pr\": 123,',\n    '     \"branch\": \"feat/42-add-foo\",',\n    '     \"generated_at\": \"2026-04-16T14:02:00Z\",',\n    '     \"items\": [',\n    '       {\"comment_id\": \"IC_abc\", \"author\": \"alice\", \"file\": \"src/foo.ts\", \"line\": 42, \"instruction\": \"rename getFoo to fetchFoo\"},',\n    '       {\"comment_id\": \"IC_def\", \"author\": \"bob\",   \"file\": \"src/foo.test.ts\", \"instruction\": \"add a test for the null branch\"}',\n    \"     ]\",\n    \"   }\",\n    \"   ```\",\n    \"   ````\",\n    \"\",\n    \"   The JSON block is the **authoritative** list of work — the checkbox\",\n    \"   summary above it is for humans only and must be ignored. If multiple\",\n    \"   reviewer-authored fix-list comments exist, use the most recent one.\",\n    \"   If the JSON cannot be parsed, abort and report failure.\",\n    \"\",\n    \"3. Apply each `items[].instruction` in order. Each item references a\",\n    \"   `file` (and optional `line`). Track `comment_id` per item so you can\",\n    \"   report which items were handled and which (if any) failed.\",\n    \"\",\n    \"   **Synthetic rebase items.** Two `comment_id` values flag the\",\n    \"   reviewer's signal that the PR's head branch is BEHIND the default\",\n    \"   branch with merge conflicts that `gh pr update-branch` could not\",\n    \"   resolve. For either item the work is **not** an editorial change\",\n    \"   — it is a merge of the default branch into the PR branch plus\",\n    \"   conflict resolution. The two ids select different recipes:\",\n    \"\",\n    \"   - `synthetic:rebase-behind-main` — generic conflict. Resolve\",\n    \"     each conflicting file by hand (read both sides, reconcile,\",\n    \"     stage), then `git commit --no-edit` to complete the merge\",\n    \"     commit.\",\n    \"   - `synthetic:rebase-shared-index` — every conflicting file is a\",\n    \"     row-insert race on a shared-index file (registry / index /\",\n    \"     feature-matrix under a Starlight content root). Apply the\",\n    \"     explicit re-insert recipe carried in the item's `instruction`\",\n    \"     field — do **not** hand-merge.\",\n    \"\",\n    \"   **Marker name vs. operation.** The `comment_id` values keep their\",\n    \"   historical `rebase` spelling as a **stable identifier** the\",\n    \"   reviewer and worker agree on across sessions — the operation they\",\n    \"   select is a **merge** of the default branch into the PR branch,\",\n    \"   **not** a rebase. The PR branch is already pushed and diverged,\",\n    \"   so a rebase would rewrite its published history and require a\",\n    \"   `--force-with-lease` push that rule 8 forbids. A merge commit is\",\n    \"   fast-forward-pushable with a plain `git push`.\",\n    \"\",\n    \"   **For `synthetic:rebase-behind-main`.** Run the following\",\n    \"   sequence:\",\n    \"\",\n    \"   ```bash\",\n    \"   git fetch origin\",\n    \"   git merge --no-edit origin/{{repository.defaultBranch}}\",\n    \"   ```\",\n    \"\",\n    \"   When the merge produces conflicts, resolve each conflicting file\",\n    \"   in turn (read both sides — `<<<<<<< HEAD` is this PR's change,\",\n    \"   `>>>>>>> origin/{{repository.defaultBranch}}` is the default\",\n    \"   branch's — reconcile, stage), then run `git commit --no-edit` to\",\n    \"   complete the merge commit. Do not run `git merge --abort` to give\",\n    \"   up casually — aborting drops the work the reviewer delegated.\",\n    \"   Abort **only** as the failure path: if you genuinely cannot\",\n    \"   resolve a conflict (the change is editorial enough that it\",\n    \"   requires human judgement, or the conflict touches a generated\",\n    \"   file you should not hand-edit), record the item as `failed` with\",\n    \"   a clear reason, run `git merge --abort`, and proceed to the\",\n    \"   report step. Do not force-push.\",\n    \"\",\n    \"   When the merge completes cleanly, treat the merge commit itself\",\n    \"   as the deliverable. Skip the conventional commit step in Phase 6\",\n    \"   for this item — the merge already produced the commit. Push with\",\n    \"   a regular non-force `git push origin <branch>` (the merge commit\",\n    \"   is fast-forward-pushable, so no force-push is needed) and report\",\n    \"   the merged head SHA as the worker's commit.\",\n    \"\",\n    \"   **For `synthetic:rebase-shared-index`.** Apply the typed\",\n    \"   re-insert recipe step-by-step. Read the recipe verbatim from the\",\n    \"   item's `instruction` field; the steps below summarise the\",\n    \"   contract the reviewer encodes and the precondition guards you\",\n    \"   must enforce:\",\n    \"\",\n    \"   1. **Fetch and merge** the default branch into the PR branch:\",\n    \"\",\n    \"      ```bash\",\n    \"      git fetch origin\",\n    \"      git merge --no-edit origin/{{repository.defaultBranch}}\",\n    \"      ```\",\n    \"\",\n    \"   2. **For each conflicting file**, inspect the conflict markers\",\n    \"      against the shared-index glob set and the precondition\",\n    \"      guards. The shared-index globs (sourced from the\",\n    \"      `shared-editing-safety` rule) are:\",\n    \"\",\n    ...DEFAULT_SHARED_INDEX_PATHS.map((p) => `      - \\`${p}\\``),\n    \"\",\n    \"      **Precondition guards.** Before re-inserting, confirm every\",\n    \"      `<<<<<<<` / `=======` / `>>>>>>>` hunk in the file touches\",\n    \"      only data rows (lines starting with `| ` that are not the\",\n    \"      table header or `|---|---|` separator). If any hunk touches\",\n    \"      the frontmatter (lines between the opening / closing `---`\",\n    \"      fences), the page H1, surrounding prose paragraphs, the\",\n    \"      table header row, or the separator row, **stop**, run\",\n    \"      `git merge --abort`, and record the item as `failed` with\",\n    \"      the structured marker `BLOCKED <reason>` (e.g.\",\n    \"      `BLOCKED conflict touches table header in <path>`). Do not\",\n    \"      hand-merge — the typed recipe applies only to pure\",\n    \"      row-insert races.\",\n    \"\",\n    \"      When the guards pass, resolve the conflict in place: the\",\n    \"      `<<<<<<< HEAD` side carries this PR's row and the\",\n    \"      `>>>>>>> origin/{{repository.defaultBranch}}` side carries\",\n    \"      the other PR's row. Extract this PR's row and re-insert\",\n    \"      that row in declared sort order alongside the other PR's row\",\n    \"      using the file's documented sort key (alphabetical on the\",\n    \"      first column by default) so both rows survive, remove the\",\n    \"      conflict markers, and stage the file:\",\n    \"\",\n    \"      ```bash\",\n    \"      git add <path>\",\n    \"      ```\",\n    \"\",\n    \"   3. **Run the commit-path verification** for each re-inserted\",\n    \"      row. The marker must appear exactly once in the staged file\",\n    \"      (zero means missing, more than one means duplicated by a\",\n    \"      mis-merge):\",\n    \"\",\n    \"      ```bash\",\n    '      count=$(git show :<path> | grep -Fc \"<row-unique-marker>\")',\n    '      [ \"$count\" = \"1\" ] || { echo \"BLOCKED verification failed for <path>\"; exit 1; }',\n    \"      ```\",\n    \"\",\n    \"   4. **Complete the merge and push** with a plain non-force push\",\n    \"      once every file is staged and verified (the merge commit is\",\n    \"      fast-forward-pushable, so no force-push is needed):\",\n    \"\",\n    \"      ```bash\",\n    \"      git commit --no-edit\",\n    \"      git push origin <branch>\",\n    \"      ```\",\n    \"\",\n    \"   On any `BLOCKED` precondition failure, exit non-zero with the\",\n    \"   `BLOCKED <reason>` line, run `git merge --abort`, record the\",\n    \"   item as `failed`, and proceed to the report step. The reviewer\",\n    \"   will see the `failed` outcome on the next pass and fall through\",\n    \"   to the human-required hand-off via `review:awaiting-human`. Do\",\n    \"   not force-push under any circumstance.\",\n    \"\",\n    \"4. When complete, prepare a short structured report (PR number, commit\",\n    \"   SHAs you will push, items handled by `comment_id`, items that failed\",\n    \"   to apply) — you will return this after Phase 6.\",\n    \"\",\n    \"**Normal mode:**\",\n    \"\",\n    \"Read the issue body carefully. Understand the acceptance criteria.\",\n    \"\",\n    \"Implement the change following these guidelines based on issue type:\",\n    \"\",\n    \"- **feat**: Implement the new feature. Add tests. Export public APIs from `index.ts`.\",\n    \"- **fix**: Reproduce the bug first. Write a failing test. Fix the bug. Verify the test passes.\",\n    \"- **chore**: Make the maintenance change. Verify no regressions.\",\n    \"- **refactor**: Restructure code without changing behavior. Existing tests must pass unchanged.\",\n    \"- **docs**: Update documentation only. Do not change source code.\",\n    \"\",\n    \"Follow all conventions from CLAUDE.md and the project's agent rules.\",\n    \"\",\n    \"## Phase 5: Verify\",\n    \"\",\n    \"Run the appropriate verification commands depending on what changed:\",\n    \"\",\n    \"1. If Projen config was changed: run the three-step regen sequence `pnpm i && pnpm exec projen && pnpm i` (leading `pnpm i` syncs `node_modules` with the lockfile so synth runs against the right configulator/projen/plugin versions; trailing `pnpm i` refreshes the lockfile after synth)\",\n    \"2. Compile the affected package: `pnpm --filter @codedrifters/<package> compile`\",\n    \"3. Test the affected package: `pnpm --filter @codedrifters/<package> test`\",\n    \"4. If changes span multiple packages: `pnpm build:all`\",\n    \"\",\n    \"Fix any compilation errors, test failures, or lint errors before proceeding.\",\n    \"\",\n    \"## Phase 6: Commit and Push\",\n    \"\",\n    \"**If you are in interactive mode, pause here.** Before running any `git\",\n    \"commit`, present the user with a summary of the proposed changes:\",\n    \"\",\n    \"```bash\",\n    \"git status\",\n    \"git diff --stat\",\n    \"```\",\n    \"\",\n    \"Then state the conventional commit message you intend to use and ask for\",\n    \"explicit approval to commit, push, and open the PR. Do **not** proceed to\",\n    \"`git commit` until the user replies with an affirmative response (e.g.,\",\n    '\"yes\", \"approved\", \"go ahead\"). If the user requests changes, address',\n    \"them and ask again.\",\n    \"\",\n    \"**If you are in scheduled mode, skip the pause and proceed directly.**\",\n    \"\",\n    \"**Feedback mode:** Use a `fix(review)` commit message that references\",\n    \"the PR number, and push to the existing branch **without** `-u` (the\",\n    \"branch is already tracking origin). Before pushing, re-run\",\n    \"`git pull --rebase origin <branch-name>` to incorporate any commits\",\n    \"that landed on the branch while you were working. **Never force-push.**\",\n    \"If the rebase conflicts, abort and report failure.\",\n    \"\",\n    \"```bash\",\n    \"git add <files>\",\n    'git commit -m \"fix(review): <summary> (PR #<pr-number>)\"',\n    \"git pull --rebase origin <branch-name>\",\n    \"git push origin <branch-name>\",\n    \"```\",\n    \"\",\n    \"**Synthetic rebase items skip the `fix(review)` commit.** When the\",\n    \"fix-list contained a `comment_id` of `synthetic:rebase-behind-main`\",\n    \"or `synthetic:rebase-shared-index` and you completed the merge in\",\n    \"Phase 4, the merge commit is itself the deliverable — there is no\",\n    \"per-item editorial change to wrap in a `fix(review)` commit. The\",\n    \"merge commit already exists from Phase 4, so skip the `git add` /\",\n    '`git commit -m \"fix(review)...\"` / `git pull --rebase` editorial',\n    \"steps for that item and push the merged branch directly:\",\n    \"\",\n    \"```bash\",\n    \"git push origin <branch-name>\",\n    \"```\",\n    \"\",\n    \"If the fix-list mixed a synthetic rebase item with editorial items,\",\n    \"perform the editorial commit first (the merge already preceded it\",\n    \"in Phase 4), then push once at the end.\",\n    \"\",\n    \"**Normal mode:** Use conventional commit messages and push with `-u`\",\n    \"to set up branch tracking:\",\n    \"\",\n    \"```bash\",\n    \"git add <files>\",\n    'git commit -m \"<type>: <description>\"',\n    \"git push -u origin <branch-name>\",\n    \"```\",\n    \"\",\n    \"## Phase 6.5: Complete the Feedback Hand-off (MANDATORY, ATOMIC)\",\n    \"\",\n    \"**Normal mode:** Skip this phase entirely.\",\n    \"\",\n    \"**Feedback mode — the invariant.** A successful Phase 6 push is **not**\",\n    \"the end of the unit of work. **If you pushed in feedback mode, the unit\",\n    \"of work is NOT complete until `complete-feedback-handoff.sh` returns\",\n    \"0.** The git push and the hand-off are a single atomic step: the marker\",\n    \"must be cleared and the worker-report posted in the **same session** as\",\n    \"the push. A clean push that leaves `review:needs-worker` set and posts\",\n    \"no report double-wedges the PR — the reviewer's confirm pass never\",\n    \"fires (the marker is still present) and stale-lease reclaim never fires\",\n    \"(it requires the marker absent). Never stop, hand back to the caller,\",\n    \"or move to any optional/secondary step until the procedure has exited 0.\",\n    \"\",\n    \"**This is the FIRST action after a successful push** — before any\",\n    \"summary, log line, or secondary step. Call the deterministic procedure\",\n    \"with the PR number, the commit SHA you pushed (or the merged head SHA\",\n    \"for a synthetic rebase item), and the per-item outcomes JSON array:\",\n    \"\",\n    \"```bash\",\n    \".claude/procedures/complete-feedback-handoff.sh <pr-number> <commit-sha> '<items-json>'\",\n    \"```\",\n    \"\",\n    \"The `<items-json>` argument is a JSON array of per-item outcomes keyed\",\n    \"by the fix-list `comment_id` — one entry per item you applied in Phase\",\n    '4, each `{\"comment_id\": \"<id>\", \"outcome\": \"applied\"|\"failed\",',\n    '   \"detail\": \"<short reason on failure>\"}`:',\n    \"\",\n    \"```json\",\n    \"[\",\n    '  {\"comment_id\": \"IC_abc\", \"outcome\": \"applied\", \"detail\": \"\"},',\n    '  {\"comment_id\": \"IC_def\", \"outcome\": \"failed\", \"detail\": \"test still red\"}',\n    \"]\",\n    \"```\",\n    \"\",\n    \"The procedure performs **both** halves of the hand-off in one call and\",\n    \"exits non-zero on any failure:\",\n    \"\",\n    \"1. **Posts the structured `## Worker report` comment** — the record the\",\n    \"   reviewer's confirm pass reads to react on source comments and\",\n    \"   re-evaluate AC/CI. It renders one checklist line per `comment_id`\",\n    \"   (`applied` / `failed`), the pushed commit SHA, and an overall\",\n    \"   outcome (`complete` when every item applied, `partial` when any\",\n    \"   failed).\",\n    \"2. **Removes the `review:needs-worker` marker** — leaving the\",\n    \"   `review:fixing` lease in place. Clearing the marker flips the PR\",\n    \"   into the lease-without-marker state the reviewer's confirm pass keys\",\n    \"   on.\",\n    \"\",\n    \"**Partial failure still clears the marker.** The worker-report is\",\n    \"ALWAYS posted and the marker ALWAYS cleared even when every item\",\n    \"`failed` (the procedure reports overall outcome `partial` and the\",\n    \"per-item failures by `comment_id`). The reviewer's confirm pass reacts\",\n    \"`thinking_face` on the failed items and falls through to the\",\n    \"human-required hand-off via `review:awaiting-human`. Leaving the marker\",\n    \"applied on a partial or total failure would wedge the PR, so the marker\",\n    \"is cleared unconditionally — never remove it yourself out-of-band and\",\n    \"never skip the procedure because items failed.\",\n    \"\",\n    \"If the procedure exits non-zero (e.g. the comment post or the label\",\n    \"removal failed), the hand-off did **not** complete — retry it. Do not\",\n    \"treat the pushed commit as a finished unit of work until the procedure\",\n    \"returns 0.\",\n    \"\",\n    \"Do **not** remove `review:fixing` yourself, and do **not** re-enable\",\n    \"auto-merge — both belong to the reviewer's confirm pass.\",\n    \"\",\n    \"## Phase 7: Open a PR\",\n    \"\",\n    \"**Feedback mode:** Skip this phase entirely. The PR already exists; you\",\n    \"have pushed additional commits to its existing branch. Do not open a new\",\n    \"PR.\",\n    \"\",\n    \"**Normal mode:**\",\n    \"\",\n    \"Every PR you open must carry the `origin:issue-worker` label so downstream\",\n    \"agents can identify bot-authored PRs. Always include\",\n    \"`--label 'origin:issue-worker'` in the `gh pr create` invocation:\",\n    \"\",\n    \"```bash\",\n    'gh pr create --title \"<type>(<scope>): <description>\" \\\\',\n    \"  --label 'origin:issue-worker' \\\\\",\n    '  --body \"## Summary',\n    \"\",\n    \"<bullet points>\",\n    \"\",\n    'Closes #<issue-number>\"',\n    \"```\",\n    \"\",\n    \"**One closing keyword per issue, each on its own line.** GitHub honours\",\n    \"only one issue reference per keyword, so `Closes #A, #B` closes `#A` and\",\n    \"leaves `#B` open forever — the same is true of `Closes #A / #B` and\",\n    \"`Closes #A and #B`. A PR that closes several issues repeats the keyword:\",\n    \"\",\n    \"```\",\n    \"Closes #<first-issue-number>\",\n    \"Closes #<second-issue-number>\",\n    \"```\",\n    \"\",\n    \"Verify it mechanically before moving on — this exits non-zero and names\",\n    \"every issue the body would strand:\",\n    \"\",\n    \"```bash\",\n    \".claude/procedures/check-closing-keywords.sh <pr-number>\",\n    \"```\",\n    \"\",\n    \"If it reports `CLOSING_KEYWORDS_MALFORMED`, fix the body with\",\n    \"`gh pr edit <pr-number> --body-file <path>` and re-run until it exits\",\n    \"`0`. See the **Closing Keywords** section of the `pr-workflow` rule.\",\n    \"\",\n    \"Do **not** enable auto-merge yourself. The `pr-reviewer` sub-agent owns\",\n    \"review and merge for every PR — it verifies the diff against the issue's\",\n    \"acceptance criteria and enables squash auto-merge only when all checks\",\n    \"pass. Record the new PR number so a reviewer can be invoked next.\",\n    \"\",\n    \"## Phase 8: Update Status\",\n    \"\",\n    \"**Feedback mode:** Skip this phase entirely. The linked issue stays in\",\n    \"`status:in-progress` while the PR is still open — do not toggle any\",\n    \"labels.\",\n    \"\",\n    \"**Normal mode:**\",\n    \"\",\n    \"After the PR is created, transition the issue to the review phase:\",\n    \"```bash\",\n    'gh issue edit <number> --remove-label \"status:in-progress\" --add-label \"status:ready-for-review\"',\n    \"```\",\n    \"\",\n    \"Do **not** set `status:done` here — the `pr-reviewer` sub-agent is\",\n    \"responsible for that transition once the PR successfully merges.\",\n    \"\",\n    \"## Phase 9: Branch Cleanup\",\n    \"\",\n    \"**Feedback mode:** Skip this phase entirely. Do not poll the PR state\",\n    \"and do not delete the local branch. You have already posted the\",\n    \"structured worker-report comment and cleared `review:needs-worker` in\",\n    \"Phase 6.5 — the pr-reviewer's confirm pass picks up the hand-off from\",\n    \"the lease-without-marker label state. Return control to the caller\",\n    \"with the same structured report (PR number, commit SHAs pushed, items\",\n    \"handled by `comment_id`, items that failed to apply) so a pushing\",\n    \"orchestrator can log it.\",\n    \"\",\n    \"**Normal mode:**\",\n    \"\",\n    \"The PR will not auto-merge until the `pr-reviewer` enables it. Poll the PR\",\n    \"state up to 10 times, waiting 30 seconds between polls, until it either\",\n    \"merges, closes, or the timeout is reached:\",\n    \"\",\n    \"```bash\",\n    \"gh pr view <pr-number> --json state --jq '.state'\",\n    \"```\",\n    \"\",\n    \"- **If the state becomes `MERGED`:** clean up the local branch.\",\n    \"  ```bash\",\n    \"  git checkout {{repository.defaultBranch}}\",\n    \"  git pull origin {{repository.defaultBranch}}\",\n    \"  git branch -D <branch-name>\",\n    \"  ```\",\n    \"- **If the state becomes `CLOSED` (not merged):** leave the branch in place\",\n    \"  and report that the PR was closed without merging. Do not delete the branch.\",\n    \"- **If still `OPEN` after the polling window:** report that the PR is\",\n    \"  awaiting review/merge and stop. Do not delete the branch.\",\n    \"\",\n    \"---\",\n    \"\",\n    \"## Rules\",\n    \"\",\n    \"1. **One issue per session.** Process exactly ONE issue, then stop.\",\n    \"2. **Use check-blocked.sh.** Always use the procedure script for issue selection.\",\n    \"3. **Follow CLAUDE.md conventions** for branch naming, commits, and PRs.\",\n    \"4. **Do not assign PRs to a project board** — this repo has no GitHub project.\",\n    \"5. **Do not add AI co-author** attribution to commits.\",\n    \"6. **Always label PRs with `origin:issue-worker`.** Every PR opened by\",\n    \"   the issue-worker must carry the `origin:issue-worker` label so\",\n    \"   downstream agents (notably the `pr-reviewer`) can identify\",\n    \"   bot-authored PRs. Pass `--label 'origin:issue-worker'` on every\",\n    \"   `gh pr create` call.\",\n    \"7. **On failure:** If you cannot complete the issue (including a\",\n    \"   wrong-agent / routing mismatch), flag it for human triage and\",\n    \"   leave a comment. **Add** `status:needs-attention` with\",\n    \"   `--add-label` alone — do **not** remove the base\",\n    \"   `status:in-progress` label. `status:needs-attention` is\",\n    \"   additive, so the flagged issue reads `status:in-progress` +\",\n    \"   `status:needs-attention` and keeps a base status a human can act\",\n    \"   on; stripping it leaves the issue with no base `status:*` label,\",\n    \"   invisible to every status-driven query:\",\n    \"   ```bash\",\n    '   gh issue edit <number> --add-label \"status:needs-attention\"',\n    '   gh issue comment <number> --body \"Worker could not complete: <reason>\"',\n    \"   ```\",\n    \"8. **Never force-push in feedback mode.** If a `git pull --rebase`\",\n    \"   produces conflicts, abort and report failure. Do not pass\",\n    \"   `--force` or `--force-with-lease` to `git push`.\",\n    \"9. **Abort if the PR is not OPEN in feedback mode.** Before checking\",\n    \"   out the head branch, verify `gh pr view <pr> --json state` returns\",\n    \"   `OPEN`. If the state is `MERGED` or `CLOSED`, stop immediately —\",\n    \"   do not modify the branch.\",\n    \"10. **Use the most-recent reviewer-authored fix-list comment.** If\",\n    \"    multiple `fix-list` comments exist on the PR, use the most recent\",\n    \"    one authored by the reviewer account. Ignore older fix-list\",\n    \"    comments and any fix-list comments authored by other accounts.\",\n    \"11. **Never create a new branch in feedback mode.** Always check out\",\n    \"    the existing PR head branch returned by `gh pr view`. Do not run\",\n    \"    `git checkout -b` while in feedback mode.\",\n    \"12. **Never `git push -u` in feedback mode.** The existing PR branch\",\n    \"    already tracks origin. Use plain `git push origin <branch-name>`.\",\n    \"13. **Respect the funnel-tier sort.** Never re-order the `PICK` lines\",\n    \"    emitted by `check-blocked.sh eligible`. The first line is the next\",\n    \"    work item by **priority desc → funnel tier asc → issue number asc**.\",\n    \"    See the **Funnel-tier dispatch ordering** section in `CLAUDE.md`\",\n    \"    for the tier table.\",\n    \"14. **Refuse `large`-scope issues.** Before claiming an issue, run\",\n    \"    `.claude/procedures/check-blocked.sh scope <number>` and stop\",\n    \"    with a `BLOCKED_ON_SCOPE` report if the classifier returns\",\n    \"    `large`. Never claim, branch, or implement a `large` issue —\",\n    \"    the orchestrator must decompose it first. See the **Scope gate**\",\n    \"    section in `CLAUDE.md` for the contract.\",\n    \"15. **Prefer feedback PRs over fresh issues (scheduled mode).** When\",\n    \"    running autonomously, scan open PRs for the `review:needs-worker`\",\n    \"    marker **before** scanning the issue queue, and pick up the\",\n    \"    highest-priority unconsumed fix-list first. A half-finished PR\",\n    \"    should land before a new unit of work starts. The explicit\",\n    \"    `feedback mode: PR #<n>` push always overrides both scans.\",\n    \"16. **Complete the hand-off atomically; clear `review:needs-worker`,\",\n    \"    never `review:fixing`.** A successful feedback-mode push is not a\",\n    \"    finished unit of work until the hand-off completes. As the FIRST\",\n    \"    action after the push (Phase 6.5), run\",\n    \"    `.claude/procedures/complete-feedback-handoff.sh <pr> <commit-sha>\",\n    \"    '<items-json>'`, which posts the structured worker-report comment\",\n    \"    and removes **only** the `review:needs-worker` marker in one call,\",\n    \"    exiting non-zero on any failure. The unit of work is **not**\",\n    \"    complete until it returns 0. The `review:fixing` lease belongs to\",\n    \"    the reviewer's confirm pass — never remove it yourself, and never\",\n    \"    re-enable auto-merge. The procedure clears the marker even when\",\n    \"    every item failed (overall outcome `partial`), so a partial or\",\n    \"    crashed delegation does not wedge the PR.\",\n    \"17. **Auto-pull only in scheduled mode.** The autonomous\",\n    \"    `review:needs-worker` scan is scheduled-mode only. In an\",\n    \"    interactive session, never auto-pull a feedback PR — a human who\",\n    \"    wants one fixed passes `feedback mode: PR #<n>` explicitly.\",\n  ].join(\"\\n\"),\n};\n\n/*******************************************************************************\n *\n * Orchestrator conventions rule — content includes the default tier\n * table. `AgentConfig.preSynthesize` replaces this content with a\n * tier-aware version when consumers supply `options.tiers`.\n *\n ******************************************************************************/\n\nconst ORCHESTRATOR_CONVENTIONS_PREAMBLE = [\n  \"# Orchestrator Conventions\",\n  \"\",\n  \"When running the orchestrator agent (`.claude/agents/orchestrator.md`):\",\n  \"\",\n  \"- The orchestrator runs **one full end-to-end cycle every invocation**: startup → PR review sweep → feedback drain → triage / unblock → maintenance → queue scan → delegate to `issue-worker` → cleanup\",\n  \"- The orchestrator **never** implements code, creates branches, or pushes commits — it routes work to other sub-agents. Its **only** issue mutation is the claim-at-pick label flip (Phase E, see below). The merge decision is still owned by the `pr-reviewer` sub-agent; Phase B only chooses which open PRs the reviewer should look at and dispatches one reviewer session per eligible PR (skipping drafts, any PR carrying `review:human-required` or `review:awaiting-human`, and any PR with a review already in flight).\",\n  \"- **Fleet anti-collision.** When several orchestrator runners share one GitHub queue, two guards stop duplicate dispatch. **Claim-at-pick:** in Phase E, once the scope gate passes, the orchestrator re-reads the picked issue's labels (skipping to the next candidate if it is no longer `status:ready`), posts an `<!-- issue-claim -->` marker, and flips `status:ready` → `status:in-progress` itself **before** dispatching in Phase G — collapsing the window in which a sibling runner would re-pick the same issue. The Phase G dispatch brief tells the worker the label was pre-flipped so it does not treat the claim as foreign. **Review-in-flight:** `pr-sweep.sh review` skips (`reason=review-in-flight`) any PR whose newest `## Reviewer*` comment is younger than the review-in-flight window, so overlapping runners do not both dispatch a reviewer on the same PR. The dispatched `issue-worker` and every phased analyst carry a matching **Claim verification** backstop that verifies claim ownership by issue-claim-marker ordering and backs off without writing artifacts on a foreign prior claim.\",\n  \"- **Phase B produces `review:needs-worker` markers; Phase B1 consumes them.** Phase B's `pr-reviewer` dispatch leaves a durable `review:needs-worker` marker whenever it delegates a fix-list (it cannot spawn the worker in session — it may run at depth-1). Phase B1 (feedback drain) actively drains that queue every cycle: it dispatches a top-level `issue-worker` per open `review:needs-worker` PR — highest-priority first, looping until the queue is empty — to consume the reviewer's fix-list. **Feedback PRs are preferred over fresh issues**, so Phase B1 runs after the review sweep but before the queue scan (Phase E) and fresh delegation (Phase G). A PR that also carries the `review:fixing` lease still drains **unless a worker is demonstrably active** — the reviewer acquires the lease and applies the marker in one atomic pass and holds the lease across sessions, so the bare lease does not mean a worker is running. The drain judges 'active' with the same `delegation_active_signals` helper the maintenance lease-reconcile uses: it skips only when there is no reviewer fix-list (`reason=no-fixlist`), a worker-report already landed (`reason=reported`), or the branch HEAD advanced past the fix-list (`reason=in-flight`); otherwise the delegated-but-idle PR drains so its FIRST worker gets dispatched.\",\n  \"- All triage queries use `.claude/procedures/check-blocked.sh` for token efficiency. PR-eligibility filtering for Phase B uses `.claude/procedures/pr-sweep.sh review`, which emits `PR_ELIGIBLE` / `PR_SKIP reason=<draft|human-required|awaiting-human|review-in-flight>` lines; the Phase B1 feedback-drain enumeration uses `.claude/procedures/pr-sweep.sh needs-worker`, which emits `PR_DRAIN` / `PR_SKIP reason=<no-fixlist|reported|in-flight>` lines. The orchestrator never iterates raw `gh pr list` JSON.\",\n  \"- The queue scan reads only `priority:*` and `status:*` labels — type-routing (which typed agent handles a given `type:*` label) is the `issue-worker`'s concern, not the orchestrator's. The orchestrator's funnel-tier sort is a tie-breaker on `priority:*`, not a routing decision.\",\n  \"- Priority order: critical > high > medium > low > trivial, then **funnel tier asc** (lower tier wins ties), then FIFO by issue number. Phase E's queue scan walks each priority bucket in turn (one `gh issue list` call per bucket, **capped at 50 issues per bucket**) and short-circuits on the first bucket whose survivors clear the `Depends on:` filter, so every higher-priority issue is visible even when the global ready backlog is much larger than 50.\",\n  \"- Stale thresholds: 72h for in-progress, 168h for blocked\",\n  \"- Flagged issues get `status:needs-attention` — they are not auto-reset\",\n  \"- **Phase D auto-reconciles stuck PR leases.** The maintenance sweep's `check-blocked.sh maintenance` invocation folds in a PR-lease reconcile that unwedges `review:fixing` PRs the Phase B1 drain and the worker hand-off left stuck, emitting a `LEASE_RECONCILE orphaned=<N> consumed_uncleared=<M>` line alongside `MAINTENANCE_DONE`. An **orphaned lease** (`review:fixing` without `review:needs-worker`, fix-list older than the 72h stale threshold, no worker-report newer than the fix-list) is **re-armed** — the sweep re-applies `review:needs-worker` so the Phase B1 drain retries the delegation, leaving the lease untouched. A **consumed-but-uncleared wedge** (both labels present, branch HEAD newer than the fix-list, no worker-report — the worker pushed but skipped the hand-off) is **auto-reconciled** — the sweep removes `review:needs-worker` so the reviewer confirm pass can merge. Both paths post an audit-trail note comment; a lease is never silently force-released, and the `review:fixing` lease itself is always left for the reviewer confirm pass to release.\",\n  \"- **Phase D enforces the phase-label → `type:<bundle>` invariant.** The same maintenance sweep folds in a label-invariant pass that auto-corrects open issues carrying a pipeline phase label without the matching `type:<bundle>` label, emitting a `LABEL_INVARIANT_DONE mode=fix checked=<N> ok=<O> violations=<V> corrected=<C> flagged=<F>` line alongside `MAINTENANCE_DONE`. The correction **replaces** a shadowing conventional-commit `type:*` rather than merely adding the bundle type, so the issue keeps exactly one `type:*` and Phase E's funnel-tier sort key stays deterministic. Ambiguous pairings and collisions with another bundle's `type:*` label are **flagged** `status:needs-attention` (additively) instead of guessed at. See the **Phase-label → `type:<bundle>` invariant** section below for the matcher table and the full correction policy.\",\n  \"\",\n  \"## Depth-0 invocation requirement\",\n  \"\",\n  'The orchestrator agent **must run as the top-level (depth-0) session** because Phase B (PR review sweep), Phase B1 (feedback drain), and Phase G (issue delegation) all need to spawn child sub-agents. Phase B dispatches the `pr-reviewer` sub-agent once per eligible open PR; Phase B1 dispatches the `issue-worker` sub-agent once per open `review:needs-worker` PR to consume the reviewer\\'s fix-list; Phase G dispatches the `issue-worker` sub-agent against the picked issue. The Claude Code harness forbids nested sub-agent spawning — *\"Subagents cannot spawn other subagents. If your workflow requires nested delegation, use Skills or chain subagents from the main conversation.\"* (see <https://code.claude.com/docs/en/sub-agents>). If the orchestrator itself were spawned as a depth-1 sub-agent (e.g. via `Agent(subagent_type: \"orchestrator\")` from another session), the `Agent` tool needed to reach `pr-reviewer` and `issue-worker` at depth-2 would not be available and Phase B, Phase B1, and Phase G would all silently abort. Phase B1 is precisely why the reviewer\\'s pull-based hand-off works: the depth-1 reviewer leaves a durable `review:needs-worker` marker, and the depth-0 orchestrator — which *can* spawn the worker — drains it.',\n  \"\",\n  'Practical implication for scheduled-task wiring: the `worker-orchestrator` scheduled task\\'s `SKILL.md` instructs the **scheduled-task session itself** to read `.claude/agents/orchestrator.md` and execute its phase pipeline in-session, then use the `Agent` tool to delegate to `pr-reviewer` (Phase B) and `issue-worker` (Phase B1 and Phase G) at depth-1. The scheduled task does **not** call `Agent(subagent_type: \"orchestrator\")` — that would put the orchestrator at depth-1 and break all three delegation chains.',\n].join(\"\\n\");\n\n/**\n * Build the orchestrator-conventions rule content for a given resolved\n * tier table, scope gate, scheduled-tasks, and unblock-dependents\n * config. The preamble is constant; each section below it is rendered\n * from the supplied values so consumer overrides propagate into the\n * generated rule.\n *\n * Every optional parameter defaults to the bundle's built-in default\n * when the caller omits it.\n *\n * The `runRatio` parameter is retained for API compatibility but is\n * no longer rendered into the conventions content — the orchestrator\n * runs a single linear cycle on every invocation, so the\n * dispatch/housekeeping ratio convention was retired. See Phase B\n * (PR review sweep) in `.claude/agents/orchestrator.md` for the\n * replacement workflow.\n */\nexport function buildOrchestratorConventionsContent(\n  tiers: ReadonlyArray<ResolvedAgentTier>,\n  scopeGate: ResolvedScopeGate = resolveScopeGate(),\n  _runRatio: ResolvedRunRatio = resolveRunRatio(),\n  scheduledTasks: ResolvedScheduledTasks = resolveScheduledTasks(),\n  unblockDependents: ResolvedUnblockDependents = resolveUnblockDependents(),\n  excludeBundles: ReadonlyArray<string> = [],\n): string {\n  return [\n    ORCHESTRATOR_CONVENTIONS_PREAMBLE,\n    \"\",\n    renderAgentTierSection(tiers, excludeBundles),\n    \"\",\n    renderScopeGateSection(scopeGate, excludeBundles),\n    \"\",\n    renderPhaseTypeInvariantSection(excludeBundles),\n    \"\",\n    renderScheduledTasksSection(scheduledTasks),\n    \"\",\n    renderUnblockDependentsSection(unblockDependents),\n  ].join(\"\\n\");\n}\n\n/**\n * Resolve the orchestrator-conventions rule content and the\n * check-blocked.sh procedure content for a given (possibly absent)\n * consumer-supplied tier config, scope-gate config, run-ratio config,\n * and scheduled-tasks config. Called by `AgentConfig.preSynthesize`.\n *\n * Returns the resolved tier table, scope gate, run ratio, and\n * scheduled-tasks config alongside both rendered artifacts so callers\n * can splice them into their rule map and procedure map in a single\n * pass.\n *\n * The `runRatio` parameter is retained for API compatibility but no\n * longer feeds the rendered conventions content or the\n * `check-blocked.sh` script — the orchestrator runs a single linear\n * cycle on every invocation, so the run-counter / `tick` subcommand\n * were retired.\n */\nexport function resolveOrchestratorAssets(\n  tierConfig?: AgentTierConfig,\n  scopeGateConfig?: ScopeGateConfig,\n  runRatioConfig?: RunRatioConfig,\n  scheduledTasksConfig?: ScheduledTasksConfig,\n  unblockDependentsConfig?: UnblockDependentsConfig,\n  excludeBundles: ReadonlyArray<string> = [],\n): {\n  readonly tiers: ReadonlyArray<ResolvedAgentTier>;\n  readonly scopeGate: ResolvedScopeGate;\n  readonly runRatio: ResolvedRunRatio;\n  readonly scheduledTasks: ResolvedScheduledTasks;\n  readonly unblockDependents: ResolvedUnblockDependents;\n  readonly conventionsContent: string;\n  readonly procedure: AgentProcedure;\n  readonly unblockDependentsProcedure: AgentProcedure;\n} {\n  const tiers = resolveAgentTiers(tierConfig);\n  const scopeGate = resolveScopeGate(scopeGateConfig);\n  const runRatio = resolveRunRatio(runRatioConfig);\n  const scheduledTasks = resolveScheduledTasks(\n    scheduledTasksConfig,\n    excludeBundles,\n  );\n  const unblockDependentsResolved = resolveUnblockDependents(\n    unblockDependentsConfig,\n  );\n  return {\n    tiers,\n    scopeGate,\n    runRatio,\n    scheduledTasks,\n    unblockDependents: unblockDependentsResolved,\n    conventionsContent: buildOrchestratorConventionsContent(\n      tiers,\n      scopeGate,\n      runRatio,\n      scheduledTasks,\n      unblockDependentsResolved,\n      excludeBundles,\n    ),\n    procedure: buildCheckBlockedProcedure(tiers, scopeGate, runRatio),\n    unblockDependentsProcedure: buildUnblockDependentsProcedure(\n      unblockDependentsResolved,\n    ),\n  };\n}\n\n/*******************************************************************************\n *\n * Default slash commands\n *\n * Thin user-invokable wrappers that delegate to the existing orchestrator\n * sub-agent and check-blocked procedure. Each body is intentionally\n * terse — the full contract lives in the cited rule / agent / procedure.\n * Consumers can opt out individually via `excludeCommands` or drop the\n * whole orchestrator bundle via `excludeBundles`.\n *\n ******************************************************************************/\n\nconst orchestrateCommand: AgentCommand = {\n  name: \"orchestrate\",\n  description:\n    \"Run one full orchestrator cycle: triage, queue scan, delegate to issue-worker.\",\n  content: [\n    \"# Orchestrate\",\n    \"\",\n    \"Invoke the `orchestrator` sub-agent and run **one full end-to-end\",\n    \"cycle**: PR review sweep → feedback drain (drain every open\",\n    \"`review:needs-worker` PR through the `issue-worker`) → triage /\",\n    \"unblock → maintenance → queue scan → delegate the picked issue to\",\n    \"the `issue-worker` sub-agent → cleanup.\",\n    \"\",\n    \"Follow the contract in `.claude/agents/orchestrator.md`. Do **not**\",\n    \"implement code, create branches, push commits, or merge PRs — those\",\n    \"are the worker's and `pr-reviewer`'s jobs respectively.\",\n    \"\",\n    \"Run as a depth-0 (top-level) session so the orchestrator can spawn\",\n    \"the `issue-worker` sub-agent at depth-1 — Claude Code forbids nested\",\n    \"sub-agent dispatch.\",\n    \"\",\n  ].join(\"\\n\"),\n};\n\nconst checkBlockedCommand: AgentCommand = {\n  name: \"check-blocked\",\n  description:\n    \"Run .claude/procedures/check-blocked.sh and summarise the unblock candidates.\",\n  content: [\n    \"# Check Blocked\",\n    \"\",\n    \"Run the bundled triage helper and report what it found:\",\n    \"\",\n    \"```bash\",\n    'bash .claude/procedures/check-blocked.sh \"$@\"',\n    \"```\",\n    \"\",\n    \"Pass any extra arguments through verbatim. The `unblock` subcommand\",\n    \"walks every `status:blocked` issue, re-checks each `Depends on:`\",\n    \"reference, applies the `status:blocked` → `status:ready` label flip\",\n    \"itself, posts the canned `Dependencies resolved — unblocking.`\",\n    \"comment, and emits a single\",\n    \"`TRIAGE_DONE unblocked=<N> still_blocked=<M> deferred_skipped=<K>`\",\n    \"summary line. Candidates carrying `status:deferred` are skipped\",\n    \"rather than promoted — only a human clears that label. Per-issue\",\n    \"informational lines (`UNBLOCKED`, `UNBLOCK_FAILED`, `STILL_BLOCKED`,\",\n    \"`SKIP_DEFERRED`) are also emitted for log visibility.\",\n    \"\",\n    \"Summarise the output (the `TRIAGE_DONE` counts and the first few\",\n    \"per-issue lines) — do **not** apply additional label flips yourself;\",\n    \"the script already transitioned every eligible issue.\",\n    \"\",\n  ].join(\"\\n\"),\n};\n\nconst scanCommand: AgentCommand = {\n  name: \"scan\",\n  description:\n    \"Run the orchestrator queue scan only and report the next ready issue without dispatching.\",\n  content: [\n    \"# Scan\",\n    \"\",\n    \"Run the orchestrator's **queue scan only** (Phase E of the contract\",\n    \"in `.claude/agents/orchestrator.md`) and print the next ready issue,\",\n    \"the funnel-tier sort that put it on top, and the scope-gate result.\",\n    \"\",\n    \"Do **not** claim the issue, create a branch, or delegate to\",\n    \"`issue-worker`. This command exists for proactive review of what\",\n    \"the next `/orchestrate` invocation would pick up.\",\n    \"\",\n    \"Walk each `priority:*` bucket in turn (capped at 50 per bucket),\",\n    \"filter `Depends on:` references, and short-circuit on the first\",\n    \"bucket whose survivors clear the filter. Report the top candidate\",\n    \"and the number of survivors per bucket.\",\n    \"\",\n  ].join(\"\\n\"),\n};\n\n/*******************************************************************************\n *\n * Bundle definition\n *\n ******************************************************************************/\n\n/**\n * The parts of the orchestrator bundle that carry no consumer-resolved\n * configuration. Split out so `buildOrchestratorBundle` only has to\n * spell out the one dynamic surface (the conventions rule).\n */\nconst ORCHESTRATOR_BUNDLE_STATIC = {\n  subAgents: [orchestratorSubAgent, issueWorkerSubAgent],\n\n  procedures: [\n    checkBlockedProcedure,\n    unblockDependentsProcedure,\n    prSweepProcedure,\n    completeFeedbackHandoffProcedure,\n  ],\n\n  commands: [orchestrateCommand, checkBlockedCommand, scanCommand],\n\n  claudePermissions: {\n    allow: [\n      // Allow executing the check-blocked.sh procedure\n      \"Bash(.claude/procedures/*.sh *)\",\n    ],\n  },\n};\n\n/**\n * Fully-resolved settings that feed the `orchestrator-conventions`\n * rule. Every field is already resolved, so `buildOrchestratorBundle`\n * can seed the rule's final content up front rather than shipping\n * default content that a later pass has to rewrite.\n */\nexport interface ResolvedOrchestratorConventions {\n  readonly tiers: ReadonlyArray<ResolvedAgentTier>;\n  readonly scopeGate: ResolvedScopeGate;\n  readonly runRatio: ResolvedRunRatio;\n  readonly scheduledTasks: ResolvedScheduledTasks;\n  readonly unblockDependents: ResolvedUnblockDependents;\n\n  /**\n   * Bundle names the consumer excluded. Rows owned by an excluded\n   * bundle are dropped from the rendered tier table, scope-gate\n   * overrides, and scheduled-tasks registry.\n   */\n  readonly excludeBundles: ReadonlyArray<string>;\n}\n\n/**\n * The orchestrator-conventions settings the bundle ships when the\n * consumer supplies no override.\n */\nexport const DEFAULT_ORCHESTRATOR_CONVENTIONS: ResolvedOrchestratorConventions =\n  {\n    tiers: DEFAULT_AGENT_TIERS,\n    scopeGate: resolveScopeGate(),\n    runRatio: resolveRunRatio(),\n    scheduledTasks: resolveScheduledTasks(),\n    unblockDependents: resolveUnblockDependents(),\n    excludeBundles: [],\n  };\n\n/**\n * Build the `orchestrator` bundle with the consumer's resolved tier,\n * scope-gate, run-ratio, scheduled-tasks, and unblock-dependents\n * settings already baked into the `orchestrator-conventions` rule\n * content.\n *\n * Resolving here — rather than rewriting the rule after the rule map\n * has been assembled — is what lets a consumer's\n * `ruleExtensions[\"orchestrator-conventions\"]` append (or a same-name\n * `agentConfig.rules` entry) survive alongside a tier / scope-gate /\n * scheduled-tasks override. The two features compose because the rule\n * enters the map already carrying the consumer's resolved settings.\n *\n * When the argument is omitted the bundle ships with the documented\n * defaults baked in, identical to the `orchestratorBundle` const below.\n */\nexport function buildOrchestratorBundle(\n  conventions: ResolvedOrchestratorConventions = DEFAULT_ORCHESTRATOR_CONVENTIONS,\n): AgentRuleBundle {\n  return {\n    name: \"orchestrator\",\n    description:\n      \"Pipeline orchestrator agent for issue triage, PR review, and queue management\",\n\n    // Always included by default\n    appliesWhen: () => true,\n\n    rules: [\n      {\n        name: \"orchestrator-conventions\",\n        description:\n          \"Guidelines for orchestrator agent behavior and pipeline management, including the funnel-tier dispatch sort, scope gate, and per-agent scheduled-task layout\",\n        scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n        // Bundle defaults exclude paths into configulator's own source\n        // (only meaningful when configulator is a workspace package).\n        // codedrifters/packages restores them via\n        // `agentConfig.additionalRulePaths`.\n        filePatterns: [\n          \".claude/agents/orchestrator.md\",\n          \".claude/scheduled-tasks/**\",\n        ],\n        content: buildOrchestratorConventionsContent(\n          conventions.tiers,\n          conventions.scopeGate,\n          conventions.runRatio,\n          conventions.scheduledTasks,\n          conventions.unblockDependents,\n          conventions.excludeBundles,\n        ),\n        platforms: {\n          cursor: { exclude: true },\n        },\n        tags: [\"workflow\"],\n      },\n    ],\n    ...ORCHESTRATOR_BUNDLE_STATIC,\n  };\n}\n\n/**\n * Default-config instance of the orchestrator bundle, preserved for\n * backward compatibility with consumers that import the const\n * directly. The factory above is the canonical entry point when a\n * consumer supplies tier / scope-gate / scheduled-tasks overrides.\n */\nexport const orchestratorBundle: AgentRuleBundle = buildOrchestratorBundle();\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { renderClaimVerificationSection } from \"./claim-verification\";\nimport {\n  ISSUE_CLOSE_RULE_REFERENCE,\n  ISSUE_CLOSE_SECTION_TITLE,\n  renderIssueClosePolicySection,\n} from \"./issue-close\";\nimport {\n  DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n  ResolvedIssueDefaults,\n  labelsForPhase,\n} from \"./issue-defaults\";\nimport { renderIssueTypeAssignmentStep } from \"./issue-type\";\nimport { renderOriginStampSection } from \"./origin-label\";\nimport { DEFAULT_AGENT_PATHS, ResolvedAgentPaths } from \"./paths\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n  AGENT_MODEL,\n  AGENT_RULE_SCOPE,\n  AgentModel,\n  AgentSkill,\n  AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that researches and profiles individual people into\n * structured markdown. Produces one profile per person, maintains\n * cross-references to related companies, software, and meeting notes,\n * and enqueues downstream research issues for companies and software\n * products surfaced during profiling (handed off to the\n * `company-profile` and `software-profile` bundles).\n *\n * In addition to the initial research → draft → followup cycle, the\n * agent supports one maintenance phase:\n *\n * - `people:refresh` — re-verify an existing profile against a narrow\n *   set of facts (current role, employer, primary public channel) with\n *   a small number of targeted web searches and update it in place.\n *\n * The prompt deliberately avoids hardcoded domains, companies, or source\n * projects. Consumers configure the person-role taxonomy scope, output\n * paths, cross-reference targets, and refresh cadence via the skill\n * invocation and by extending the rule in their own `agentConfig.rules`.\n */\nfunction buildPeopleProfileAnalystSubAgent(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n  tier: AgentModel,\n): AgentSubAgent {\n  return {\n    name: \"people-profile-analyst\",\n    description:\n      \"Researches an individual person (colleague, customer contact, vendor contact, partner contact, industry expert, or connector) from public sources and produces a structured markdown profile cross-linked to companies, software, and meeting notes, then enqueues downstream `company:research` and `software:research` issues for unprofiled companies and software products surfaced during profiling. Also handles maintenance refreshes on a configurable staleness cadence (`people:refresh`). One person per session, tracked by people:* GitHub issue labels.\",\n    model: tier,\n    maxTurns: 80,\n    platforms: { cursor: { exclude: true } },\n    prompt: [\n      \"# People Profile Analyst Agent\",\n      \"\",\n      \"You research a single person from public sources and write a\",\n      \"structured markdown profile. Each profile cycle runs across a small\",\n      \"sequence of GitHub issues — one per phase — and produces a single\",\n      \"profile file on disk plus cross-references to related entities\",\n      \"(companies, software, meeting notes) already tracked elsewhere in\",\n      \"the project.\",\n      \"\",\n      \"This agent is **domain-neutral**. It makes no assumptions about what\",\n      \"the consuming project sells, which industry it serves, or which\",\n      \"people matter to it. All domain-specific vocabulary, output\",\n      \"locations, cross-reference targets, and profile-template overrides\",\n      \"come from the invoking issue body or the consuming project's\",\n      \"configuration.\",\n      \"\",\n      \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n      \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...PROJECT_CONTEXT_READER_SECTION,\n      \"## Design Principles\",\n      \"\",\n      \"1. **One person per session.** Never profile two people in a single\",\n      \"   session, even if they came up together (e.g. co-founders).\",\n      \"2. **Public sources only.** Use the person's own public writing,\",\n      \"   company bios, conference talks, public interviews, and similar\",\n      \"   public material. Do not attempt to access gated or paywalled\",\n      \"   content unless the invoking issue body explicitly authorizes it.\",\n      \"3. **Filesystem durability.** The profile file is the deliverable. It\",\n      \"   is committed to disk before the profile issue closes. Downstream\",\n      \"   phases read from disk — never rely on session memory.\",\n      \"4. **Generic over specific.** No hardcoded role types, taxonomies, or\",\n      \"   relationship assumptions. Use the generic person-role taxonomy\",\n      \"   below and let consuming projects override it.\",\n      \"5. **Cite everything.** Every non-trivial factual claim in the\",\n      \"   profile must carry a source citation (URL plus access date).\",\n      \"6. **Respect privacy.** Profile only public, professional information.\",\n      \"   Never capture home addresses, personal phone numbers, family\",\n      \"   details, health information, or other private data even when\",\n      \"   encountered in public sources.\",\n      \"7. **Cross-reference, don't duplicate.** When the profile mentions a\",\n      \"   company, software product, or meeting already tracked by the\",\n      \"   consuming project, link to the existing artifact rather than\",\n      \"   duplicating its content.\",\n      \"8. **Follow-up, don't widen scope.** If the session turns up adjacent\",\n      \"   research questions (a significant employer worth profiling, a\",\n      \"   software product the person created or leads), emit a follow-up\",\n      \"   issue rather than expanding the profile beyond its scope.\",\n      \"   Companies are handed off to the `company-profile` bundle via\",\n      \"   `company:research` issues; software products are handed off to\",\n      \"   the `software-profile` bundle via `software:research` issues.\",\n      \"   Meeting notes remain link-only — this agent never creates\",\n      \"   meeting-research issues.\",\n      \"9. **Refresh is targeted re-verification, not re-research.**\",\n      \"   `people:refresh` runs a small number of targeted searches focused\",\n      \"   on the narrow set of facts that drift (role, employer, primary\",\n      \"   public channel) and updates the profile in place. It never\",\n      \"   re-runs the full research-phase sweep and never forks the profile\",\n      \"   under a new slug.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Person Role Taxonomy\",\n      \"\",\n      \"Pick exactly one role per person profile. The taxonomy is\",\n      \"deliberately generic — consuming projects override it via\",\n      \"`agentConfig.rules` if they need a domain-specific refinement.\",\n      \"\",\n      \"| Role | Use for |\",\n      \"|------|---------|\",\n      \"| `colleague` | People inside your own organization worth tracking (teammates, cross-functional partners, leadership). |\",\n      \"| `customer-contact` | Named individuals at existing or prospective customer accounts. |\",\n      \"| `vendor-contact` | Named individuals at vendors, suppliers, or software providers you depend on. |\",\n      \"| `partner-contact` | Named individuals at strategic, channel, or integration partners. |\",\n      \"| `industry-expert` | Analysts, researchers, journalists, or well-known practitioners whose work shapes the market. |\",\n      \"| `connector` | People who primarily provide introductions, referrals, or access across networks — advisors, investors acting as connectors, community hubs. |\",\n      \"\",\n      \"If the person plausibly fits two roles, prefer the one that reflects\",\n      \"the **reason the profile was requested**, and note the secondary\",\n      \"role in the profile body.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## State Machine Overview\",\n      \"\",\n      \"```\",\n      \"┌───────────────────┐     ┌──────────────────────┐     ┌────────────────────┐\",\n      \"│ 1. RESEARCH       │────▶│ 2. DRAFT PROFILE     │────▶│ 3. FOLLOWUP        │\",\n      \"│ Collect public    │     │ Write the structured │     │ Cross-link existing│\",\n      \"│ sources into a    │     │ markdown profile to  │     │ artifacts; enqueue │\",\n      \"│ bounded notes     │     │ the configured path  │     │ company/software   │\",\n      \"│ file              │     │                      │     │ research issues    │\",\n      \"└───────────────────┘     └──────────────────────┘     └────────────────────┘\",\n      \"\",\n      \"┌───────────────────┐\",\n      \"│ 4. REFRESH        │  (cadence-driven, or on-demand)\",\n      \"│ Re-verify an      │\",\n      \"│ existing profile  │\",\n      \"│ with targeted web │\",\n      \"│ searches. Update  │\",\n      \"│ in place.         │\",\n      \"└───────────────────┘\",\n      \"```\",\n      \"\",\n      \"**Issue labels encode the phase:**\",\n      \"\",\n      \"| Label | Phase | Session work |\",\n      \"|-------|-------|-------------|\",\n      \"| `people:research` | 1. Research | Gather public sources. Write a bounded research-notes file. Create the draft issue. |\",\n      \"| `people:draft` | 2. Draft | Read the research notes. Write the structured profile to `<PROFILES_DIR>`. Create the followup issue if warranted. |\",\n      \"| `people:followup` | 3. Followup | Read the profile. Update cross-references to existing companies, software, and meeting notes. Enqueue `company:research` and `software:research` issues for unprofiled, genuinely-relevant entities surfaced in the profile. |\",\n      \"| `people:refresh` | 4. Refresh | Read an existing profile. Run 3–5 targeted web searches for role, employer, and primary public channel changes. Update the profile in place and add a revision-history entry. |\",\n      \"\",\n      \"All issues also carry `type:people-profile` and a `status:*` label.\",\n      \"\",\n      \"**Issue count per person cycle:** 1 research + 1 draft + 0–1 followup =\",\n      \"**2–3 sessions** on the initial cycle. `people:refresh` is an\",\n      \"independent downstream cycle that runs on its own cadence.\",\n      \"\",\n      \"**Shortened paths:**\",\n      \"- Research phase determines the person is out of scope (not\",\n      \"  relevant, insufficient public material) → research issue closes\",\n      \"  with a justification and no downstream issues are created → **1 session**.\",\n      \"- Short profile with no cross-references and no downstream\",\n      \"  candidates → **2 sessions**.\",\n      \"- Refresh that finds no material change → **1 session** (revision-\",\n      \"  history entry only, profile body unchanged).\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Configurable Paths\",\n      \"\",\n      \"The pipeline uses these placeholders. Consuming projects override the\",\n      \"defaults by passing paths in the `/profile-person` or `/refresh-person`\",\n      \"skill invocations, or by extending this rule in their own\",\n      \"`agentConfig.rules`.\",\n      \"\",\n      \"| Placeholder | Meaning | Default |\",\n      \"|-------------|---------|---------|\",\n      `| \\`<PEOPLE_ROOT>\\` | Root folder for person profiles | \\`${paths.peopleRoot}/\\` |`,\n      \"| `<PROFILES_DIR>` | Final person profile files | `<PEOPLE_ROOT>/profiles/` |\",\n      \"| `<NOTES_DIR>` | Research-notes files from Phase 1 | `<PEOPLE_ROOT>/notes/` |\",\n      \"| `<PERSON_SLUG>` | Short kebab-case slug identifying the person | derived from the person's name |\",\n      `| \\`<COMPANIES_DIR>\\` | Where existing company profiles live (for cross-references and duplicate detection during followup) | \\`${paths.companiesRoot}/profiles/\\` |`,\n      `| \\`<SOFTWARE_DIR>\\` | Where existing software profiles live (for cross-references and duplicate detection during followup) | \\`${paths.softwareRoot}/profiles/\\` |`,\n      `| \\`<MEETINGS_DIR>\\` | Where meeting notes live (for cross-references) | \\`${paths.meetingsRoot}/\\` |`,\n      \"\",\n      `If \\`${paths.docsRoot}/project-context.md\\` specifies a different people-research`,\n      \"tree or cross-reference target, prefer that. Otherwise fall back to\",\n      \"the defaults above. Cross-reference directories are read-only — this\",\n      \"agent never writes into them.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Refresh Cadence\",\n      \"\",\n      \"Profiles go stale. A person changes jobs, publishes new work, or\",\n      \"shifts focus. The pipeline supports a configurable refresh cadence\",\n      \"so `people:refresh` issues can be filed on a schedule without\",\n      \"hardcoding the interval:\",\n      \"\",\n      \"- **Default staleness threshold:** 180 days from the profile's\",\n      \"  `date` frontmatter.\",\n      \"- **Override precedence** (first match wins):\",\n      \"  1. `refresh_days` in the issue body (per-run override)\",\n      \"  2. `refresh_days` frontmatter on the profile itself\",\n      \"  3. Project-wide default declared under a `## Refresh Cadence`\",\n      `     section in \\`${paths.docsRoot}/project-context.md\\``,\n      \"  4. Built-in default: **180 days**\",\n      \"\",\n      \"When the `/refresh-person` skill is invoked for an existing profile:\",\n      \"\",\n      \"- If the profile is **younger** than the staleness threshold, the\",\n      \"  skill exits with a message pointing to the existing profile. Pass\",\n      \"  `force: true` in the issue body to refresh anyway.\",\n      \"- If the profile is **older** than the staleness threshold, the\",\n      \"  pipeline files a `people:refresh` issue and Phase 4 updates the\",\n      \"  existing file in place, preserving its slug and bumping the\",\n      \"  `date` frontmatter.\",\n      \"\",\n      \"The same precedence and `force: true` semantics apply when\",\n      \"`/profile-person` is invoked for a slug that already has a profile:\",\n      \"a fresh profile short-circuits; a stale profile is updated in place\",\n      \"by Phase 2 rather than forked under a new slug.\",\n      \"\",\n      \"Refresh mode never changes the profile's role without an explicit\",\n      \"override in the refresh request (`retype: <role>`) — role changes\",\n      \"are material and warrant a human review step.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Agent Loop\",\n      \"\",\n      \"Run this loop exactly once per session. Never start a second issue.\",\n      \"\",\n      \"1. Claim one open `type:people-profile` issue using phase priority:\",\n      \"   `people:research` > `people:draft` > `people:followup` >\",\n      \"   `people:refresh`.\",\n      \"2. Transition `status:ready` → `status:in-progress` and create the\",\n      \"   branch per your project's branch-naming convention.\",\n      \"3. Execute the phase handler that matches the issue's `people:*`\",\n      \"   label.\",\n      \"4. Commit, push, open a PR (if applicable), and close the issue per\",\n      `   your project's PR workflow — see the **${ISSUE_CLOSE_SECTION_TITLE}**`,\n      \"   section below before you close anything yourself.\",\n      \"   Stamp every PR you open with the `origin:agent` label — see the\",\n      \"   **Origin label** section below.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...renderClaimVerificationSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderOriginStampSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderIssueClosePolicySection(),\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 1: Research (`people:research`)\",\n      \"\",\n      \"**Goal:** Gather public sources into a bounded research-notes file.\",\n      \"\",\n      \"**Budget:** Public web search only, unless the issue body authorizes\",\n      \"additional sources. Write one notes file. Do not write the profile\",\n      \"in this phase.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the issue body.** It should include:\",\n      \"   - The person's name and primary affiliation (company) if known\",\n      \"   - The requested role from the taxonomy above\",\n      \"   - The reason the profile was requested (framing — what does the\",\n      \"     invoking project want to learn?)\",\n      \"   - Optional: `<PERSON_SLUG>` override, custom output paths,\",\n      \"     `refresh_days` override, `force: true` for out-of-cadence refresh\",\n      \"\",\n      \"2. **Derive `<PERSON_SLUG>`** if not supplied — a 2–4 word kebab-case\",\n      \"   summary of the person's name. Disambiguate against any existing\",\n      \"   slug under `<PROFILES_DIR>/` or `<NOTES_DIR>/` by appending a\",\n      \"   company or role qualifier (e.g. `jane-doe-acme`).\",\n      \"\",\n      \"3. **Check for an existing profile.** If `<PROFILES_DIR>/<PERSON_SLUG>.md`\",\n      \"   exists, read its `date` frontmatter and apply the refresh cadence\",\n      \"   rules above before proceeding.\",\n      \"\",\n      \"4. **Gather sources.** Prioritize in this order:\",\n      \"   - The person's own public writing (personal site, blog, newsletter)\",\n      \"   - Their current employer's bio / leadership page\",\n      \"   - Public conference talks, podcast appearances, and interviews\",\n      \"   - Public directories that the invoking issue body authorizes\",\n      \"     (LinkedIn, GitHub, company profiles, Crunchbase)\",\n      \"   - Public contributions (open-source repos, published papers)\",\n      \"\",\n      \"5. **Write a research-notes file** to\",\n      \"   `<NOTES_DIR>/<PERSON_SLUG>.notes.md`:\",\n      \"\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"Research Notes: <person name>\"',\n      \"   slug: <PERSON_SLUG>\",\n      \"   role: <one of the taxonomy values>\",\n      \"   primary_company: <company name if known>\",\n      \"   date: YYYY-MM-DD\",\n      \"   parent_issue: <N>\",\n      \"   ---\",\n      \"\",\n      \"   ## Framing\",\n      \"   <why this person was requested and what to learn>\",\n      \"\",\n      \"   ## Raw Findings\",\n      \"   - <finding> — source: <citation>\",\n      \"\",\n      \"   ## Candidate Cross-References\",\n      \"   - **Companies mentioned:** <list of company names>\",\n      \"   - **Software mentioned:** <list of product names>\",\n      \"   - **Meetings mentioned:** <list of meeting identifiers>\",\n      \"\",\n      \"   ## Open Questions\",\n      \"   <anything the notes could not answer from public sources>\",\n      \"\",\n      \"   ## Sources\",\n      \"   - <source URL or file path> — <date accessed>\",\n      \"   ```\",\n      \"\",\n      \"6. **Create the `people:draft` issue** with `Depends on: #<research-issue>`.\",\n      \"   Its body references the notes file path, the requested role, and\",\n      \"   any refresh-mode flags.\",\n      \"\",\n      \"7. **Commit and push** the notes file. Close the research issue\",\n      `   ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 2: Draft Profile (`people:draft`)\",\n      \"\",\n      \"**Goal:** Write the structured person profile from the research notes.\",\n      \"\",\n      \"**Budget:** No new web searches unless explicitly needed to fill a\",\n      \"gap the notes flagged. Write one profile file.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the research-notes file** referenced in the issue body.\",\n      \"\",\n      \"2. **Check for duplicates / refresh.** If `<PROFILES_DIR>/<PERSON_SLUG>.md`\",\n      \"   already exists:\",\n      \"   - In refresh mode, open the existing file and update in place,\",\n      \"     preserving the slug and bumping the `date` frontmatter.\",\n      \"   - Otherwise, flag a naming collision and stop — never silently\",\n      \"     overwrite a non-trivial existing profile.\",\n      \"\",\n      \"3. **Write the profile** to `<PROFILES_DIR>/<PERSON_SLUG>.md` using\",\n      \"   the template below. All sections are required; use\",\n      \"   `_Not available in public sources._` when a section cannot be\",\n      \"   filled from the notes.\",\n      \"\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"<person name>\"',\n      \"   slug: <PERSON_SLUG>\",\n      \"   role: <one of the taxonomy values>\",\n      \"   primary_company: <company name>\",\n      \"   date: YYYY-MM-DD\",\n      \"   refresh_days: <N, default 180>\",\n      \"   parent_issue: <N>\",\n      \"   notes: <NOTES_DIR>/<PERSON_SLUG>.notes.md\",\n      \"   ---\",\n      \"\",\n      \"   ## Summary\",\n      \"   <2–4 sentence elevator description: who they are, what they do,\",\n      \"   why they matter to this project>\",\n      \"\",\n      \"   ## Classification\",\n      \"   - **Primary role:** <taxonomy value>\",\n      \"   - **Secondary role (if any):** <taxonomy value or `n/a`>\",\n      \"   - **Relevance to this project:** <1–2 sentences tying the person\",\n      \"     back to the framing from the notes>\",\n      \"\",\n      \"   ## Current Position\",\n      \"   - **Company:** <primary company — link to company profile if tracked>\",\n      \"   - **Title:** <current title>\",\n      \"   - **Tenure:** <since YYYY, if known>\",\n      \"   - **Focus areas:** <what they work on day-to-day>\",\n      \"\",\n      \"   ## Background\",\n      \"   - **Prior roles:** <short reverse-chronological list>\",\n      \"   - **Education / credentials:** <if publicly disclosed>\",\n      \"   - **Notable contributions:** <open-source, publications, talks>\",\n      \"\",\n      \"   ## Expertise Signals\",\n      \"   <topics they write or speak about — each bullet cited to a public\",\n      \"   source>\",\n      \"\",\n      \"   ## Positioning / Point of View\",\n      \"   <how they describe their own work and views — use their own\",\n      \"   language, cited, rather than inferred>\",\n      \"\",\n      \"   ## Cross-References\",\n      \"   - **Companies:** <links to `<COMPANIES_DIR>/*.md` for companies\",\n      \"     already tracked by this project>\",\n      \"   - **Software:** <links to `<SOFTWARE_DIR>/*.md` for software\",\n      \"     already tracked by this project>\",\n      \"   - **Meetings:** <links to `<MEETINGS_DIR>/*.md` for meeting notes\",\n      \"     this person participated in>\",\n      \"\",\n      \"   ## Contact Preferences\",\n      \"   <public channels only — company email if listed, social handles,\",\n      \"   speaker inquiry forms. Never private contact info.>\",\n      \"\",\n      \"   ## Risks / Open Questions\",\n      \"   <what the profile could not answer; flag anything the followup\",\n      \"   phase should cross-reference>\",\n      \"\",\n      \"   ## Revision History\",\n      \"   | Date | Changes |\",\n      \"   |------|---------|\",\n      \"   | YYYY-MM-DD | Initial profile |\",\n      \"\",\n      \"   ## Sources\",\n      \"   - <source URL> — <date accessed>\",\n      \"   ```\",\n      \"\",\n      \"4. **Decide whether a followup issue is warranted.** Create a\",\n      \"   `people:followup` issue (depending on this draft issue) if the\",\n      \"   profile's Candidate Cross-References lists at least one company,\",\n      \"   software product, or meeting — whether or not the entity is\",\n      \"   already profiled. The followup phase links what exists and\",\n      \"   enqueues downstream research for what doesn't. Only skip the\",\n      \"   followup when the profile surfaced no cross-reference candidates\",\n      \"   at all; note this in the draft issue's closing comment.\",\n      \"\",\n      \"5. **Commit and push** the profile file. Close the draft issue\",\n      `   ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 3: Followup (`people:followup`)\",\n      \"\",\n      \"**Goal:** Populate the profile's `## Cross-References` section with\",\n      \"links to existing artifacts — companies, software, meetings — that\",\n      \"the consuming project already tracks, **and** enqueue downstream\",\n      \"`company:research` and `software:research` issues for unprofiled,\",\n      \"genuinely-relevant companies and software products surfaced in the\",\n      \"profile. Hand the candidates off to the `company-profile` and\",\n      \"`software-profile` bundles so they can be researched independently.\",\n      \"\",\n      \"**Budget:** No new web searches. Read the candidate cross-references,\",\n      \"resolve them against the configured directories, update the profile,\",\n      \"and enqueue downstream research issues where warranted. Markdown\",\n      \"cross-references in the profile are preserved — issue creation is\",\n      \"**additive** on top of the existing cross-reference behavior.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the profile file** referenced in the issue body.\",\n      \"\",\n      \"2. **Resolve company cross-references.** For each company named in\",\n      \"   the profile's research notes or body text, look for a matching\",\n      \"   file under `<COMPANIES_DIR>/`. If found, link it under\",\n      \"   `## Cross-References > Companies` and do **not** open a\",\n      \"   `company:research` issue for it — the profile already exists.\",\n      \"\",\n      \"3. **Resolve software cross-references.** Same pattern against\",\n      \"   `<SOFTWARE_DIR>/`. If found, link under `## Cross-References >\",\n      \"   Software` and do **not** open a `software:research` issue.\",\n      \"\",\n      \"4. **Resolve meeting cross-references.** For meetings the person\",\n      \"   participated in, look for a matching file under `<MEETINGS_DIR>/`\",\n      \"   by date or slug. Link matches; leave TODOs otherwise. Meeting\",\n      \"   notes are **always link-only** — this agent never opens\",\n      \"   meeting-research issues.\",\n      \"\",\n      \"5. **Enqueue a `company:research` issue per unprofiled, genuinely-\",\n      \"   relevant company.** For each company named in the profile that\",\n      \"   has no matching file under `<COMPANIES_DIR>/`, decide whether it\",\n      \"   warrants a downstream company profile (see restraint guidance\",\n      \"   below). If so, open an issue carrying:\",\n      \"\",\n      \"   - `type:company-profile`\",\n      \"   - `company:research`\",\n      `   - \\`priority:${labelsForPhase(issueDefaults, \"company:research\").priority}\\``,\n      `   - \\`status:${labelsForPhase(issueDefaults, \"company:research\").status}\\``,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"   The issue body must include:\",\n      \"   - A **discovery source** line naming this person profile\",\n      \"     (`Discovered while profiling: <person name>`)\",\n      \"   - A link to the person profile path (`Person profile: <PROFILES_DIR>/<PERSON_SLUG>.md`)\",\n      \"   - Enough identifying metadata — company name and primary domain/\",\n      \"     website — that the `company-profile-analyst` agent can begin\",\n      \"     research without revisiting this person profile\",\n      \"\",\n      \"6. **Enqueue a `software:research` issue per unprofiled software\",\n      \"   product the person has primary attribution for.** For each\",\n      \"   software product named in the profile with no matching file under\",\n      \"   `<SOFTWARE_DIR>/`, decide whether it warrants a downstream\",\n      \"   software profile (see restraint guidance below). If so, open an\",\n      \"   issue carrying:\",\n      \"\",\n      \"   - `type:software-profile`\",\n      \"   - `software:research`\",\n      `   - \\`priority:${labelsForPhase(issueDefaults, \"software:research\").priority}\\``,\n      `   - \\`status:${labelsForPhase(issueDefaults, \"software:research\").status}\\``,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"   The issue body must include:\",\n      \"   - A **discovery source** line naming this person profile\",\n      \"     (`Discovered while profiling: <person name>`)\",\n      \"   - A link to the person profile path (`Person profile: <PROFILES_DIR>/<PERSON_SLUG>.md`)\",\n      \"   - Enough identifying metadata — product name and vendor (the\",\n      \"     company that builds or maintains the product) — that the\",\n      \"     `software-profile-analyst` agent can begin research without\",\n      \"     revisiting this person profile\",\n      \"\",\n      \"7. **Avoid duplicates.** Before opening a `company:research` or\",\n      \"   `software:research` issue, verify no existing profile or open\",\n      \"   research issue already covers the candidate:\",\n      \"\",\n      \"   - Companies: check `<COMPANIES_DIR>/` for a matching profile\",\n      \"     file (by derived slug or by searching the directory for the\",\n      \"     company's name). If a profile exists, reuse it as a cross-\",\n      \"     reference only — **do not** open a new `company:research` issue.\",\n      \"   - Software: check `<SOFTWARE_DIR>/` the same way. If a profile\",\n      \"     exists, reuse it as a cross-reference only — **do not** open a\",\n      \"     new `software:research` issue.\",\n      \"   - Also scan open issues carrying the matching `company:research`\",\n      \"     or `software:research` label so this phase never re-opens\",\n      \"     research that is already queued.\",\n      \"\",\n      \"8. **Exercise restraint.** Only create downstream issues for\",\n      \"   entities **genuinely relevant** to the person's professional\",\n      \"   identity:\",\n      \"\",\n      \"   - **Companies:** open an issue for the person's current\",\n      \"     employer, significant past employers (roles of real tenure or\",\n      \"     leadership influence), companies where they sit on the board\",\n      \"     or act as an advisor, and companies they co-founded. Do **not**\",\n      \"     open an issue for every company on their LinkedIn, short\",\n      \"     consulting engagements, or employers tangential to the framing\",\n      \"     of this profile.\",\n      \"   - **Software:** open an issue only for products where the person\",\n      \"     has **primary attribution** — creator, maintainer, lead PM,\",\n      \"     founding engineer, or otherwise materially influenced the\",\n      \"     product. Do **not** open an issue for software the person\",\n      \"     merely uses, endorses in passing, or lists in a stack. When\",\n      \"     in doubt, leave the candidate as a markdown cross-reference\",\n      \"     and skip the downstream issue.\",\n      \"\",\n      \"9. **Assume the peers are present.** This pipeline assumes the\",\n      \"   `company-profile` and `software-profile` bundles are enabled in\",\n      \"   the consuming project. If a consuming project has disabled one\",\n      \"   of them, flag the followup issue with `status:needs-attention`\",\n      \"   and list the candidates that could not be routed — never invent\",\n      \"   an alternative label taxonomy.\",\n      \"\",\n      \"10. **Cross-link** — update the profile's `## Cross-References`\",\n      \"    section so each company or software entry references either\",\n      \"    the linked profile path (for existing profiles) or the newly-\",\n      \"    created downstream issue number (for candidates that were\",\n      \"    enqueued for research).\",\n      \"\",\n      \"11. **Commit and push** the updated profile. Close the followup\",\n      `    issue ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 4: Refresh (`people:refresh`)\",\n      \"\",\n      \"**Goal:** Re-verify an existing profile against a narrow set of facts\",\n      \"that tend to drift — current role, current employer, primary public\",\n      \"channel (email, handle, personal site) — with a small number of\",\n      \"targeted web searches, then update the profile in place.\",\n      \"\",\n      \"**Budget:** 3–5 targeted web searches focused on the narrow delta\",\n      \"set. Do not redo the full research-phase sweep, do not re-gather the\",\n      \"full background, and do not rewrite the profile body for facts that\",\n      \"have not changed.\",\n      \"\",\n      \"**Temporal framing.** Refreshes follow the same grep-`as of `-and-\",\n      \"re-verify pattern documented for `company:refresh` in the\",\n      \"`company-profile-analyst` bundle (Phase 5, steps 3 and 5): build\",\n      \"the list of qualified claims, classify each against the cadence\",\n      \"table in the `temporal-framing-convention` rule (90d for current\",\n      \"role / employer / tenure, falling back to 180d for slower-decay\",\n      \"claims), re-verify every claim past cadence, and update the\",\n      \"qualifier date on every claim that still holds. Treat a profile\",\n      \"with no `as of ` qualifiers as needing back-fill before any other\",\n      \"verification.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the existing profile** at the path referenced in the issue\",\n      \"   body. If the profile file is missing, close the issue with\",\n      \"   `status:needs-attention` and stop.\",\n      \"\",\n      \"2. **Confirm the staleness threshold.** Compare the profile's `date`\",\n      \"   frontmatter against today's date and the `refresh_days`\",\n      \"   frontmatter (or the project default from the Refresh Cadence\",\n      \"   section above). If the profile is younger than the threshold and\",\n      \"   the issue body does not set `force: true`, close the issue with\",\n      \"   a short comment and stop — do not burn the search budget.\",\n      \"\",\n      \"3. **Run 3–5 targeted searches.** Focus on the narrow delta set:\",\n      \"   - Current role / title at the current employer\",\n      \"   - Current employer (has the person changed jobs?)\",\n      \"   - Primary public channel (personal site URL, primary social\",\n      \"     handle, speaker inquiry form, public email if listed)\",\n      \"   - Optional: one search for notable recent public work (a new\",\n      \"     talk, post, or project) if the profile's Expertise Signals\",\n      \"     section has no entry from the last 12 months\",\n      \"\",\n      \"4. **Update the profile in place.** Edit only the affected sections\",\n      \"   (typically `## Current Position`, `## Contact Preferences`, and\",\n      \"   occasionally `## Expertise Signals`). Cite every new claim.\",\n      \"   Preserve the slug and the original `parent_issue` field. Bump the\",\n      \"   `date` frontmatter to today's date. Leave untouched sections\",\n      \"   untouched — refresh is a narrow delta, not a rewrite.\",\n      \"\",\n      \"5. **Do not silently re-type the person.** If the refresh surfaces\",\n      \"   evidence that the person's primary role has changed (e.g., a\",\n      \"   customer-contact who now works at your own organization and\",\n      \"   should become a colleague), flag it in `## Risks / Open Questions`\",\n      \"   and stop — do **not** rewrite the `role` frontmatter without an\",\n      \"   explicit override in the refresh issue body (`retype: <role>`).\",\n      \"\",\n      \"6. **Append a revision-history row.** Summarize the delta in one\",\n      \"   line:\",\n      \"\",\n      \"   ```markdown\",\n      \"   | YYYY-MM-DD | Refreshed: <one-line summary of what changed> |\",\n      \"   ```\",\n      \"\",\n      \"   When the search budget finds no material change, the row still\",\n      \"   appears so the next scheduled refresh knows this profile was\",\n      \"   reviewed:\",\n      \"\",\n      \"   ```markdown\",\n      \"   | YYYY-MM-DD | Refreshed: no material change |\",\n      \"   ```\",\n      \"\",\n      \"7. **Respect privacy.** The narrow delta set is bounded to public\",\n      \"   professional facts. Never expand the refresh into private contact\",\n      \"   details, family information, or other non-professional data —\",\n      \"   even if a search surfaces them. Privacy guardrails from Phase 1\",\n      \"   apply to every refresh.\",\n      \"\",\n      \"8. **Commit and push.** Report the delta on the refresh issue with\",\n      \"   a short comment (or `no material change`), and close it\",\n      `   ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Output Boundaries\",\n      \"\",\n      \"This agent writes **only** to:\",\n      \"\",\n      \"- `<NOTES_DIR>/` — research-notes files (Phase 1)\",\n      \"- `<PROFILES_DIR>/` — person profiles (Phase 2, updated in Phases\",\n      \"  3 and 4)\",\n      \"\",\n      \"In Phase 3, this agent also **creates `company:research` and\",\n      \"`software:research` issues** for companies and software products\",\n      \"surfaced in the profile that are not already tracked under\",\n      \"`<COMPANIES_DIR>/` or `<SOFTWARE_DIR>/`. It never writes the\",\n      \"downstream profiles themselves — those are the responsibility of the\",\n      \"`company-profile-analyst` and `software-profile-analyst` agents,\",\n      \"which pick up the issues this pipeline creates. Meeting notes\",\n      \"remain link-only across all phases.\",\n      \"\",\n      \"In Phase 4, this agent only updates an existing profile in place —\",\n      \"it never forks a new profile under a different slug and never\",\n      \"enqueues downstream `company:research` or `software:research`\",\n      \"issues. Cross-references surfaced during a refresh are flagged in\",\n      \"`## Risks / Open Questions` for a follow-up `people:followup` pass\",\n      \"to handle.\",\n      \"\",\n      \"The pipeline produces **person profiles and notes only**. Deeper\",\n      \"research on companies and software products is delegated to\",\n      \"downstream research pipelines via `company:research` and\",\n      \"`software:research` issues — this agent never writes company\",\n      \"profiles, software profiles, product evaluations, or comparative\",\n      \"analyses itself. Keep this boundary clean so the people-profile\",\n      \"pipeline stays generic.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Rules\",\n      \"\",\n      \"- **One person per session.** Never profile two people back-to-back.\",\n      \"- **Persist before closing.** Every phase must write its output file\",\n      \"  before closing its issue.\",\n      \"- **Cite everything.** Profile claims without source citations do not\",\n      \"  belong in the deliverable.\",\n      \"- **Respect privacy.** Never record private contact details, family\",\n      \"  information, or other non-professional personal data, even when\",\n      \"  encountered in a public source.\",\n      \"- **Cross-reference, don't duplicate.** Link to existing company,\",\n      \"  software, and meeting artifacts rather than re-describing them.\",\n      \"- **Delegate, don't duplicate.** Unprofiled companies and software\",\n      \"  products surfaced during profiling are handed off to the\",\n      \"  `company-profile` and `software-profile` bundles via\",\n      \"  `company:research` and `software:research` issues in Phase 3 —\",\n      \"  never inlined as company or software profiles in this pipeline.\",\n      \"- **Check before enqueueing.** Before opening a `company:research`\",\n      \"  or `software:research` issue, verify no existing profile or open\",\n      \"  research issue already covers the candidate. Reuse existing\",\n      \"  profiles as cross-references rather than re-queuing research.\",\n      \"- **Restrain the queue.** Only enqueue downstream research for\",\n      \"  companies that are a current employer, significant past employer,\",\n      \"  board/advisor role, or co-founded venture — not every company on\",\n      \"  the person's résumé. Only enqueue software research for products\",\n      \"  the person has **primary attribution** for (creator, maintainer,\",\n      \"  lead PM), not products they merely use.\",\n      \"- **Meetings stay link-only.** Phase 3 never opens meeting-research\",\n      \"  or any other meeting-related issues. Meetings are cross-\",\n      \"  referenced only.\",\n      \"- **Produce profiles, not requirement or evaluation documents.** Do\",\n      \"  not open `type:requirement` or formal evaluation issues from this\",\n      \"  pipeline. Follow-up research is scoped through `company:research`\",\n      \"  and `software:research` only.\",\n      \"- **Refresh respects the cadence.** Phase 4 exits early when the\",\n      \"  profile is younger than the staleness threshold and `force: true`\",\n      \"  is not set. It always appends a revision-history row so the next\",\n      \"  scheduled run knows the profile was reviewed.\",\n      \"- **Refresh is narrow, not a rewrite.** Phase 4 re-verifies role,\",\n      \"  employer, and primary public channel with 3–5 targeted searches\",\n      \"  and updates only the affected sections. It never re-runs the full\",\n      \"  research-phase sweep and never rewrites sections whose underlying\",\n      \"  facts have not changed.\",\n      \"- **Refresh, don't fork.** When a profile exists and is past its\",\n      \"  cadence, update in place rather than creating a new slug.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off a people profile cycle. */\nfunction buildProfilePersonSkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"profile-person\",\n    description:\n      \"Kick off a people-profile pipeline. Creates a people:research issue for the given person and dispatches Phase 1 (Research) in the people-profile-analyst agent. Phase 3 (Followup) enqueues downstream `company:research` and `software:research` issues for unprofiled, genuinely-relevant entities surfaced in the profile.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"people-profile-analyst\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Profile Person\",\n      \"\",\n      \"Kick off a people-profile pipeline. Creates a `people:research`\",\n      \"issue carrying the person's name, role, primary affiliation, and\",\n      \"framing, then dispatches Phase 1 (Research) in the\",\n      \"people-profile-analyst agent.\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/profile-person <person-name>\",\n      \"\",\n      \"Optional extensions in the issue body:\",\n      \"- `role: <colleague | customer-contact | vendor-contact |\",\n      \"   partner-contact | industry-expert | connector>` — override the\",\n      \"   default role inference\",\n      \"- `company: <name>` — primary company affiliation if not obvious\",\n      \"   from the name\",\n      \"- `framing: <text>` — why this profile was requested and what to learn\",\n      \"- `slug: <kebab-case>` — override the derived person slug\",\n      \"- `refresh_days: <N>` — override the default 180-day refresh cadence\",\n      \"- `force: true` — refresh even if the profile is younger than the\",\n      \"   cadence window\",\n      \"- `sources: <list>` — additional authorized sources beyond public web\",\n      \"\",\n      \"## Default Paths\",\n      \"\",\n      `If the project has no override in \\`${paths.docsRoot}/project-context.md\\` or`,\n      \"`agentConfig.rules`, outputs land under:\",\n      \"\",\n      `- \\`${paths.peopleRoot}/notes/<slug>.notes.md\\``,\n      `- \\`${paths.peopleRoot}/profiles/<slug>.md\\``,\n      \"\",\n      \"Cross-references are resolved against:\",\n      \"\",\n      `- \\`${paths.companiesRoot}/profiles/\\``,\n      `- \\`${paths.softwareRoot}/profiles/\\``,\n      `- \\`${paths.meetingsRoot}/\\``,\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `people:research` issue with `type:people-profile`,\",\n      `   \\`priority:${labelsForPhase(issueDefaults, \"people:research\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"people:research\").status}\\`. Body must include the`,\n      \"   person's name, selected role, primary company, framing, and any\",\n      \"   overrides.\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 1 (Research) of the people-profile-analyst agent.\",\n      \"3. Phase 1 creates the `people:draft` issue. Phase 2 may create a\",\n      \"   `people:followup` issue. Each downstream issue declares its\",\n      \"   `Depends on:` predecessor.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- A research-notes file under the project's notes directory\",\n      \"- A single person profile under the profiles directory\",\n      \"- Cross-references to existing companies, software, and meetings\",\n      \"  tracked elsewhere in the project\",\n      \"- `company:research` issues for unprofiled companies surfaced in\",\n      \"  the profile (handed off to the `company-profile` bundle)\",\n      \"- `software:research` issues for software products the person has\",\n      \"  primary attribution for (handed off to the `software-profile`\",\n      \"  bundle)\",\n      \"- This pipeline produces **person profiles only** — it does not\",\n      \"  write company profiles, software profiles, meeting notes, or any\",\n      \"  other downstream artifacts itself.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off a person refresh (maintenance) cycle. */\nfunction buildRefreshPersonSkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"refresh-person\",\n    description:\n      \"Kick off a people-profile refresh cycle. Creates a people:refresh issue for an existing profile and dispatches Phase 4 (Refresh) in the people-profile-analyst agent. Refresh re-verifies the profile's narrow delta set (role, employer, primary public channel) with 3–5 targeted web searches and updates it in place. Respects a configurable staleness threshold so profiles younger than the threshold exit early.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"people-profile-analyst\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Refresh Person\",\n      \"\",\n      \"Re-verify an existing person profile with a small number of\",\n      \"targeted web searches and update the profile in place. Creates a\",\n      \"`people:refresh` issue for the target profile and dispatches\",\n      \"Phase 4 (Refresh) in the people-profile-analyst agent.\",\n      \"\",\n      \"Refresh respects a configurable **staleness threshold** so scheduled\",\n      \"refreshes do not burn search budget on profiles that are still\",\n      \"fresh.\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/refresh-person <path-to-profile>\",\n      \"\",\n      \"Optional extensions in the issue body:\",\n      \"- `refresh_days: <N>` — override the default 180-day staleness\",\n      \"  threshold for this run\",\n      \"- `force: true` — refresh even if the profile is younger than the\",\n      \"  threshold\",\n      \"- `retype: <colleague | customer-contact | vendor-contact |\",\n      \"   partner-contact | industry-expert | connector>` — explicitly\",\n      \"   allow Phase 4 to change the profile's `role` when the refresh\",\n      \"   finds material evidence of a role-type change\",\n      \"\",\n      \"## Staleness Threshold\",\n      \"\",\n      \"Order of precedence (first match wins):\",\n      \"\",\n      \"1. `refresh_days` in the issue body (per-run override)\",\n      \"2. `refresh_days` frontmatter on the profile itself\",\n      \"3. Project-wide default declared under a `## Refresh Cadence`\",\n      `   section in \\`${paths.docsRoot}/project-context.md\\``,\n      \"4. Built-in default: **180 days**\",\n      \"\",\n      \"If the profile's `date` frontmatter plus the resolved threshold is\",\n      \"in the future (i.e. the profile is still fresh) and `force: true`\",\n      \"is not set, Phase 4 closes the refresh issue with a short comment\",\n      \"and stops without running any searches.\",\n      \"\",\n      \"## Budget\",\n      \"\",\n      \"- **3–5 targeted web searches** focused on the narrow delta set:\",\n      \"  current role / title, current employer, primary public channel\",\n      \"  (personal site, handle, speaker inquiry form, public email).\",\n      \"- Optional: one search for notable recent public work if the\",\n      \"  profile has no Expertise Signals entry from the last 12 months.\",\n      \"\",\n      \"## Privacy\",\n      \"\",\n      \"Privacy guardrails from Phase 1 apply to every refresh. Never\",\n      \"record private contact details, family information, or other\",\n      \"non-professional personal data — even if a search surfaces them.\",\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `people:refresh` issue with `type:people-profile`,\",\n      `   \\`priority:${labelsForPhase(issueDefaults, \"people:refresh\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"people:refresh\").status}\\`. Body must include the`,\n      \"   profile path and any overrides.\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 4 (Refresh) of the people-profile-analyst agent.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- The profile is updated in place (affected sections edited,\",\n      \"  `date` bumped, slug preserved)\",\n      \"- A revision-history row summarizing the delta — or\",\n      \"  `Refreshed: no material change` when the search budget found\",\n      \"  nothing material\",\n    ].join(\"\\n\"),\n  };\n}\n\n/**\n * People-profile bundle — enabled by default.\n *\n * Consuming projects can disable it with\n * `excludeBundles: [\"people-profile\"]`. `appliesWhen` always returns\n * `true` per the operating-system directive that bundles assume peers\n * are present — in Phase 3 this bundle hands work off to\n * `company-profile` (via `company:research`) and `software-profile`\n * (via `software:research`).\n *\n * Ships a sub-agent (`people-profile-analyst`), two user-invocable\n * skills (`/profile-person`, `/refresh-person`), and `type:people-profile`\n * plus `people:*` phase labels for the four phases.\n */\nexport function buildPeopleProfileBundle(\n  paths: ResolvedAgentPaths = DEFAULT_AGENT_PATHS,\n  issueDefaults: ResolvedIssueDefaults = DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n  tier: AgentModel = AGENT_MODEL.BALANCED,\n): AgentRuleBundle {\n  return {\n    name: \"people-profile\",\n    description:\n      \"People research and profiling pipeline: research, draft profile, followup, refresh. Enabled by default; domain-neutral; filesystem-durable between phases. Cross-references existing companies, software, and meeting notes, and Phase 3 (Followup) hands unprofiled, genuinely-relevant companies and software products off to the `company-profile` and `software-profile` bundles via `company:research` and `software:research` issues. Phase 4 (Refresh) re-verifies profiles on a configurable staleness cadence.\",\n    appliesWhen: () => true,\n    rules: [\n      {\n        name: \"people-profile-workflow\",\n        description:\n          \"Describes the 4-phase people-profile pipeline, the people:* label taxonomy, the cross-reference model, the refresh cadence rules, and the boundary against downstream research agents.\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# People Profile Workflow\",\n          \"\",\n          \"Use `/profile-person <person-name>` to kick off a person\",\n          \"research and profiling pipeline. The pipeline runs in up to 4\",\n          \"phases — research, draft, followup, refresh — each tracked by\",\n          \"its own GitHub issue labeled `people:research`, `people:draft`,\",\n          \"`people:followup`, or `people:refresh`. All issues carry\",\n          \"`type:people-profile`.\",\n          \"\",\n          \"One additional user-invocable skill drives the maintenance\",\n          \"phase independently:\",\n          \"\",\n          \"- `/refresh-person <path-to-profile>` — re-verify an existing\",\n          \"  profile with 3–5 targeted web searches and update it in\",\n          \"  place (Phase 4, respects a configurable staleness threshold).\",\n          \"\",\n          \"The pipeline produces **person profiles only**. Deeper research\",\n          \"on companies and software products surfaced while profiling is\",\n          \"delegated to the `company-profile` and `software-profile`\",\n          \"bundles via `company:research` and `software:research` issues\",\n          \"opened during Phase 3 (Followup). Meeting notes remain link-\",\n          \"only — the pipeline never creates meeting-research issues.\",\n          \"\",\n          \"See the `people-profile-analyst` agent definition for full\",\n          \"workflow details, default paths, the person-role taxonomy, the\",\n          \"refresh cadence rules, and phase-by-phase instructions.\",\n        ].join(\"\\n\"),\n        platforms: {\n          cursor: { exclude: true },\n        },\n        tags: [\"workflow\"],\n      },\n    ],\n    skills: [\n      buildProfilePersonSkill(paths, issueDefaults),\n      buildRefreshPersonSkill(paths, issueDefaults),\n    ],\n    subAgents: [buildPeopleProfileAnalystSubAgent(paths, issueDefaults, tier)],\n    labels: [\n      {\n        name: \"type:people-profile\",\n        color: \"0E8A16\",\n        description:\n          \"Work that produces or maintains a person profile or its research notes\",\n      },\n      {\n        name: \"people:research\",\n        color: \"C5DEF5\",\n        description:\n          \"Phase 1: gather public sources about a person into a research-notes file\",\n      },\n      {\n        name: \"people:draft\",\n        color: \"BFDADC\",\n        description:\n          \"Phase 2: write the structured person profile from research notes\",\n      },\n      {\n        name: \"people:followup\",\n        color: \"D4C5F9\",\n        description:\n          \"Phase 3: cross-link profile to companies/software/meetings; enqueue follow-up research issues\",\n      },\n      {\n        name: \"people:refresh\",\n        color: \"F9D0C4\",\n        description:\n          \"Phase 4: re-verify an existing person profile with targeted web searches and update it in place\",\n      },\n    ],\n  };\n}\n\n/**\n * Default-paths instance of the people-profile bundle, preserved for\n * backward compatibility with consumers that import the const\n * directly. The factory above is the canonical entry point when a\n * consumer supplies `AgentConfigOptions.paths`.\n */\nexport const peopleProfileBundle: AgentRuleBundle = buildPeopleProfileBundle();\n","import { relative } from \"node:path\";\nimport { Component, Project, YamlFile } from \"projen\";\nimport { ValueOf } from \"type-fest\";\n\n/**\n * Predefined minimum release age values in minutes.\n */\nexport const MINIMUM_RELEASE_AGE = {\n  ZERO_DAYS: 0,\n  ONE_HOUR: 60,\n  SIX_HOURS: 360,\n  TWELVE_HOURS: 720,\n  ONE_DAY: 1440,\n  TWO_DAYS: 2880,\n  THREE_DAYS: 4320,\n  FOUR_DAYS: 5760,\n  FIVE_DAYS: 7200,\n  SIX_DAYS: 8640,\n  ONE_WEEK: 10080,\n};\n\n/**\n * Platform selectors used by `supportedArchitectures` to widen the set of\n * optional dependencies pnpm downloads beyond the current host.\n *\n * See: https://pnpm.io/settings#supportedarchitectures\n */\nexport interface PnpmSupportedArchitectures {\n  /**\n   * Operating systems to fetch optional dependencies for, e.g.\n   * `[\"current\", \"win32\", \"linux\"]`.\n   */\n  readonly os?: Array<string>;\n\n  /**\n   * CPU architectures to fetch optional dependencies for, e.g.\n   * `[\"current\", \"x64\", \"arm64\"]`.\n   */\n  readonly cpu?: Array<string>;\n\n  /**\n   * libc implementations to fetch optional dependencies for, e.g.\n   * `[\"current\", \"glibc\", \"musl\"]`.\n   */\n  readonly libc?: Array<string>;\n}\n\n/**\n * Rules that relax pnpm's peer-dependency diagnostics.\n *\n * See: https://pnpm.io/settings#peerdependencyrules\n */\nexport interface PnpmPeerDependencyRules {\n  /**\n   * Peer dependency names (glob patterns allowed) whose \"missing peer\"\n   * warnings are suppressed.\n   */\n  readonly ignoreMissing?: Array<string>;\n\n  /**\n   * Peer dependency names (glob patterns allowed) that may resolve to any\n   * version without a version-mismatch warning.\n   */\n  readonly allowAny?: Array<string>;\n\n  /**\n   * Additional version ranges accepted for a peer dependency, keyed by\n   * package name or by `parent>child` selector.\n   */\n  readonly allowedVersions?: { [selector: string]: string };\n}\n\n/**\n * pnpm 11's `update` block, controlling `pnpm update` behavior.\n *\n * Supersedes the deprecated `updateConfig` block. When both are set, pnpm\n * ignores `updateConfig` in favor of `update` and emits a warning — so\n * configulator emits only the winning key.\n *\n * See: https://pnpm.io/settings#update\n */\nexport interface PnpmUpdateSettings {\n  /**\n   * Packages excluded from `pnpm update`. Replaces the deprecated\n   * `updateConfig.ignoreDependencies`.\n   */\n  readonly ignoreDeps?: Array<string>;\n\n  /**\n   * Whether `pnpm update` writes a changeset file.\n   */\n  readonly changeset?: boolean;\n\n  /**\n   * Whether `pnpm update` also updates GitHub Actions workflow pins.\n   */\n  readonly githubActions?: boolean;\n\n  /**\n   * GitHub server used when resolving GitHub Actions updates.\n   */\n  readonly githubActionsServer?: string;\n}\n\n/**\n * The deprecated `updateConfig` block.\n *\n * @deprecated Superseded by `update` in pnpm 11. Retained so consumers on\n *             older pnpm majors keep a typed route; prefer `update`.\n *\n * See: https://pnpm.io/settings#updateconfig\n */\nexport interface PnpmUpdateConfigSettings {\n  /**\n   * Packages excluded from `pnpm update`.\n   */\n  readonly ignoreDependencies?: Array<string>;\n\n  /**\n   * Whether `pnpm update` writes a changeset file.\n   */\n  readonly changeset?: boolean;\n\n  /**\n   * Whether `pnpm update` also updates GitHub Actions workflow pins.\n   */\n  readonly githubActions?: boolean;\n\n  /**\n   * GitHub server used when resolving GitHub Actions updates.\n   */\n  readonly githubActionsServer?: string;\n}\n\nexport interface PnpmWorkspaceOptions {\n  /**\n   * Filename for the pnpm workspace file. This should probably never change.\n   *\n   * @default \"pnpm-workspace.yaml\"\n   */\n  readonly fileName?: string;\n\n  /**\n   * To reduce the risk of installing compromised packages, you can delay the\n   * installation of newly published versions. In most cases, malicious releases\n   * are discovered and removed from the registry within an hour.\n   *\n   * minimumReleaseAge defines the minimum number of minutes that must pass\n   * after a version is published before pnpm will install it. This applies to\n   * all dependencies, including transitive ones.\n   *\n   * Note: this should match depsUpgradeOptions.cooldown in the project config.\n   *\n   * See: https://pnpm.io/settings#minimumreleaseage\n   *\n   * @default MINIMUM_RELEASE_AGE.ONE_WEEK\n   */\n  readonly minimumReleaseAge?: ValueOf<typeof MINIMUM_RELEASE_AGE>;\n\n  /**\n   * If you set minimumReleaseAge but need certain dependencies to always\n   * install the newest version immediately, you can list them under\n   * minimumReleaseAgeExclude. The exclusion works by package name and applies\n   * to all versions of that package.\n   *\n   * @default - no exclusions (empty array)\n   *\n   * See: https://pnpm.io/settings#minimumreleaseageexclude\n   */\n  readonly minimumReleaseAgeExclude?: Array<string>;\n\n  /**\n   * A map of package names to booleans controlling whether each package may\n   * execute \"preinstall\", \"install\", and/or \"postinstall\" scripts during\n   * installation. Set a package's value to `true` to allow lifecycle scripts;\n   * set it to `false` to silently block them without a warning.\n   *\n   * pnpm 11 replaced the legacy `onlyBuiltDependencies` (allow-list) and\n   * `ignoredBuiltDependencies` (deny-list) settings with this single\n   * `allowBuilds` map. Configulator translates the deprecated input fields\n   * automatically: entries from `onlyBuiltDependencies` map to `true` and\n   * entries from `ignoredBuiltDependencies` map to `false`. When a key\n   * appears in both `allowBuilds` and one of the deprecated fields, the\n   * explicit `allowBuilds` value wins.\n   *\n   * For cross-version compatibility, configulator emits BOTH the new\n   * `allowBuilds` map AND the legacy `onlyBuiltDependencies` /\n   * `ignoredBuiltDependencies` arrays in the generated YAML so consumers\n   * on either pnpm 10 or pnpm 11 see correct lifecycle-script behavior\n   * without changing their input.\n   *\n   * See: https://pnpm.io/settings#allowbuilds\n   *\n   * @default none (empty object)\n   */\n  readonly allowBuilds?: { [packageName: string]: boolean };\n\n  /**\n   * A list of package names that are allowed to execute \"preinstall\",\n   * \"install\", and/or \"postinstall\" scripts during installation. Only the\n   * packages listed in this array will be able to run those lifecycle scripts.\n   * If onlyBuiltDependenciesFile and neverBuiltDependencies are omitted, this\n   * configuration option will default to blocking all install scripts.\n   *\n   * You may restrict allowances to specific versions (and lists of versions\n   * using a disjunction with ||). When versions are specified, only those\n   * versions of the package may run lifecycle scripts:\n   *\n   * See: https://pnpm.io/settings#onlybuiltdependencies\n   *\n   * @deprecated Deprecated in pnpm 11; configulator emits both legacy and\n   *             new keys for cross-version compatibility — pnpm 10 honors\n   *             the legacy keys, pnpm 11 honors `allowBuilds`. Prefer\n   *             `allowBuilds` as the input field going forward; entries\n   *             supplied here translate to `allowBuilds[<package>] = true`.\n   *\n   * @default none (empty array)\n   */\n  readonly onlyBuiltDependencies?: Array<string>;\n\n  /**\n   * A list of package names that are NOT allowed to execute \"preinstall\",\n   * \"install\", and/or \"postinstall\" scripts during installation and will not\n   * warn or ask to be executed.\n   *\n   * This is useful when you want to hide the warning because you know the\n   * lifecycle scripts are not needed.\n   *\n   * https://pnpm.io/settings#ignoredbuiltdependencies\n   *\n   * @deprecated Deprecated in pnpm 11; configulator emits both legacy and\n   *             new keys for cross-version compatibility — pnpm 10 honors\n   *             the legacy keys, pnpm 11 honors `allowBuilds`. Prefer\n   *             `allowBuilds` as the input field going forward; entries\n   *             supplied here translate to `allowBuilds[<package>] = false`.\n   *\n   * @default none (empty array)\n   */\n  readonly ignoredBuiltDependencies?: Array<string>;\n\n  /**\n   * Additional subproject paths to include in the workspace packages array.\n   * These will be combined with any subprojects discovered via projen's\n   * project.subprojects property. Paths should be relative to the project root.\n   *\n   * @default none (empty array)\n   */\n  readonly subprojects?: Array<string>;\n\n  /**\n   * Catalog of reusable dependency version ranges.\n   *\n   * The catalog allows you to define dependency versions as reusable constants\n   * that can be referenced in package.json files using the catalog: protocol.\n   *\n   * Example:\n   * ```yaml\n   * catalog:\n   *   react: ^18.0.0\n   *   typescript: ^5.0.0\n   * ```\n   *\n   * Then in package.json:\n   * ```json\n   * {\n   *   \"dependencies\": {\n   *     \"react\": \"catalog:react\"\n   *   }\n   * }\n   * ```\n   *\n   * @default undefined (not included in output)\n   *\n   * See: https://pnpm.io/pnpm-workspace_yaml#catalog\n   */\n  readonly defaultCatalog?: { [key: string]: string };\n\n  /**\n   * Named catalogs of reusable dependency version ranges.\n   *\n   * Multiple named catalogs with arbitrarily chosen names can be configured under the `catalogs` key.\n   *\n   * Example:\n   * ```yaml\n   * catalogs:\n   *   frontend:\n   *     react: ^18.0.0\n   *     typescript: ^5.0.0\n   *   backend:\n   *     express: ^4.18.0\n   * ```\n   *\n   * Then in package.json:\n   * ```json\n   * {\n   *   \"dependencies\": {\n   *     \"react\": \"catalog:frontend/react\"\n   *   }\n   * }\n   * ```\n   *\n   * @default undefined (not included in output)\n   *\n   * See: https://pnpm.io/catalogs\n   */\n  readonly namedCatalogs?: {\n    [catalogName: string]: { [dependencyName: string]: string };\n  };\n\n  /**\n   * Whether pnpm prompts before removing a sub-project's `node_modules`\n   * directory during install. Set to `false` to skip the interactive prompt\n   * so headless / non-TTY consumers (Claude Code agents, CI scripts,\n   * scheduled tasks) don't abort with\n   * `ERR_PNPM_ABORTED_REMOVE_MODULES_DIR_NO_TTY` mid-synth.\n   *\n   * Introduced in pnpm 11.0.\n   *\n   * @default undefined (key omitted; pnpm uses its built-in default)\n   *\n   * @see https://pnpm.io/settings#confirmmodulespurge\n   */\n  readonly confirmModulesPurge?: boolean;\n\n  /**\n   * Whether pnpm fails the install when a dependency's build script has not\n   * been explicitly approved via `allowBuilds`. Set to `false` so unreviewed\n   * build-script entries don't fail mid-synth in CI when configulator is\n   * regenerating `allowBuilds` placeholders.\n   *\n   * Introduced in pnpm 10.3 (default `true` in pnpm 11).\n   *\n   * @default undefined (key omitted; pnpm uses its built-in default)\n   *\n   * @see https://pnpm.io/settings#strictdepbuilds\n   */\n  readonly strictDepBuilds?: boolean;\n\n  /**\n   * Whether `pnpm run` / `pnpm exec` verifies the lockfile matches\n   * `node_modules` before executing the requested script. Set to `\"install\"`\n   * (or `false`) so non-TTY consumers don't hang on the `\"prompt\"` default.\n   *\n   * Introduced in pnpm 10.x.\n   *\n   * @default undefined (key omitted; pnpm uses its built-in default of \"prompt\")\n   *\n   * @see https://pnpm.io/settings#verifydepsbeforerun\n   */\n  readonly verifyDepsBeforeRun?:\n    \"install\" | \"warn\" | \"error\" | \"prompt\" | false;\n\n  /**\n   * How catalog entries are enforced when a sub-project's `package.json`\n   * specifies a dependency that exists in a catalog. `\"manual\"` keeps the\n   * existing opt-in `catalog:` protocol behavior, `\"prefer\"` substitutes\n   * catalog versions automatically, and `\"strict\"` rejects any version\n   * that diverges from the catalog.\n   *\n   * Introduced in pnpm 10.12.1.\n   *\n   * @default undefined (key omitted; pnpm uses its built-in default of \"manual\")\n   *\n   * @see https://pnpm.io/settings#catalogmode\n   */\n  readonly catalogMode?: \"manual\" | \"prefer\" | \"strict\";\n\n  /**\n   * Whether pnpm removes unused catalog entries from `pnpm-workspace.yaml`\n   * during install. Helps keep the catalog honest when sub-projects stop\n   * referencing a catalog entry.\n   *\n   * Introduced in pnpm 10.15.\n   *\n   * @default undefined (key omitted; pnpm uses its built-in default)\n   *\n   * @see https://pnpm.io/settings#cleanupunusedcatalogs\n   */\n  readonly cleanupUnusedCatalogs?: boolean;\n\n  /**\n   * Whether `minimumReleaseAge` resolution fails when no published version\n   * satisfies the age constraint. `true` fails the install; `false` falls\n   * back to an older version that does satisfy the age constraint.\n   *\n   * Either way the quarantine holds — a package younger than\n   * `minimumReleaseAge` is never installed. This setting only chooses the\n   * failure mode when no mature version is available: hard error, or\n   * resolution to an older mature version.\n   *\n   * Introduced in pnpm 11.0.\n   *\n   * @default false\n   *\n   * @see https://pnpm.io/settings#minimumreleaseagestrict\n   */\n  readonly minimumReleaseAgeStrict?: boolean;\n\n  /**\n   * Whether `minimumReleaseAge` resolution skips the age check for packages\n   * whose registry response lacks timestamp metadata. Default is `true`\n   * (skip the check rather than fail), which mirrors pnpm's behavior.\n   *\n   * Introduced in pnpm 11.0.\n   *\n   * @default undefined (key omitted; pnpm uses its built-in default of true)\n   *\n   * @see https://pnpm.io/settings#minimumreleaseageignoremissingtime\n   */\n  readonly minimumReleaseAgeIgnoreMissingTime?: boolean;\n\n  /*****************************************************************************\n   *\n   * DEPENDENCY GRAPH\n   *\n   ****************************************************************************/\n\n  /**\n   * Version overrides applied to any dependency in the graph, including\n   * transitive ones that no direct dependency would otherwise let you pin.\n   *\n   * Keys accept pnpm's full selector syntax — a bare name (`\"foo\"`), a\n   * range-scoped selector (`\"@smithy/types@^4\"`), or a parent-scoped\n   * selector (`\"parent>child\"`). Rendered verbatim.\n   *\n   * ```ts\n   * overrides: {\n   *   \"@smithy/types@^4\": \"4.17.2\",\n   *   \"cli-table3>colors\": \"^1.4.0\",\n   * }\n   * ```\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#overrides\n   */\n  readonly overrides?: { [selector: string]: string };\n\n  /**\n   * Extra fields merged into a third-party package's manifest at install\n   * time — the supported way to repair a dependency that ships an incorrect\n   * or incomplete `package.json` without patching it.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#packageextensions\n   */\n  readonly packageExtensions?: { [packageSelector: string]: unknown };\n\n  /**\n   * Patch files applied to dependencies, keyed by `name@version` and valued\n   * with a repo-relative path to the `.patch` file.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#patcheddependencies\n   */\n  readonly patchedDependencies?: { [packageAndVersion: string]: string };\n\n  /**\n   * Directory that `pnpm patch-commit` writes patch files into.\n   *\n   * @default undefined (key omitted; pnpm defaults to \"patches\")\n   *\n   * @see https://pnpm.io/settings#patchesdir\n   */\n  readonly patchesDir?: string;\n\n  /**\n   * Whether an entry in `patchedDependencies` that matches no installed\n   * package is tolerated instead of failing the install.\n   *\n   * @default undefined (key omitted; pnpm uses its built-in default)\n   *\n   * @see https://pnpm.io/settings#allowunusedpatches\n   */\n  readonly allowUnusedPatches?: boolean;\n\n  /**\n   * Deprecation warnings to silence, keyed by package name (or\n   * `name@range`) and valued with the version range whose deprecation\n   * message is suppressed.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#alloweddeprecatedversions\n   */\n  readonly allowedDeprecatedVersions?: { [packageName: string]: string };\n\n  /**\n   * Packages whose lifecycle scripts never run, regardless of the\n   * `allowBuilds` map.\n   *\n   * Composes with the `allowBuilds` / legacy built-dependencies hybrid\n   * emission: every entry is merged into the emitted `allowBuilds` map as\n   * `false` (so the derived legacy allow/deny arrays stay consistent), and\n   * the verbatim `neverBuiltDependencies` array is emitted alongside.\n   * Precedence runs `onlyBuiltDependencies` → `ignoredBuiltDependencies` →\n   * `neverBuiltDependencies` → explicit `allowBuilds`, so an explicit\n   * `allowBuilds` entry still wins.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#neverbuiltdependencies\n   */\n  readonly neverBuiltDependencies?: Array<string>;\n\n  /**\n   * Optional dependencies that are never installed, by package name.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#ignoredoptionaldependencies\n   */\n  readonly ignoredOptionalDependencies?: Array<string>;\n\n  /**\n   * Platforms to fetch optional dependencies for beyond the current host —\n   * the usual way to make a lockfile usable across CI runners and developer\n   * machines with different OS/CPU/libc combinations.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#supportedarchitectures\n   */\n  readonly supportedArchitectures?: PnpmSupportedArchitectures;\n\n  /**\n   * Packages installed before anything else and allowed to contribute\n   * configuration (hooks, patches, catalogs) to the workspace, keyed by\n   * package name and valued with `version+integrity`.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#configdependencies\n   */\n  readonly configDependencies?: { [packageName: string]: string };\n\n  /**\n   * How pnpm picks a version when several satisfy a range.\n   *\n   * @default undefined (key omitted; pnpm defaults to \"highest\")\n   *\n   * @see https://pnpm.io/settings#resolutionmode\n   */\n  readonly resolutionMode?: \"highest\" | \"time-based\" | \"lowest-direct\";\n\n  /**\n   * Range prefix written for newly added dependencies, e.g. `\"^\"` or `\"~\"`.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#saveprefix\n   */\n  readonly savePrefix?: string;\n\n  /**\n   * Whether newly added dependencies are pinned to an exact version.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#saveexact\n   */\n  readonly saveExact?: boolean;\n\n  /*****************************************************************************\n   *\n   * SUPPLY-CHAIN POSTURE\n   *\n   * Extends the `minimumReleaseAge` stance above.\n   *\n   ****************************************************************************/\n\n  /**\n   * Whether pnpm rejects a package whose publish-trust level has regressed\n   * (e.g. a package previously published with provenance that no longer is).\n   *\n   * @default undefined (key omitted; pnpm uses its built-in default)\n   *\n   * @see https://pnpm.io/settings#trustpolicy\n   */\n  readonly trustPolicy?: \"off\" | \"no-downgrade\";\n\n  /**\n   * Packages exempt from `trustPolicy`, as `name` or `name@range` selectors.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#trustpolicyexclude\n   */\n  readonly trustPolicyExclude?: Array<string>;\n\n  /**\n   * Unix timestamp (seconds) after which `trustPolicy` stops applying, used\n   * to grandfather in packages published before a cutoff.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#trustpolicyignoreafter\n   */\n  readonly trustPolicyIgnoreAfter?: number;\n\n  /**\n   * Whether transitive dependencies resolved through exotic (non-registry)\n   * specifiers — git, tarball URL, local path — are rejected. Direct\n   * dependencies are unaffected.\n   *\n   * @default undefined (key omitted; pnpm 11 defaults to false)\n   *\n   * @see https://pnpm.io/settings#blockexoticsubdeps\n   */\n  readonly blockExoticSubdeps?: boolean;\n\n  /**\n   * Whether `minimumReleaseAgeExclude` entries are pruned to those actually\n   * resolved in the lockfile.\n   *\n   * @default undefined (key omitted; pnpm defaults to false)\n   *\n   * @see https://pnpm.io/settings#minimumreleaseageexcludeprune\n   */\n  readonly minimumReleaseAgeExcludePrune?: boolean;\n\n  /*****************************************************************************\n   *\n   * PEER DEPENDENCIES\n   *\n   ****************************************************************************/\n\n  /**\n   * Whether missing peer dependencies are installed automatically.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#autoinstallpeers\n   */\n  readonly autoInstallPeers?: boolean;\n\n  /**\n   * Whether an unresolved peer dependency fails the install.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#strictpeerdependencies\n   */\n  readonly strictPeerDependencies?: boolean;\n\n  /**\n   * Whether dependents are deduplicated when they resolve peers identically.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#dedupepeerdependents\n   */\n  readonly dedupePeerDependents?: boolean;\n\n  /**\n   * Whether peer dependencies may resolve from the workspace root's\n   * dependencies.\n   *\n   * @default undefined (key omitted; pnpm 11 defaults to true)\n   *\n   * @see https://pnpm.io/settings#resolvepeersfromworkspaceroot\n   */\n  readonly resolvePeersFromWorkspaceRoot?: boolean;\n\n  /**\n   * Rules that relax peer-dependency diagnostics for known-good mismatches.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#peerdependencyrules\n   */\n  readonly peerDependencyRules?: PnpmPeerDependencyRules;\n\n  /*****************************************************************************\n   *\n   * WORKSPACE SEMANTICS\n   *\n   ****************************************************************************/\n\n  /**\n   * Whether dependencies satisfied by a workspace package link to it rather\n   * than resolving from the registry. `\"deep\"` also links transitively.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#linkworkspacepackages\n   */\n  readonly linkWorkspacePackages?: boolean | \"deep\";\n\n  /**\n   * Whether a workspace package is preferred over a registry version even\n   * when the registry has a higher matching version.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#preferworkspacepackages\n   */\n  readonly preferWorkspacePackages?: boolean;\n\n  /**\n   * Whether workspace dependencies are hard-linked into the dependent's\n   * `node_modules` instead of symlinked.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#injectworkspacepackages\n   */\n  readonly injectWorkspacePackages?: boolean;\n\n  /**\n   * Whether injected workspace dependencies are deduplicated.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#dedupeinjecteddeps\n   */\n  readonly dedupeInjectedDeps?: boolean;\n\n  /**\n   * Script names after which injected workspace dependencies are re-synced.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#syncinjecteddepsafterscripts\n   */\n  readonly syncInjectedDepsAfterScripts?: Array<string>;\n\n  /**\n   * How workspace dependencies are written to `package.json`. `\"rolling\"`\n   * writes `workspace:^`, `true` writes `workspace:<version>`.\n   *\n   * @default undefined (key omitted; pnpm defaults to \"rolling\")\n   *\n   * @see https://pnpm.io/settings#saveworkspaceprotocol\n   */\n  readonly saveWorkspaceProtocol?: boolean | \"rolling\";\n\n  /**\n   * Whether recursive commands include the workspace root project.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#includeworkspaceroot\n   */\n  readonly includeWorkspaceRoot?: boolean;\n\n  /**\n   * Whether the workspace uses a single shared lockfile at the root.\n   *\n   * @default undefined (key omitted; pnpm defaults to true)\n   *\n   * @see https://pnpm.io/settings#sharedworkspacelockfile\n   */\n  readonly sharedWorkspaceLockfile?: boolean;\n\n  /**\n   * Whether a cyclic dependency between workspace packages fails the install.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#disallowworkspacecycles\n   */\n  readonly disallowWorkspaceCycles?: boolean;\n\n  /**\n   * Whether workspace packages are hoisted to the root `node_modules`.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#hoistworkspacepackages\n   */\n  readonly hoistWorkspacePackages?: boolean;\n\n  /**\n   * Scripts every workspace package must define; a missing script fails the\n   * install.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#requiredscripts\n   */\n  readonly requiredScripts?: Array<string>;\n\n  /*****************************************************************************\n   *\n   * LAYOUT AND LOCKFILE\n   *\n   ****************************************************************************/\n\n  /**\n   * How `node_modules` is laid out — pnpm's symlinked store (`\"isolated\"`),\n   * a flat npm-style tree (`\"hoisted\"`), or Plug'n'Play (`\"pnp\"`).\n   *\n   * @default undefined (key omitted; pnpm defaults to \"isolated\")\n   *\n   * @see https://pnpm.io/settings#nodelinker\n   */\n  readonly nodeLinker?: \"isolated\" | \"hoisted\" | \"pnp\";\n\n  /**\n   * Glob patterns hoisted into the hidden `node_modules/.pnpm/node_modules`\n   * directory.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#hoistpattern\n   */\n  readonly hoistPattern?: Array<string>;\n\n  /**\n   * Glob patterns hoisted all the way to the root `node_modules`, making\n   * them importable by any package.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#publichoistpattern\n   */\n  readonly publicHoistPattern?: Array<string>;\n\n  /**\n   * Whether every dependency is hoisted to the root `node_modules`,\n   * reproducing npm's flat layout.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#shamefullyhoist\n   */\n  readonly shamefullyHoist?: boolean;\n\n  /**\n   * Whether an up-to-date lockfile short-circuits resolution.\n   *\n   * @default undefined (key omitted; pnpm defaults to true)\n   *\n   * @see https://pnpm.io/settings#preferfrozenlockfile\n   */\n  readonly preferFrozenLockfile?: boolean;\n\n  /**\n   * Maximum length of the peer-resolution suffix in virtual store directory\n   * names, lowered when Windows path limits bite.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#peerssuffixmaxlength\n   */\n  readonly peersSuffixMaxLength?: number;\n\n  /*****************************************************************************\n   *\n   * SCRIPTS, ENGINES, PUBLISH\n   *\n   ****************************************************************************/\n\n  /**\n   * Whether `pre` and `post` script hooks run around a named script.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#enableprepostscripts\n   */\n  readonly enablePrePostScripts?: boolean;\n\n  /**\n   * Value of `NODE_OPTIONS` for lifecycle scripts, e.g.\n   * `\"--max-old-space-size=4096\"`.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#nodeoptions\n   */\n  readonly nodeOptions?: string;\n\n  /**\n   * Whether a package whose `engines` field excludes the running Node\n   * version fails the install.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#enginestrict\n   */\n  readonly engineStrict?: boolean;\n\n  /**\n   * `pnpm update` behavior. Supersedes `updateConfig`.\n   *\n   * When both `update` and `updateConfig` are supplied, `update` wins and\n   * only `update` is emitted — pnpm warns and ignores `updateConfig` when\n   * it sees both keys, so emitting both would produce a warning on every\n   * install.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#update\n   */\n  readonly update?: PnpmUpdateSettings;\n\n  /**\n   * `pnpm update` behavior, in the pre-pnpm-11 spelling.\n   *\n   * @deprecated Superseded by `update` in pnpm 11. Supplying both emits only\n   *             `update`. Prefer `update` in new configs.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#updateconfig\n   */\n  readonly updateConfig?: PnpmUpdateConfigSettings;\n\n  /**\n   * Whether `pnpm publish` runs its git working-tree and branch checks.\n   *\n   * @default undefined (key omitted; pnpm defaults to true)\n   *\n   * @see https://pnpm.io/settings#gitchecks\n   */\n  readonly gitChecks?: boolean;\n\n  /**\n   * Branch `pnpm publish` is allowed to publish from.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#publishbranch\n   */\n  readonly publishBranch?: string;\n\n  /**\n   * Whether `pnpm publish` attaches npm provenance attestations.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#provenance\n   */\n  readonly provenance?: boolean;\n\n  /**\n   * Whether the README is embedded in the published package metadata.\n   *\n   * @default undefined (key omitted)\n   *\n   * @see https://pnpm.io/settings#embedreadme\n   */\n  readonly embedReadme?: boolean;\n\n  /*****************************************************************************\n   *\n   * CATALOG MAINTENANCE\n   *\n   ****************************************************************************/\n\n  /**\n   * Whether pnpm prunes unused catalog entries from `pnpm-workspace.yaml`\n   * during install. This is pnpm's current spelling for what\n   * `cleanupUnusedCatalogs` configures.\n   *\n   * When both are supplied, `catalogPrune` wins and only `catalogPrune` is\n   * emitted, matching pnpm's own `catalogPrune ??= cleanupUnusedCatalogs`\n   * precedence. When only `cleanupUnusedCatalogs` is supplied, that key is\n   * emitted unchanged so consumers on older pnpm majors keep working.\n   *\n   * @default undefined (key omitted; pnpm defaults to false)\n   *\n   * @see https://pnpm.io/settings#catalogprune\n   */\n  readonly catalogPrune?: boolean;\n\n  /*****************************************************************************\n   *\n   * PASSTHROUGH\n   *\n   ****************************************************************************/\n\n  /**\n   * Arbitrary pnpm settings rendered verbatim as top-level keys in the\n   * generated `pnpm-workspace.yaml`.\n   *\n   * This is the escape hatch for every setting configulator does not type —\n   * per-user / per-machine / CI-environment settings that are deliberately\n   * left untyped (proxies and TLS, fetch and retry tuning, store and cache\n   * paths, CLI cosmetics, registry and auth settings), settings added by\n   * future pnpm releases, and the handful of settings that do not exist in\n   * the pnpm version this package targets.\n   *\n   * ```ts\n   * additionalSettings: {\n   *   networkConcurrency: 8,\n   *   storeDir: \"/mnt/pnpm-store\",\n   * }\n   * ```\n   *\n   * A key that collides with a typed field or with a structural key\n   * (`packages`, `catalog`, `catalogs`) throws at synth, naming the typed\n   * option to use instead.\n   *\n   * @default undefined (no additional keys)\n   *\n   * @see https://pnpm.io/settings\n   */\n  readonly additionalSettings?: { [settingName: string]: unknown };\n}\n\n/**\n * Curated settings that render verbatim under their own name whenever the\n * consumer supplies a value.\n *\n * Declaration order here is emission order in the generated YAML, so the\n * output stays deterministic across synths. Every entry is verified to exist\n * in the pnpm version this package targets.\n *\n * Settings needing bespoke handling are deliberately absent:\n * `neverBuiltDependencies` (merges into the `allowBuilds` map),\n * `catalogPrune` / `cleanupUnusedCatalogs`, and `update` / `updateConfig`\n * (deprecated-alias precedence pairs).\n */\nconst CURATED_SETTING_KEYS = [\n  // Dependency graph\n  \"overrides\",\n  \"packageExtensions\",\n  \"patchedDependencies\",\n  \"patchesDir\",\n  \"allowUnusedPatches\",\n  \"allowedDeprecatedVersions\",\n  \"ignoredOptionalDependencies\",\n  \"supportedArchitectures\",\n  \"configDependencies\",\n  \"resolutionMode\",\n  \"savePrefix\",\n  \"saveExact\",\n  // Supply-chain posture\n  \"trustPolicy\",\n  \"trustPolicyExclude\",\n  \"trustPolicyIgnoreAfter\",\n  \"blockExoticSubdeps\",\n  \"minimumReleaseAgeExcludePrune\",\n  // Peer dependencies\n  \"autoInstallPeers\",\n  \"strictPeerDependencies\",\n  \"dedupePeerDependents\",\n  \"resolvePeersFromWorkspaceRoot\",\n  \"peerDependencyRules\",\n  // Workspace semantics\n  \"linkWorkspacePackages\",\n  \"preferWorkspacePackages\",\n  \"injectWorkspacePackages\",\n  \"dedupeInjectedDeps\",\n  \"syncInjectedDepsAfterScripts\",\n  \"saveWorkspaceProtocol\",\n  \"includeWorkspaceRoot\",\n  \"sharedWorkspaceLockfile\",\n  \"disallowWorkspaceCycles\",\n  \"hoistWorkspacePackages\",\n  \"requiredScripts\",\n  // Layout and lockfile\n  \"nodeLinker\",\n  \"hoistPattern\",\n  \"publicHoistPattern\",\n  \"shamefullyHoist\",\n  \"preferFrozenLockfile\",\n  \"peersSuffixMaxLength\",\n  // Scripts, engines, publish\n  \"enablePrePostScripts\",\n  \"nodeOptions\",\n  \"engineStrict\",\n  \"gitChecks\",\n  \"publishBranch\",\n  \"provenance\",\n  \"embedReadme\",\n] as const satisfies ReadonlyArray<keyof PnpmWorkspaceOptions>;\n\n/**\n * A curated setting name.\n */\nexport type PnpmCuratedSettingKey = (typeof CURATED_SETTING_KEYS)[number];\n\n/**\n * YAML keys the emitter owns, mapped to the typed option that produces them.\n *\n * `additionalSettings` is validated against this map: a passthrough key that\n * appears here is rejected with a message naming the option to use instead.\n * Most entries are identity mappings; the exceptions are the structural keys\n * whose option name differs from the emitted key.\n */\nconst RESERVED_YAML_KEYS: { [yamlKey: string]: string } = {\n  // Structural keys whose option name differs from the emitted YAML key.\n  packages: \"subprojects\",\n  catalog: \"defaultCatalog\",\n  catalogs: \"namedCatalogs\",\n  // Settings emitted by the pre-existing typed surface.\n  minimumReleaseAge: \"minimumReleaseAge\",\n  minimumReleaseAgeExclude: \"minimumReleaseAgeExclude\",\n  onlyBuiltDependencies: \"onlyBuiltDependencies\",\n  ignoredBuiltDependencies: \"ignoredBuiltDependencies\",\n  allowBuilds: \"allowBuilds\",\n  confirmModulesPurge: \"confirmModulesPurge\",\n  strictDepBuilds: \"strictDepBuilds\",\n  verifyDepsBeforeRun: \"verifyDepsBeforeRun\",\n  catalogMode: \"catalogMode\",\n  cleanupUnusedCatalogs: \"cleanupUnusedCatalogs\",\n  minimumReleaseAgeStrict: \"minimumReleaseAgeStrict\",\n  minimumReleaseAgeIgnoreMissingTime: \"minimumReleaseAgeIgnoreMissingTime\",\n  // Settings with bespoke emission.\n  neverBuiltDependencies: \"neverBuiltDependencies\",\n  catalogPrune: \"catalogPrune\",\n  update: \"update\",\n  updateConfig: \"updateConfig\",\n  // Every curated passthrough setting is an identity mapping.\n  ...Object.fromEntries(CURATED_SETTING_KEYS.map((key) => [key, key])),\n};\n\nexport class PnpmWorkspace extends Component {\n  /**\n   * Get the pnpm workspace component of a project. If it does not exist,\n   * return undefined.\n   *\n   * @param project - The project to query.\n   * @returns The PnpmWorkspace component if present, otherwise undefined.\n   */\n  public static of(project: Project): PnpmWorkspace | undefined {\n    const isDefined = (c: Component): c is PnpmWorkspace =>\n      c instanceof PnpmWorkspace;\n    return project.root.components.find(isDefined);\n  }\n\n  /**\n   * Filename for the pnpm workspace file.\n   */\n  public readonly fileName: string;\n\n  /**\n   * To reduce the risk of installing compromised packages, you can delay the\n   * installation of newly published versions. In most cases, malicious releases\n   * are discovered and removed from the registry within an hour.\n   *\n   * minimumReleaseAge defines the minimum number of minutes that must pass\n   * after a version is published before pnpm will install it. This applies to\n   * all dependencies, including transitive ones.\n   *\n   * Note: this should match depsUpgradeOptions.cooldown in the project config.\n   *\n   * See: https://pnpm.io/settings#minimumreleaseage\n   */\n  public minimumReleaseAge: ValueOf<typeof MINIMUM_RELEASE_AGE>;\n\n  /**\n   * If you set minimumReleaseAge but need certain dependencies to always\n   * install the newest version immediately, you can list them under\n   * minimumReleaseAgeExclude. The exclusion works by package name and applies\n   * to all versions of that package.\n   *\n   * See: https://pnpm.io/settings#minimumreleaseageexclude\n   */\n  public minimumReleaseAgeExclude: Array<string>;\n\n  /**\n   * A map of package names to booleans controlling whether each package may\n   * execute lifecycle scripts during install. `true` allows the scripts;\n   * `false` silently blocks them.\n   *\n   * pnpm 11+ replaced `onlyBuiltDependencies` and `ignoredBuiltDependencies`\n   * with this single map. Configulator translates the deprecated input\n   * fields into `allowBuilds` automatically and emits both legacy and new\n   * keys in the generated YAML for pnpm 10/11 cross-version compatibility.\n   *\n   * See: https://pnpm.io/settings#allowbuilds\n   */\n  public allowBuilds: { [packageName: string]: boolean };\n\n  /**\n   * A list of package names that are allowed to execute \"preinstall\",\n   * \"install\", and/or \"postinstall\" scripts during installation. Only the\n   * packages listed in this array will be able to run those lifecycle scripts.\n   * If onlyBuiltDependenciesFile and neverBuiltDependencies are omitted, this\n   * configuration option will default to blocking all install scripts.\n   *\n   * You may restrict allowances to specific versions (and lists of versions\n   * using a disjunction with ||). When versions are specified, only those\n   * versions of the package may run lifecycle scripts:\n   *\n   * See: https://pnpm.io/settings#onlybuiltdependencies\n   *\n   * @deprecated Deprecated in pnpm 11; configulator emits both legacy and\n   *             new keys for cross-version compatibility — pnpm 10 honors\n   *             the legacy keys, pnpm 11 honors `allowBuilds`. Prefer\n   *             `allowBuilds` as the input field going forward; entries\n   *             supplied here translate to `allowBuilds[<package>] = true`.\n   */\n  public onlyBuiltDependencies: Array<string>;\n\n  /**\n   * A list of package names that are NOT allowed to execute \"preinstall\",\n   * \"install\", and/or \"postinstall\" scripts during installation and will not\n   * warn or ask to be executed.\n   *\n   * This is useful when you want to hide the warning because you know the\n   * lifecycle scripts are not needed.\n   *\n   * https://pnpm.io/settings#ignoredbuiltdependencies\n   *\n   * @deprecated Deprecated in pnpm 11; configulator emits both legacy and\n   *             new keys for cross-version compatibility — pnpm 10 honors\n   *             the legacy keys, pnpm 11 honors `allowBuilds`. Prefer\n   *             `allowBuilds` as the input field going forward; entries\n   *             supplied here translate to `allowBuilds[<package>] = false`.\n   */\n  public ignoredBuiltDependencies: Array<string>;\n\n  /**\n   * Additional subproject paths to include in the workspace packages array.\n   * These will be combined with any subprojects discovered via projen's\n   * project.subprojects property.\n   */\n  public subprojects: Array<string>;\n\n  /**\n   * Default catalog of reusable dependency version ranges.\n   *\n   * The default catalog is used to define dependency versions as reusable constants\n   * that can be referenced in package.json files using the catalog: protocol.\n   *\n   * See:https://pnpm.io/catalogs\n   */\n  public defaultCatalog?: { [key: string]: string };\n\n  /**\n   * Named catalogs of reusable dependency version ranges.\n   *\n   * Multiple named catalogs with arbitrarily chosen names can be configured under the `catalogs` key.\n   *\n   * See: https://pnpm.io/catalogs\n   */\n  public namedCatalogs?: {\n    [catalogName: string]: { [dependencyName: string]: string };\n  };\n\n  /**\n   * Skip the interactive `node_modules` purge prompt so headless consumers\n   * don't abort mid-synth. Introduced in pnpm 11.0.\n   *\n   * @see https://pnpm.io/settings#confirmmodulespurge\n   */\n  public confirmModulesPurge?: boolean;\n\n  /**\n   * Fail (`true`) or warn (`false`) when a dependency's build script has\n   * not been explicitly approved via `allowBuilds`. Introduced in pnpm 10.3.\n   *\n   * @see https://pnpm.io/settings#strictdepbuilds\n   */\n  public strictDepBuilds?: boolean;\n\n  /**\n   * Behavior of `pnpm run` / `pnpm exec` when the lockfile drifts from\n   * `node_modules`. Use `\"install\"` (or `false`) for non-TTY callers.\n   *\n   * @see https://pnpm.io/settings#verifydepsbeforerun\n   */\n  public verifyDepsBeforeRun?: \"install\" | \"warn\" | \"error\" | \"prompt\" | false;\n\n  /**\n   * Catalog enforcement mode. Introduced in pnpm 10.12.1.\n   *\n   * @see https://pnpm.io/settings#catalogmode\n   */\n  public catalogMode?: \"manual\" | \"prefer\" | \"strict\";\n\n  /**\n   * Whether unused catalog entries are pruned on install.\n   * Introduced in pnpm 10.15.\n   *\n   * @see https://pnpm.io/settings#cleanupunusedcatalogs\n   */\n  public cleanupUnusedCatalogs?: boolean;\n\n  /**\n   * Whether `minimumReleaseAge` resolution fails when no version satisfies\n   * the age constraint. Introduced in pnpm 11.0.\n   *\n   * @default false\n   *\n   * @see https://pnpm.io/settings#minimumreleaseagestrict\n   */\n  public minimumReleaseAgeStrict?: boolean;\n\n  /**\n   * Whether `minimumReleaseAge` skips the age check for registries lacking\n   * timestamp metadata. Introduced in pnpm 11.0.\n   *\n   * @see https://pnpm.io/settings#minimumreleaseageignoremissingtime\n   */\n  public minimumReleaseAgeIgnoreMissingTime?: boolean;\n\n  /**\n   * Values for every curated setting the consumer supplied, keyed by setting\n   * name. A setting left undefined is absent from this record and therefore\n   * omitted from the generated YAML, so consumers who configure nothing get\n   * byte-identical output.\n   */\n  private readonly curatedSettings: { [settingName: string]: unknown };\n\n  /**\n   * Verbatim passthrough settings supplied via `additionalSettings`.\n   */\n  private readonly additionalSettings: { [settingName: string]: unknown };\n\n  constructor(project: Project, options: PnpmWorkspaceOptions = {}) {\n    super(project);\n\n    /***************************************************************************\n     *\n     * CLEAR package,json\n     *\n     * It appears that if ANY pnpm settings exist in the package.json file, all\n     * of the setting in the pnpm-workspace.yaml file are ignored. so we need to\n     * clear out anything that was placed into the package.json file.\n     *\n     **************************************************************************/\n\n    project.tryFindObjectFile(\"package.json\")?.addDeletionOverride(\"pnpm\");\n\n    /***************************************************************************\n     *\n     * Setup pnpm-workspace.yaml file.\n     *\n     * Now that the package.json file is cleared of any pnpm settings, we can\n     * safely write settings to the pnpm-workspace.yaml file.\n     *\n     **************************************************************************/\n\n    /**\n     * Set filename to default if not provided.\n     */\n    this.fileName = options.fileName ?? \"pnpm-workspace.yaml\";\n\n    /**\n     * Set minimum release age; default ONE_WEEK when not provided.\n     */\n    this.minimumReleaseAge =\n      options.minimumReleaseAge ?? MINIMUM_RELEASE_AGE.ONE_WEEK;\n\n    /**\n     * Set minimum release age exclude to empty array if not provided\n     */\n    this.minimumReleaseAgeExclude = options.minimumReleaseAgeExclude\n      ? [\"@codedrifters/*\", ...options.minimumReleaseAgeExclude]\n      : [\"@codedrifters/*\"];\n\n    /**\n     * Set only built dependencies to empty array if not provided\n     */\n    this.onlyBuiltDependencies = options.onlyBuiltDependencies\n      ? options.onlyBuiltDependencies\n      : [];\n\n    /**\n     * Set ignored built dependencies to empty array if not provided\n     */\n    this.ignoredBuiltDependencies = options.ignoredBuiltDependencies\n      ? options.ignoredBuiltDependencies\n      : [];\n\n    /**\n     * Set allowBuilds map; default empty object when not provided.\n     */\n    this.allowBuilds = options.allowBuilds ?? {};\n\n    /**\n     * Store additional subproject paths if provided\n     */\n    this.subprojects = options.subprojects ?? [];\n\n    /**\n     * Store catalog if provided\n     */\n    this.defaultCatalog = options.defaultCatalog;\n\n    /**\n     * Store named catalogs if provided\n     */\n    this.namedCatalogs = options.namedCatalogs;\n\n    /**\n     * Store pnpm 11 headless / non-TTY options. Each is left undefined when\n     * the consumer doesn't supply it so the generated YAML omits the key\n     * and pnpm's built-in default applies.\n     */\n    this.confirmModulesPurge = options.confirmModulesPurge;\n    this.strictDepBuilds = options.strictDepBuilds;\n    this.verifyDepsBeforeRun = options.verifyDepsBeforeRun;\n\n    /**\n     * Store catalog tuning options. Same omit-when-undefined contract.\n     */\n    this.catalogMode = options.catalogMode;\n    this.cleanupUnusedCatalogs = options.cleanupUnusedCatalogs;\n\n    /**\n     * Store minimumReleaseAge tuning options. The omit-when-undefined contract\n     * applies per-option here, not to the block as a whole:\n     * `minimumReleaseAgeStrict` defaults to `false` and therefore always emits\n     * into the generated YAML, while `minimumReleaseAgeIgnoreMissingTime` is\n     * omitted when undefined so pnpm's built-in default applies.\n     */\n    this.minimumReleaseAgeStrict = options.minimumReleaseAgeStrict ?? false;\n    this.minimumReleaseAgeIgnoreMissingTime =\n      options.minimumReleaseAgeIgnoreMissingTime;\n\n    /**\n     * Collect the curated settings the consumer actually supplied. Undefined\n     * values are never recorded, which is what keeps the omit-when-undefined\n     * contract (and therefore snapshot stability) intact.\n     *\n     * The four bespoke settings are collected here too so `setting()` can\n     * read them back uniformly; their *emission* is handled separately\n     * because each one composes with or supersedes another key.\n     */\n    this.curatedSettings = {};\n    for (const key of [\n      ...CURATED_SETTING_KEYS,\n      \"neverBuiltDependencies\",\n      \"catalogPrune\",\n      \"update\",\n      \"updateConfig\",\n    ] as ReadonlyArray<keyof PnpmWorkspaceOptions>) {\n      const value = options[key];\n      if (value !== undefined) {\n        this.curatedSettings[key] = value;\n      }\n    }\n\n    /**\n     * Validate the passthrough tier. A key that configulator already emits\n     * would silently shadow (or be shadowed by) the typed field, so reject\n     * it up front and name the option to use instead.\n     */\n    this.additionalSettings = { ...options.additionalSettings };\n    for (const settingName of Object.keys(this.additionalSettings)) {\n      const typedOption = RESERVED_YAML_KEYS[settingName];\n      if (typedOption !== undefined) {\n        throw new Error(\n          `additionalSettings[\"${settingName}\"] collides with a key that ${this.constructor.name} already emits. ` +\n            `Use the \\`${typedOption}\\` option instead of passing \"${settingName}\" through additionalSettings.`,\n        );\n      }\n    }\n\n    /**\n     * In case that this file is in a package, don't package it.\n     */\n    project.addPackageIgnore(this.fileName);\n\n    /***************************************************************************\n     *\n     * RECONCILE with projen's native pnpm-workspace generation.\n     *\n     * projen 0.101+ unconditionally registers its own `PnpmWorkspaceYaml`\n     * component (writing `pnpm-workspace.yaml`) for every pnpm project. This\n     * richer PnpmWorkspace owns the file instead, so remove projen's native\n     * component first to avoid projen's \"there is already a file\" synth error.\n     * `tryRemoveFile` is a no-op on older projen that never registered it.\n     *\n     **************************************************************************/\n\n    project.tryRemoveFile(this.fileName);\n\n    /**\n     * Write pnpm workspace file\n     */\n    new YamlFile(this.project, this.fileName, {\n      obj: () => {\n        const pnpmConfig: any = {};\n        const packages = new Array<string>();\n\n        /**\n         * Add projen subprojects to the packages array.\n         */\n        for (const subproject of project.subprojects) {\n          // grab the relative out directory\n          packages.push(relative(this.project.outdir, subproject.outdir));\n        }\n\n        /**\n         * Add additional subproject paths provided via options.\n         * Use a Set to deduplicate paths to avoid including the same\n         * subproject multiple times.\n         */\n        const packageSet = new Set(packages);\n        for (const subprojectPath of this.subprojects) {\n          packageSet.add(subprojectPath);\n        }\n\n        /**\n         * Convert back to array if we added any additional paths\n         */\n        if (this.subprojects.length > 0) {\n          packages.length = 0;\n          packages.push(...packageSet);\n        }\n\n        /**\n         * Set minimum release age.\n         */\n        pnpmConfig.minimumReleaseAge = this.minimumReleaseAge;\n\n        /**\n         * Set minimum release age exclude if any are provided.\n         */\n        if (this.minimumReleaseAgeExclude.length > 0) {\n          pnpmConfig.minimumReleaseAgeExclude = this.minimumReleaseAgeExclude;\n        }\n\n        /**\n         * Build the merged allowBuilds map. Deprecated and adjacent\n         * build-blocking fields translate silently, in precedence order:\n         *   - onlyBuiltDependencies entries become allowBuilds[pkg] = true\n         *   - ignoredBuiltDependencies entries become allowBuilds[pkg] = false\n         *   - neverBuiltDependencies entries become allowBuilds[pkg] = false\n         * Explicit `allowBuilds` entries always win on key collisions.\n         *\n         * Folding `neverBuiltDependencies` into the same map keeps the\n         * derived legacy allow/deny arrays consistent with it — otherwise a\n         * package listed there could still surface in the emitted\n         * `onlyBuiltDependencies` allow-list and contradict itself.\n         */\n        const neverBuiltDependencies = (this.curatedSettings\n          .neverBuiltDependencies ?? []) as Array<string>;\n\n        const mergedAllowBuilds: { [packageName: string]: boolean } = {};\n        for (const pkg of this.onlyBuiltDependencies) {\n          mergedAllowBuilds[pkg] = true;\n        }\n        for (const pkg of this.ignoredBuiltDependencies) {\n          mergedAllowBuilds[pkg] = false;\n        }\n        for (const pkg of neverBuiltDependencies) {\n          mergedAllowBuilds[pkg] = false;\n        }\n        for (const [pkg, allowed] of Object.entries(this.allowBuilds)) {\n          mergedAllowBuilds[pkg] = allowed;\n        }\n\n        /**\n         * Emit hybrid YAML for pnpm 10/11 cross-version compatibility. The\n         * legacy `onlyBuiltDependencies` / `ignoredBuiltDependencies` arrays\n         * are derived from the final merged map (not echoed from input)\n         * so an explicit `allowBuilds: { foo: true }` still produces the\n         * legacy keys, and explicit-allowBuilds precedence flows through.\n         *\n         * pnpm 10 silently ignores unknown YAML keys and falls through to\n         * its post-Rspack-attack default of \"block ALL build scripts\" when\n         * only `allowBuilds` is present — emitting the legacy arrays keeps\n         * pnpm-10 consumers working. pnpm 11 honors `allowBuilds` directly.\n         *\n         * Both legacy arrays are sorted alphabetically for deterministic\n         * snapshot output.\n         */\n        const allowList: Array<string> = [];\n        const denyList: Array<string> = [];\n        for (const [pkg, allowed] of Object.entries(mergedAllowBuilds)) {\n          if (allowed) {\n            allowList.push(pkg);\n          } else {\n            denyList.push(pkg);\n          }\n        }\n        allowList.sort();\n        denyList.sort();\n\n        if (allowList.length > 0) {\n          pnpmConfig.onlyBuiltDependencies = allowList;\n        }\n        if (denyList.length > 0) {\n          pnpmConfig.ignoredBuiltDependencies = denyList;\n        }\n\n        /**\n         * Emit `neverBuiltDependencies` verbatim alongside the derived keys.\n         * It is a pnpm setting in its own right, so the array is preserved\n         * as supplied even though its entries also appear as `false` in the\n         * merged map above.\n         */\n        if (neverBuiltDependencies.length > 0) {\n          pnpmConfig.neverBuiltDependencies = neverBuiltDependencies;\n        }\n\n        if (Object.keys(mergedAllowBuilds).length > 0) {\n          pnpmConfig.allowBuilds = mergedAllowBuilds;\n        }\n\n        /**\n         * Set default catalog if provided.\n         */\n        if (\n          this.defaultCatalog &&\n          Object.keys(this.defaultCatalog).length > 0\n        ) {\n          pnpmConfig.catalog = this.defaultCatalog;\n        }\n\n        /**\n         * Set named catalogs if provided.\n         */\n        if (this.namedCatalogs && Object.keys(this.namedCatalogs).length > 0) {\n          pnpmConfig.catalogs = this.namedCatalogs;\n        }\n\n        /**\n         * Emit each pnpm 11 tuning key only when the consumer supplied a\n         * value. Omitting the key preserves pnpm's built-in default for\n         * consumers that don't opt in, and keeps the omitted-default\n         * snapshot stable.\n         */\n        if (this.confirmModulesPurge !== undefined) {\n          pnpmConfig.confirmModulesPurge = this.confirmModulesPurge;\n        }\n        if (this.strictDepBuilds !== undefined) {\n          pnpmConfig.strictDepBuilds = this.strictDepBuilds;\n        }\n        if (this.verifyDepsBeforeRun !== undefined) {\n          pnpmConfig.verifyDepsBeforeRun = this.verifyDepsBeforeRun;\n        }\n        if (this.catalogMode !== undefined) {\n          pnpmConfig.catalogMode = this.catalogMode;\n        }\n        /**\n         * `catalogPrune` is pnpm's current spelling for `cleanupUnusedCatalogs`\n         * and wins whenever both are supplied, mirroring pnpm's own\n         * `catalogPrune ??= cleanupUnusedCatalogs` resolution. Only the\n         * winning key is emitted: emitting both would be redundant, and\n         * emitting the deprecated spelling when the modern one was requested\n         * would misrepresent the consumer's intent. When only the deprecated\n         * option is supplied it is emitted unchanged, so consumers on older\n         * pnpm majors keep working.\n         */\n        const catalogPrune = this.curatedSettings.catalogPrune as\n          boolean | undefined;\n        if (catalogPrune !== undefined) {\n          pnpmConfig.catalogPrune = catalogPrune;\n        } else if (this.cleanupUnusedCatalogs !== undefined) {\n          pnpmConfig.cleanupUnusedCatalogs = this.cleanupUnusedCatalogs;\n        }\n        if (this.minimumReleaseAgeStrict !== undefined) {\n          pnpmConfig.minimumReleaseAgeStrict = this.minimumReleaseAgeStrict;\n        }\n        if (this.minimumReleaseAgeIgnoreMissingTime !== undefined) {\n          pnpmConfig.minimumReleaseAgeIgnoreMissingTime =\n            this.minimumReleaseAgeIgnoreMissingTime;\n        }\n\n        /**\n         * Emit every curated setting the consumer supplied, in the fixed\n         * order declared by CURATED_SETTING_KEYS. Settings the consumer left\n         * alone were never recorded, so they stay out of the YAML entirely\n         * and pnpm's own default applies.\n         */\n        for (const settingName of CURATED_SETTING_KEYS) {\n          const value = this.curatedSettings[settingName];\n          if (value !== undefined) {\n            pnpmConfig[settingName] = value;\n          }\n        }\n\n        /**\n         * `update` supersedes the deprecated `updateConfig`. Unlike the\n         * catalog pair, pnpm actively warns when it sees both keys (\"the\n         * deprecated updateConfig setting is ignored in favor of update\"),\n         * so emitting both would print a warning on every install. Emit only\n         * the winner.\n         */\n        const update = this.curatedSettings.update;\n        const updateConfig = this.curatedSettings.updateConfig;\n        if (update !== undefined) {\n          pnpmConfig.update = update;\n        } else if (updateConfig !== undefined) {\n          pnpmConfig.updateConfig = updateConfig;\n        }\n\n        /**\n         * Passthrough tier, emitted last. Keys were validated against\n         * RESERVED_YAML_KEYS at construction, so nothing here can shadow a\n         * typed field or a structural key.\n         */\n        for (const [settingName, value] of Object.entries(\n          this.additionalSettings,\n        )) {\n          pnpmConfig[settingName] = value;\n        }\n\n        /**\n         * Return the final pnpm config object.\n         */\n        return {\n          ...(packages.length > 0 ? { packages } : {}),\n          ...(pnpmConfig ? { ...pnpmConfig } : {}),\n        };\n      },\n    });\n  }\n\n  /**\n   * Read back a configured pnpm setting by name.\n   *\n   * Covers both tiers: curated settings added since the original typed\n   * surface, and verbatim `additionalSettings` passthrough keys. Returns\n   * `undefined` when the setting was not configured, which is the same\n   * signal the emitter uses to omit the key from the generated YAML.\n   *\n   * The fifteen original options (`minimumReleaseAge`, `allowBuilds`,\n   * `defaultCatalog`, and friends) remain available as public fields and are\n   * not served by this accessor.\n   *\n   * @param settingName - The pnpm setting name, e.g. `\"overrides\"`.\n   * @returns The configured value, or `undefined` when unset.\n   */\n  public setting(settingName: string): unknown {\n    if (settingName in this.curatedSettings) {\n      return this.curatedSettings[settingName];\n    }\n    return this.additionalSettings[settingName];\n  }\n}\n\n/**\n * @deprecated Use `MINIMUM_RELEASE_AGE` instead. This alias will be removed in a future major release.\n */\nexport const MIMIMUM_RELEASE_AGE = MINIMUM_RELEASE_AGE;\n","import { Project } from \"projen/lib\";\nimport { PnpmWorkspace } from \"../../pnpm/pnpm-workspace\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\nimport { hasComponent } from \"./utils\";\n\n/**\n * PNPM bundle — auto-detected when the PnpmWorkspace component is present.\n */\nexport const pnpmBundle: AgentRuleBundle = {\n  name: \"pnpm\",\n  description: \"PNPM workspace rules and dependency management conventions\",\n  appliesWhen: (project: Project) => hasComponent(project, PnpmWorkspace),\n  rules: [\n    {\n      name: \"pnpm-workspace\",\n      description: \"PNPM workspace and dependency management conventions\",\n      scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n      filePatterns: [\"package.json\", \"pnpm-workspace.yaml\", \"pnpm-lock.yaml\"],\n      content: [\n        \"# PNPM Workspace Conventions\",\n        \"\",\n        \"## Package Management\",\n        \"\",\n        \"- Use **PNPM** for package management\",\n        \"- Workspace configuration in `pnpm-workspace.yaml`\",\n        \"- Dependencies managed through Projen, not directly in `package.json`\",\n        \"- **Always use workspace dependencies** (`workspace:*` or `workspace:^`) for packages within this monorepo\",\n        \"- Never use published NPM versions of internal packages; always reference the local workspace version\",\n        \"\",\n        \"## Dependency Management\",\n        \"\",\n        \"**DO:**\",\n        \"- Configure dependencies in Projen configuration files (`.projenrc.ts` or `projenrc/*.ts`)\",\n        \"- Add dependencies to `deps`, `devDeps`, or `peerDeps` arrays in project configuration\",\n        '- Use catalog dependencies when available (e.g., `\"aws-cdk-lib@catalog:\"`)',\n        \"- Ask the user to run the three-step regen sequence after updating dependency configuration: `pnpm i`, then `pnpm exec projen`, then `pnpm i` again. The leading `pnpm i` syncs `node_modules` with the lockfile so synth runs against the right configulator/projen/plugin versions; the trailing `pnpm i` picks up any dependency changes projen wrote during synth.\",\n        \"\",\n        \"**DO NOT:**\",\n        \"- Run `npm install some-package`\",\n        \"- Run `pnpm add some-package`\",\n        \"- Run `yarn add some-package`\",\n        \"- Manually edit `package.json` dependencies\",\n        \"\",\n        \"Manual package installation creates conflicts with Projen-managed files.\",\n      ].join(\"\\n\"),\n      tags: [\"workflow\"],\n    },\n  ],\n};\n","import {\n  DELEGATION_ELIGIBLE_ORIGIN_LIST,\n  DELEGATION_ELIGIBLE_ORIGIN_PHRASE,\n} from \"./origin-label\";\nimport { ResolvedPrReviewPolicy } from \"./pr-review-policy\";\nimport { DEFAULT_SHARED_INDEX_PATHS } from \"./shared-editing\";\nimport { AgentSkill } from \"../types\";\n\n/**\n * `/babysit-prs` — the operator loop that sits **above** the\n * autonomous PR pipeline (codedrifters/packages#851).\n *\n * The pipeline (`pr-reviewer` reviewing, arming `--auto --squash`, and\n * merging; `issue-worker` pulling fix-lists; the maintenance sweep\n * reconciling stale leases) already drives the overwhelming majority of\n * open PRs to merge with no help. This skill is the thin operator layer\n * that **confirms** the pipeline is keeping up and intervenes only on\n * the small set of states the pipeline structurally cannot self-heal.\n *\n * The skill body is a trimmed port of a consumer-authored operator\n * runbook distilled from a ~20-hour, ~79-cycle babysitting session. Only\n * the **durable core** plus one **residual** handler survived the port —\n * four of the runbook's five interim handler classes were retired\n * upstream and deliberately are not reproduced here:\n *\n * - artifact-tag strip (retired by #845 — hook env vars fixed),\n * - review-label deadlock clear (retired by #846 — the pull-based\n *   `review:needs-worker` marker plus the maintenance sweep's\n *   stale-lease reclaim replaced the hand-clear),\n * - label-less PR drive (retired by #848 and #859 — sweep eligibility\n *   was never origin-gated and the `origin:agent` umbrella label closed\n *   the delegation gap),\n * - requirement-ID renumber (retired by #850 — IDs are reserved at\n *   issue-creation time).\n *\n * The surviving residual handler is shared-index conflict surgery, and\n * it is annotated with the issue that retires it so a future pass can\n * delete it mechanically.\n *\n * @see buildBabysitPrsSkill\n */\n\n/**\n * GitHub issue that retires the residual **R1** shared-index conflict\n * handler. Kept as a named constant so the annotation in the skill body\n * and the deletion checklist can never drift apart.\n */\nexport const BABYSIT_R1_RETIRING_ISSUE = 916;\n\n/**\n * Floor for the stall window, in minutes.\n *\n * Every \"act on this\" branch in the skill is gated on a signal having\n * held for at least this long. The floor exists so a tight `--interval`\n * cannot collapse the window to zero and turn the operator into a\n * racer: even at a one-minute cadence, a freshly-armed PR gets a real\n * convergence window before anything touches it.\n */\nexport const BABYSIT_STALL_WINDOW_FLOOR_MINUTES = 30;\n\n/**\n * Render the CI-verification paragraph, reflecting the consumer's\n * resolved `ci-verification.required-workflows`.\n *\n * The list is resolved at **bundle-build time** and passed into the\n * skill builder rather than patched into the rendered skill afterwards,\n * so the skill enters the bundle already carrying the consumer's\n * settings and any later `ruleExtensions` composition sees final\n * content.\n */\nfunction renderCiVerificationLines(\n  policy: ResolvedPrReviewPolicy,\n): ReadonlyArray<string> {\n  const workflows = policy.ciVerification.requiredWorkflows;\n  const gate =\n    workflows.length === 0\n      ? [\n          \"  This project configures **no** explicit required-workflow list,\",\n          \"  so treat **every** workflow run observed for the head SHA as\",\n          \"  required — the conservative zero-config default.\",\n        ]\n      : [\n          \"  This project gates on the following required workflows; a\",\n          \"  listed workflow with no run for the head SHA counts as\",\n          \"  pending, never green:\",\n          \"\",\n          ...workflows.map((name) => `  - \\`${name}\\``),\n        ];\n\n  return [\n    \"- **CI status.** Read it exactly the way the `pr-reviewer` does —\",\n    \"  never invent a second contract. The primary read is the check-runs\",\n    \"  rollup (`gh pr checks <n>`). When the token is a **fine-grained**\",\n    \"  PAT that read returns\",\n    \"  `HTTP 403: Resource not accessible by personal access token`;\",\n    \"  fall back to the Actions runs API, which a fine-grained PAT with\",\n    \"  `Actions: Read-only` can read:\",\n    \"\",\n    \"  ```bash\",\n    '  gh api \"repos/{{repository.owner}}/{{repository.name}}/actions/runs?head_sha=<SHA>&per_page=100\" \\\\',\n    \"    --jq '.workflow_runs[] | {name, status, conclusion}'\",\n    \"  ```\",\n    \"\",\n    ...gate,\n    \"\",\n    \"  A 403 is a **visibility failure, not a green signal**. Never treat\",\n    \"  an unreadable rollup as passing.\",\n  ];\n}\n\n/**\n * Build the `/babysit-prs` operator skill.\n *\n * @param policy - Resolved PR-review policy. Only the\n * `ciVerification.requiredWorkflows` half is read today; taking the\n * whole struct keeps the signature stable if a later handler needs the\n * size carve-out.\n */\nexport function buildBabysitPrsSkill(\n  policy: ResolvedPrReviewPolicy,\n): AgentSkill {\n  return {\n    name: \"babysit-prs\",\n    description:\n      \"Operator sweep over the open-PR queue: confirm the autonomous pipeline is merging the clean majority and intervene only on the states it cannot self-heal\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Babysit Open Pull Requests\",\n      \"\",\n      \"One **operator cycle** over the open-PR queue in\",\n      \"**{{repository.owner}}/{{repository.name}}**. This skill is the\",\n      \"operator layer that sits *above* the autonomous PR pipeline — it\",\n      \"confirms the pipeline is keeping up and intervenes only on the\",\n      \"small set of states the pipeline **cannot self-heal**.\",\n      \"\",\n      \"It is **not** a second reviewer and **not** a second orchestrator.\",\n      \"Review and arming belong to `pr-reviewer`; issue-queue scanning and\",\n      \"dispatch belong to `orchestrator`. See **Composability** below for\",\n      \"the exact boundaries.\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"```\",\n      \"/babysit-prs [--interval <minutes>] [--once] [--dry-run]\",\n      \"```\",\n      \"\",\n      \"### Flags\",\n      \"\",\n      \"- **`--interval <minutes>`** — pin the cycle cadence instead of\",\n      \"  self-pacing. Also sets the stall window (see **Cadence**).\",\n      \"- **`--once`** — run a single cycle and stop without emitting a\",\n      \"  next-check recommendation. The default already runs exactly one\",\n      \"  cycle per invocation; `--once` additionally suppresses the\",\n      \"  `NEXT_CHECK_IN` line for callers that drive their own schedule.\",\n      \"- **`--dry-run`** — classify every open PR and report the action\",\n      \"  each class *would* take, without running any of them. Nothing is\",\n      \"  pushed, armed, labelled, or commented. Use it to inspect the\",\n      \"  queue before letting the skill act.\",\n      \"\",\n      \"One invocation is **one cycle**. To babysit continuously, drive the\",\n      \"skill from a loop or a scheduled task at the cadence it recommends.\",\n      \"\",\n      \"## Core principle — don't do redundant work\",\n      \"\",\n      \"The pipeline reliably reviews, arms `--auto --squash`, and merges\",\n      \"clean PRs on its own. **Do not** re-review, re-arm, rebase, or\",\n      \"otherwise drive a PR that is already progressing — you only race\",\n      \"the pipeline, restart CI, and burn tokens. In the reference session\",\n      \"this skill was distilled from, roughly **4 of every 5 cycles needed\",\n      \"no intervention at all**.\",\n      \"\",\n      \"Your job is the stuck classes in **Handlers** below. For everything\",\n      \"else: confirm it is defect-free, let the pipeline merge it, and\",\n      \"re-check next cycle. A cycle whose entire output is\",\n      \"`no action needed` is a **successful** cycle, not a wasted one.\",\n      \"\",\n      \"Two corollaries that decide most judgement calls:\",\n      \"\",\n      \"1. **Every act-on branch is gated on a stall window.** No PR is\",\n      \"   touched on the first cycle a signal appears. A signal must have\",\n      \"   held for at least the stall window before it counts as stuck.\",\n      \"2. **When in doubt, report and re-check.** Reporting a PR you did\",\n      \"   not understand costs one line of output. Acting on a PR the\",\n      \"   pipeline was already handling costs a restarted CI run, a\",\n      \"   contended lease, or a lost commit.\",\n      \"\",\n      \"## Prerequisites & environment\",\n      \"\",\n      \"- **`gh` must be on `PATH`.** Some non-interactive sessions start\",\n      \"  with a minimal `PATH` that omits the package-manager prefix.\",\n      \"  Resolve it **once** per session with `command -v gh`. If that\",\n      \"  fails, invoke `gh` by its absolute path for the rest of the\",\n      \"  session (`/opt/homebrew/bin/gh` on Homebrew macOS,\",\n      \"  `/usr/local/bin/gh` or `/home/linuxbrew/.linuxbrew/bin/gh`\",\n      \"  elsewhere). **Never prefix commands with `export PATH=…`** — a\",\n      \"  leading `export` stops the command string from matching the\",\n      \"  repo's `Bash(gh …)` permission rules, so every call is denied.\",\n      \"  Abort the cycle with a clear diagnostic if `gh` is still\",\n      \"  unresolvable — never fall back to raw `curl`.\",\n      \"- **Resolve the default branch from the repo, never hard-code it:**\",\n      \"\",\n      \"  ```bash\",\n      \"  default_branch=$(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name')\",\n      \"  ```\",\n      \"\",\n      ...renderCiVerificationLines(policy),\n      \"- **Foreground git only.** Run every git command as a discrete\",\n      \"  foreground invocation. Do not background them and do not build\",\n      \"  sleep-loops inside a cycle — the cadence between cycles is the\",\n      \"  only waiting this skill does.\",\n      \"- **Isolated worktree for all git surgery.** Never touch the user's\",\n      \"  working checkout. Create one detached worktree per session, reuse\",\n      \"  it across handlers, and remove it before the cycle ends:\",\n      \"\",\n      \"  ```bash\",\n      '  wt=\"${TMPDIR:-/tmp}/babysit-prs-wt\"',\n      '  git worktree add --detach \"$wt\" \"origin/$default_branch\"',\n      '  # …reuse: git -C \"$wt\" <cmd> …',\n      '  git worktree remove --force \"$wt\"   # always, even on abort',\n      \"  ```\",\n      \"\",\n      \"- **Never force-push.** Not `--force`, not `--force-with-lease`, on\",\n      \"  any branch, for any reason. Every recipe in this skill produces a\",\n      \"  fast-forward-pushable merge commit precisely so a plain\",\n      \"  `git push` suffices.\",\n      \"- **Scope of edits.** Only ever modify paths that the PR's **own\",\n      \"  diff already touches**. Never introduce a file the PR did not\",\n      \"  already carry, and never edit a lockfile (`pnpm-lock.yaml`,\",\n      \"  `yarn.lock`, `package-lock.json`, `**/*.lock`), anything under\",\n      \"  `**/.projen/**`, or any file whose first five lines carry a\",\n      \"  `~~ Generated by projen` / `// Generated by` marker. Those are\",\n      \"  regenerated by synth, not merged by hand.\",\n      \"- **Merge model.** Squash. Where the default branch is protected\",\n      \"  **strict** (require-up-to-date), armed PRs legitimately sit at\",\n      \"  `BEHIND` until refreshed — that is the protection working, not a\",\n      \"  defect. An armed `--auto --squash` survives a branch refresh.\",\n      \"\",\n      \"## Per-cycle procedure\",\n      \"\",\n      \"### Step 1 — Sweep\",\n      \"\",\n      \"```bash\",\n      \"gh pr list --state open --limit 100 \\\\\",\n      \"  --json number,title,isDraft,mergeable,mergeStateStatus,autoMergeRequest,labels,headRefName,updatedAt \\\\\",\n      \"  --jq '.[] | {n: .number, draft: .isDraft, mergeable, merge_state: .mergeStateStatus, armed: (.autoMergeRequest != null), labels: [.labels[].name], branch: .headRefName, updated: .updatedAt}'\",\n      \"```\",\n      \"\",\n      \"One JSON object per line, all filtering done **jq-side**. Do not\",\n      \"reformat the sweep into tab- or space-separated records and parse\",\n      \"them in the shell: a record whose fields can be empty (labels, most\",\n      \"commonly) collapses under the shell's default word-splitting and\",\n      \"silently shifts every later field. Keep the data in JSON from the\",\n      \"`gh` call to the classification decision.\",\n      \"\",\n      \"If the queue is empty, report `no open PRs`, emit the next-check\",\n      \"recommendation, and stop.\",\n      \"\",\n      \"### Step 2 — Compute the stall window\",\n      \"\",\n      `The stall window is **2 × the cycle interval**, floored at **${BABYSIT_STALL_WINDOW_FLOOR_MINUTES} minutes**.`,\n      \"A signal counts as *stalled* only when the PR's `updatedAt` is older\",\n      \"than the window. `updatedAt` is deliberately conservative — any\",\n      \"activity at all (a commit, a label, a comment, a reviewer pass)\",\n      \"resets it, which biases the skill toward waiting rather than acting.\",\n      \"That is the intended bias.\",\n      \"\",\n      \"### Step 3 — Classify each PR\",\n      \"\",\n      \"Assign **exactly one** class per PR, taking the first match walking\",\n      \"the table top to bottom:\",\n      \"\",\n      \"| # | Class | Signal | Action |\",\n      \"|---|-------|--------|--------|\",\n      \"| 1 | `DRAFT` | `isDraft` is true | none — the author has not asked for review |\",\n      \"| 2 | `IN-FLIGHT-DELEGATION` | `review:fixing` **and** `review:needs-worker` | none — a worker pull is queued (**D2**) |\",\n      \"| 3 | `CONFIRM-PENDING` | `review:fixing` without `review:needs-worker` | none unless stalled (**D2**) |\",\n      \"| 4 | `NEEDS-WORKER` | `review:needs-worker` without `review:fixing` | none unless stalled (**D2**) |\",\n      \"| 5 | `LABEL-ANOMALY` | `review:awaiting-human` **and** (`review:fixing` or `review:needs-worker`) | re-invoke the reviewer (**D2**) |\",\n      \"| 6 | `AWAITING-HUMAN` | `review:awaiting-human` alone | report, and check **R1** eligibility |\",\n      \"| 7 | `CI-RED` | required CI concluded `failure` / `timed_out` / `cancelled` | report only (**D4**) |\",\n      \"| 8 | `CONFLICT-SHARED-INDEX` | `mergeable` is `CONFLICTING` **and** every conflict is a shared-index row-insert race | **R1** surgery |\",\n      \"| 9 | `CONFLICT-OTHER` | `mergeable` is `CONFLICTING`, anything else | report only (**D4**) |\",\n      \"| 10 | `BEHIND-STALLED` | armed **and** `merge_state` is `BEHIND` **and** stalled | chase the branch (**D3**) |\",\n      \"| 11 | `UNREVIEWED-STALLED` | not armed, no `review:*` label, no reviewer-notes comment, **and** stalled | hand to `pr-reviewer` (**D1**) |\",\n      \"| 12 | `PROGRESSING` | anything else | none — the pipeline has it |\",\n      \"\",\n      \"Rows 2–4 are the pipeline's own legitimate intermediate states. They\",\n      \"are listed **above** the conflict and BEHIND rows on purpose: a PR\",\n      \"with a delegation in flight is being worked on right now, whatever\",\n      \"else its merge state says, and touching it contends the lease.\",\n      \"\",\n      \"### Step 4 — Act\",\n      \"\",\n      \"Run the handler named in the Action column. Under `--dry-run`,\",\n      \"print the handler that would run and move on without executing it.\",\n      \"\",\n      \"### Step 5 — Report and recommend a cadence\",\n      \"\",\n      \"Emit the report described in **Output**, then the next-check\",\n      \"recommendation from **Cadence** (unless `--once` was passed).\",\n      \"\",\n      \"## Handlers\",\n      \"\",\n      \"Four **durable** handlers (D1–D4) and one **residual** handler (R1).\",\n      \"The durable handlers reflect permanent properties of the pipeline\",\n      \"and branch protection; they do not go away. The residual handler is\",\n      \"isolated behind its own heading and annotated with the issue that\",\n      \"retires it, so deleting it is a mechanical edit.\",\n      \"\",\n      \"### D1 — Unreviewed and stalled → hand to `pr-reviewer` *(durable)*\",\n      \"\",\n      \"A PR that is not armed, carries no `review:*` label, has no sticky\",\n      \"`## Reviewer notes` comment, and has been idle past the stall window\",\n      \"was never picked up by a reviewer pass. Hand it to the reviewer —\",\n      \"**do not** review or arm it yourself:\",\n      \"\",\n      \"```\",\n      \"/review-pr <n>\",\n      \"```\",\n      \"\",\n      \"The reviewer applies the project's PR-review policy, decides\",\n      \"`auto-merge` vs `human-required`, and arms only when the policy\",\n      \"allows. Operator-arming an **unreviewed** PR bypasses that policy\",\n      \"entirely and is an anti-pattern (see **Anti-patterns**).\",\n      \"\",\n      \"Most PRs *do* get picked up on their own. Only hand over one that\",\n      \"has genuinely stalled.\",\n      \"\",\n      \"### D2 — Review-label states: classify and route, never hand-clear *(durable)*\",\n      \"\",\n      \"The delegation loop spans three passes and is coordinated entirely\",\n      \"by two labels: the `review:fixing` lease and the\",\n      \"`review:needs-worker` marker. Every combination below is a **valid**\",\n      \"position in that loop, not a deadlock:\",\n      \"\",\n      \"| Labels present | Meaning | Operator action |\",\n      \"|----------------|---------|-----------------|\",\n      \"| `review:fixing` + `review:needs-worker` | delegation in flight; a top-level `issue-worker` pass will pull it | **none** |\",\n      \"| `review:fixing` alone | worker finished and cleared its marker; a reviewer confirm pass owns the PR | none; if stalled, re-invoke `/review-pr <n>` |\",\n      \"| `review:needs-worker` alone | a fix-list is queued and unconsumed | none; if stalled, **report** — the worker's own scan pulls it |\",\n      \"| `review:awaiting-human` + either delegation label | **invariant violation** — a PR is either in the delegation loop or handed to a human, never both | re-invoke `/review-pr <n>` |\",\n      \"\",\n      \"**The operator never runs `gh pr edit --remove-label review:*`.**\",\n      \"This is the single most important rule in this handler, and it is a\",\n      \"deliberate reversal of how a human operator used to clear these.\",\n      \"\",\n      \"Hand-clearing was correct when a reviewer pass could hold the lease\",\n      \"with no mechanism to ever release it. That is no longer the shape of\",\n      \"the system. Three owners now reconcile these labels, and each one\",\n      \"clears exactly the label it owns:\",\n      \"\",\n      \"- The **reviewer's confirm pass** releases `review:fixing` after the\",\n      \"  worker's report lands.\",\n      \"- The **`issue-worker`** clears `review:needs-worker` as the\",\n      \"  mandatory, atomic completion of its hand-off — including when\",\n      \"  every fix-list item failed.\",\n      \"- The **maintenance sweep** reconciles both stuck states without a\",\n      \"  human: it re-arms `review:needs-worker` on an orphaned lease, and\",\n      \"  removes `review:needs-worker` on a consumed-but-uncleared wedge,\",\n      \"  posting an audit-trail comment either way.\",\n      \"\",\n      \"An operator who strips a label out from under those owners destroys\",\n      \"the state they key on: clearing `review:needs-worker` by hand makes\",\n      \"an unconsumed fix-list look consumed, so the confirm pass merges a\",\n      \"PR whose fixes were never applied; clearing `review:fixing` by hand\",\n      \"invites a second delegation on top of a live one. Re-invoking the\",\n      \"reviewer is strictly better in every case — its **Phase 2.8 label\",\n      \"reconciliation** step resolves genuine invariant violations\",\n      \"canonically, logs each correction on a `**Label reconciliation:**`\",\n      \"line in the sticky notes comment, and only ever *removes* a\",\n      \"contradicting label.\",\n      \"\",\n      \"So the durable operator capability here is **classification and\",\n      \"routing**, not clearing. If a label state persists across several\",\n      \"cycles even after a reviewer re-invocation, that is a pipeline bug —\",\n      \"report it and file an issue rather than papering over it by hand.\",\n      \"\",\n      \"### D3 — Armed but `BEHIND` past the stall window → chase *(durable)*\",\n      \"\",\n      \"Inherent to strict branch protection, not a bug: an armed PR must be\",\n      \"up to date with the default branch before it can merge, and a busy\",\n      \"default branch can outrun it. Give every freshly-armed or `BEHIND`\",\n      \"PR **one** convergence window first — they usually self-merge.\",\n      \"\",\n      \"Past the stall window, refresh the branch. Prefer the API, which\",\n      \"produces a merge commit server-side and needs no worktree:\",\n      \"\",\n      \"```bash\",\n      \"gh pr update-branch <n>\",\n      \"```\",\n      \"\",\n      \"If that is unavailable, do the same thing locally in the worktree\",\n      \"and push **without** force:\",\n      \"\",\n      \"```bash\",\n      'git -C \"$wt\" fetch origin',\n      'git -C \"$wt\" checkout -B \"<branch>\" \"origin/<branch>\"',\n      'git -C \"$wt\" merge --no-edit \"origin/$default_branch\"',\n      'git -C \"$wt\" push origin \"<branch>\"',\n      \"```\",\n      \"\",\n      \"**Merge, never rebase.** The PR branch is already published and\",\n      \"diverged, so a rebase rewrites history that others have fetched and\",\n      \"forces a `--force-with-lease` push this skill forbids. A merge\",\n      \"commit is fast-forward-pushable with a plain `git push`. Squash-merge\",\n      \"collapses the merge commit at merge time anyway, so it costs nothing\",\n      \"in the final history.\",\n      \"\",\n      \"If the merge conflicts, **abort it** (`git merge --abort`) and\",\n      \"re-classify the PR as a conflict class — do not resolve conflicts in\",\n      \"this handler.\",\n      \"\",\n      \"### D4 — Report-only classes *(durable)*\",\n      \"\",\n      \"Some classes are genuinely not operator work. Report them with one\",\n      \"line each and take no action:\",\n      \"\",\n      \"- **`CI-RED`** — a required workflow concluded red. A permanent\",\n      \"  failure is the author's or the reviewer's to fix, and the reviewer\",\n      \"  already flags it with `status:needs-attention`. Never rerun CI to\",\n      \"  see if it goes away, and never refresh the branch to restart it.\",\n      \"- **`CONFLICT-OTHER`** — a conflict outside the shared-index class.\",\n      \"  The reviewer's typed generic recipe delegates these to\",\n      \"  `issue-worker`; hand-merging one here duplicates that path and\",\n      \"  risks resolving it differently than the pipeline would.\",\n      \"- **`AWAITING-HUMAN`** — the reviewer finished and handed the merge\",\n      \"  decision to a human. Surface it so the human sees it. (Check **R1**\",\n      \"  eligibility first — a hand-off caused by a *failed* shared-index\",\n      \"  fix is the one case where the pipeline explicitly asked for this\",\n      \"  kind of help.)\",\n      \"- **`DRAFT`** — the author has not asked for review yet.\",\n      \"\",\n      `### R1 — Shared-index merge conflict *(residual — retires with #${BABYSIT_R1_RETIRING_ISSUE})*`,\n      \"\",\n      `> **Deleting this handler.** When #${BABYSIT_R1_RETIRING_ISSUE} lands, delete this`,\n      \"> entire `### R1` section, drop row 8 (`CONFLICT-SHARED-INDEX`) from\",\n      \"> the classification table, and delete the matching eval. Nothing\",\n      \"> else in this skill references it.\",\n      \"\",\n      \"Two PRs raced to insert a row into the same shared registry, index,\",\n      \"or feature-matrix page and the loser is `CONFLICTING`. The pipeline\",\n      \"handles the common case on its own: the reviewer classifies the\",\n      \"conflict, emits a `synthetic:rebase-shared-index` fix-list item, and\",\n      \"an `issue-worker` applies the typed re-insert recipe. **This handler\",\n      \"exists only for the cases where that delegation could not run.**\",\n      \"\",\n      \"#### Eligibility — all four must hold\",\n      \"\",\n      \"1. **Every** conflicting path matches one of the shared-index globs:\",\n      \"\",\n      ...DEFAULT_SHARED_INDEX_PATHS.map((p) => `   - \\`${p}\\``),\n      \"\",\n      \"2. **Every** conflict hunk touches data rows only. Inspect each\",\n      \"   `<<<<<<<` / `=======` / `>>>>>>>` hunk: every conflicting line\",\n      \"   must start with `| ` and be neither the table header row nor the\",\n      \"   `|---|---|` separator. If any hunk touches the frontmatter block,\",\n      \"   the page H1, surrounding prose, the header row, or the separator\",\n      \"   row, this is **not** a row-insert race — re-classify as\",\n      \"   `CONFLICT-OTHER` and report.\",\n      \"3. No conflicting path is a lockfile, lives under `**/.projen/**`, or\",\n      \"   carries a generated-file marker in its first five lines.\",\n      \"4. The PR does **not** carry `review:human-required`, and one of:\",\n      \"   - it carries `review:awaiting-human` **and** its most recent\",\n      \"     worker-report comment records a\",\n      \"     `synthetic:rebase-shared-index` item as `failed` — the pipeline\",\n      \"     tried, could not finish, and explicitly asked for a human; **or**\",\n      \"   - it has been `CONFLICTING` past the stall window with **neither**\",\n      \"     `review:fixing` nor `review:needs-worker` — no delegation is in\",\n      \"     flight and none fired.\",\n      \"\",\n      \"If any check fails, report the PR and move on. In particular a\",\n      \"`review:human-required` PR is never resolved here: pushing\",\n      \"operator-merged content into it expands the diff the human is\",\n      \"reviewing without their consent.\",\n      \"\",\n      \"#### Recipe\",\n      \"\",\n      \"Deliberately **identical** to the worker's typed\",\n      \"`synthetic:rebase-shared-index` recipe, so an operator resolution and\",\n      \"a pipeline resolution can never produce different content.\",\n      \"\",\n      \"```bash\",\n      'git -C \"$wt\" fetch origin',\n      'git -C \"$wt\" checkout -B \"<branch>\" \"origin/<branch>\"',\n      'git -C \"$wt\" merge --no-edit \"origin/$default_branch\"',\n      \"```\",\n      \"\",\n      \"For each conflicting file, resolve by **union**: the `<<<<<<< HEAD`\",\n      \"side carries this PR's row and the other side carries the row that\",\n      \"already merged. Keep **both**, re-inserted in the file's declared\",\n      \"sort order (alphabetical on the first column unless the page\",\n      \"documents otherwise), remove the conflict markers, and stage it:\",\n      \"\",\n      \"```bash\",\n      'git -C \"$wt\" add \"<path>\"',\n      \"```\",\n      \"\",\n      \"Then verify each re-inserted row appears **exactly once** in the\",\n      \"staged content — zero means the row was dropped, more than one means\",\n      \"the merge duplicated it:\",\n      \"\",\n      \"```bash\",\n      'count=$(git -C \"$wt\" show \":<path>\" | grep -Fc \"<row-unique-marker>\")',\n      '[ \"$count\" = \"1\" ] || { echo \"BLOCKED verification failed for <path>\"; exit 1; }',\n      \"```\",\n      \"\",\n      \"On any `BLOCKED` result, run `git merge --abort`, report the PR as\",\n      \"`BLOCKED <reason>`, and leave it for a human. Otherwise complete the\",\n      \"merge and push — plain push, never force:\",\n      \"\",\n      \"```bash\",\n      'git -C \"$wt\" commit --no-edit',\n      'git -C \"$wt\" push origin \"<branch>\"',\n      \"```\",\n      \"\",\n      \"Do **not** arm the PR afterwards. Resolving the conflict returns it\",\n      \"to a state the pipeline can act on; the next reviewer pass decides\",\n      \"whether it merges. If the PR carried `review:awaiting-human`, leave\",\n      \"that label alone (**D2**) and note the resolution in the report so\",\n      \"the human can act on a now-mergeable PR.\",\n      \"\",\n      \"A PR in this class may need re-resolving after each sibling merges\",\n      \"into the same page. That is expected; it converges.\",\n      \"\",\n      \"## Anti-patterns\",\n      \"\",\n      \"- **Don't refresh or rebase an armed PR that is merely `BLOCKED` on a\",\n      \"  queued CI run.** You will restart CI and push the merge further\",\n      \"  away. Diagnose the merge state before touching the branch.\",\n      \"- **Don't operator-arm an unreviewed PR.** Arming is the reviewer's\",\n      \"  decision, made under the project's PR-review policy. Hand it to\",\n      \"  `/review-pr` instead (**D1**).\",\n      \"- **Don't hand-clear `review:*` labels** (**D2**). Route to the owner\",\n      \"  that clears each one.\",\n      \"- **Don't force-push.** Ever, on any branch.\",\n      \"- **Don't hand-merge a non-shared-index conflict.** The pipeline has\",\n      \"  a typed recipe for those; duplicating it here invites divergence.\",\n      \"- **Don't edit a path the PR's own diff does not already touch**, and\",\n      \"  never a lockfile or generated file.\",\n      \"- **Don't act on the first sighting of a signal.** Every act-on\",\n      \"  branch is stall-window gated for a reason.\",\n      \"- **Don't scan the issue queue and don't dispatch `issue-worker` on\",\n      \"  an issue.** That is the orchestrator's job, not this skill's.\",\n      \"\",\n      \"## Composability\",\n      \"\",\n      \"This skill composes with the pipeline; it never reimplements it.\",\n      \"\",\n      \"- **`pr-reviewer` owns review and arming.** Every path in this skill\",\n      \"  that needs a PR reviewed, re-confirmed, or armed invokes\",\n      \"  `/review-pr <n>` and lets the reviewer apply the policy. This skill\",\n      \"  contains no acceptance-criteria checking, no policy evaluation, and\",\n      \"  no `gh pr merge --auto` call.\",\n      \"- **`orchestrator` owns the issue queue.** This skill never runs the\",\n      \"  queue scan, never claims or labels an issue, never creates a\",\n      \"  branch for an issue, and never dispatches `issue-worker` on one. It\",\n      \"  reads **open PRs** only.\",\n      \"- **`issue-worker` owns fix-list application.** This skill never\",\n      \"  posts a fix-list, never applies one, and never writes a\",\n      \"  worker-report comment.\",\n      \"- **The maintenance sweep owns stale-lease reconcile.** This skill\",\n      \"  observes lease states; it does not reconcile them.\",\n      \"\",\n      \"The only writes this skill makes are: `gh pr update-branch` (**D3**),\",\n      \"a non-force `git push` of a conflict resolution (**R1**), and its own\",\n      \"report. Everything else is a read or a delegation.\",\n      \"\",\n      \"Origin labels are **not** an eligibility gate here. Sweep and\",\n      `auto-merge eligibility have never been origin-gated, and ${DELEGATION_ELIGIBLE_ORIGIN_LIST}`,\n      \"both mark a PR bot-authored for fix-delegation purposes. Classify\",\n      \"every open PR regardless of origin label — including PRs carrying\",\n      \"none. Origin labels matter only where this skill quotes the\",\n      \"reviewer's delegation guard, which admits\",\n      `${DELEGATION_ELIGIBLE_ORIGIN_PHRASE}.`,\n      \"\",\n      \"## Output\",\n      \"\",\n      \"One line per PR, then a summary, then the cadence recommendation:\",\n      \"\",\n      \"```\",\n      \"Cycle <ISO-8601 UTC>  (stall window: <n>m)\",\n      \"  PR #<n>  <CLASS>  <action taken, or 'no action'>\",\n      \"  PR #<n>  <CLASS>  <action taken, or 'no action'>\",\n      \"Summary: <total> open, <acted> acted on, <left> left to the pipeline\",\n      \"NEXT_CHECK_IN <minutes>\",\n      \"```\",\n      \"\",\n      \"Under `--dry-run`, the action column reads `would: <handler>` and the\",\n      \"summary reports `0 acted on`.\",\n      \"\",\n      \"## Cadence\",\n      \"\",\n      \"The workload is **bursty** — quiet stretches punctuated by batches of\",\n      \"related PRs — and mostly idle. A fixed 15-minute cadence was measured\",\n      \"as too frequent for it: it multiplies no-op cycles without landing\",\n      \"stuck PRs meaningfully sooner.\",\n      \"\",\n      \"**Preferred — dynamic self-pacing.** End each cycle by choosing the\",\n      \"next delay from what the sweep actually saw:\",\n      \"\",\n      \"| Observation | `NEXT_CHECK_IN` |\",\n      \"|-------------|-----------------|\",\n      \"| Any conflict class, label anomaly, or a batch actively landing | 15 minutes |\",\n      \"| All open PRs clean, armed, or converging | 25–30 minutes |\",\n      \"| Queue empty | 45–60 minutes |\",\n      \"\",\n      \"**Simple — fixed interval.** Pass `--interval 30`. Thirty minutes\",\n      \"halves the idle-cycle overhead versus fifteen and still catches stuck\",\n      \"PRs well inside a tolerable window, because the default branch keeps\",\n      \"advancing around a stuck PR regardless.\",\n      \"\",\n      \"Drop to 15 minutes only when you specifically want stuck PRs cleared\",\n      \"as fast as possible during a heavy burst and accept the idle\",\n      \"overhead.\",\n    ].join(\"\\n\"),\n    referenceFiles: [\n      {\n        path: \"evals/evals.json\",\n        content: JSON.stringify(\n          {\n            skill_name: \"babysit-prs\",\n            evals: [\n              {\n                id: 1,\n                prompt:\n                  \"/babysit-prs — there are three open PRs. #101 is armed for squash auto-merge and reports mergeStateStatus BEHIND, last updated four minutes ago. #102 carries review:fixing and review:needs-worker. #103 is MERGEABLE, armed, and CI is green.\",\n                expected_output:\n                  \"The skill takes no action on any of the three and says so explicitly. #101 classifies as PROGRESSING, not BEHIND-STALLED: it was updated four minutes ago, well inside the stall window (2 x the interval, floored at 30 minutes), so it gets its convergence window and is left alone — no `gh pr update-branch`, no worktree, no push. #102 classifies as IN-FLIGHT-DELEGATION and is left untouched; the skill does not clear `review:fixing` or `review:needs-worker`, does not post a fix-list, and does not invoke the reviewer. #103 classifies as PROGRESSING and is left for the pipeline to merge. The report lists one line per PR with `no action`, a summary reading 3 open / 0 acted on / 3 left to the pipeline, and a NEXT_CHECK_IN recommendation of 25-30 minutes because everything is clean or converging. The skill never scans the issue queue and never calls `gh pr merge --auto`.\",\n                files: [],\n                product_context_refs: [],\n              },\n              {\n                id: 2,\n                prompt:\n                  \"/babysit-prs — PR #204 is CONFLICTING. The only conflicting file is docs/src/content/docs/profiles/companies/index.md and the conflict is a single pair of table rows that two PRs inserted at the same position. The PR has carried review:awaiting-human for two hours with no review:fixing or review:needs-worker, and its latest worker-report comment records the synthetic:rebase-shared-index item as failed.\",\n                expected_output:\n                  \"The skill classifies #204 as CONFLICT-SHARED-INDEX and runs the R1 handler, having confirmed all four eligibility checks: the path matches the shared-index glob set, every conflict hunk touches only `| ` data rows (not the frontmatter, H1, table header, or separator row), no conflicting path is a lockfile or projen-generated file, and the PR lacks `review:human-required` while carrying `review:awaiting-human` alongside a failed `synthetic:rebase-shared-index` worker report. It creates or reuses a detached worktree outside the user's checkout, checks out the PR branch there, merges the default branch in (merge, never rebase), resolves the conflict by union — keeping both rows, re-inserted in the file's declared sort order — stages the file, and verifies with `git show :<path> | grep -Fc` that each re-inserted row appears exactly once. On success it completes the merge commit and pushes with a plain non-force `git push`. It does NOT arm the PR, does NOT remove the `review:awaiting-human` label, and does NOT force-push. It removes the worktree before finishing and reports the resolution so the human sees a now-mergeable PR. Had any verification returned a count other than 1, the expected behaviour is `git merge --abort` plus a `BLOCKED` report line rather than a push.\",\n                files: [],\n                product_context_refs: [],\n              },\n              {\n                id: 3,\n                prompt:\n                  \"/babysit-prs --interval 30 — PR #305 has been armed for squash auto-merge and stuck at mergeStateStatus BEHIND for the last three hours with no other activity. PR #306 carries both review:awaiting-human and review:needs-worker.\",\n                expected_output:\n                  \"#305 classifies as BEHIND-STALLED: it is armed, BEHIND, and its updatedAt is older than the 60-minute stall window (2 x the 30-minute interval). The skill chases it by refreshing the branch, preferring `gh pr update-branch 305`; if that is unavailable it falls back to a worktree checkout plus `git merge --no-edit origin/<default-branch>` and a plain `git push`. It never rebases and never force-pushes, and if the local merge conflicts it aborts the merge and re-classifies rather than resolving. #306 classifies as LABEL-ANOMALY — `review:awaiting-human` together with a fix-delegation label is a mutually-exclusive invariant violation — and the skill re-invokes `/review-pr 306` so the reviewer's Phase 2.8 label reconciliation resolves it canonically and logs the correction. The skill explicitly does NOT run `gh pr edit --remove-label` on either `review:awaiting-human` or `review:needs-worker`, because the reviewer confirm pass, the issue-worker, and the maintenance sweep each own clearing their own label. The cadence line reports the pinned 30-minute interval.\",\n                files: [],\n                product_context_refs: [],\n              },\n            ],\n          },\n          null,\n          2,\n        ),\n      },\n    ],\n  };\n}\n","import { PrReviewPolicyConfig } from \"../agent-config-options\";\n\n/**\n * Default path globs that exempt a PR from the `human-required.size`\n * rule. The policy walks every changed path in the PR and skips\n * rule #6 (size threshold) when **every** path matches at least one\n * glob in this list. Doc-only PRs routinely exceed the 500-insertion\n * threshold (large migrations, bulk additions, refresh passes) but\n * carry no production risk that warrants forcing a human reviewer.\n *\n * The default exempts the entire `docs/**` tree — every consumer of\n * configulator places its Starlight docs site there. Consumers can\n * extend this list (e.g. add `docs/research/**` if doc-style research\n * notes live outside the Starlight tree) by passing\n * `prReviewPolicy.autoMerge.pathsExemptFromSize`.\n *\n * @see PrReviewPolicyConfig\n * @see PrReviewAutoMergeConfig.pathsExemptFromSize\n */\nexport const DEFAULT_PATHS_EXEMPT_FROM_SIZE: ReadonlyArray<string> = [\n  \"docs/**\",\n];\n\n/**\n * Default required-workflow list for the CI-verification Actions-runs\n * fallback. Empty by design: when the reviewer has to fall back to\n * the Actions runs API (because the primary check-runs read returned\n * a fine-grained-PAT 403), an empty list means **every** workflow run\n * observed for the PR head SHA is treated as required. That is the\n * conservative zero-config default — an unknown failing workflow\n * blocks auto-merge rather than slipping through.\n *\n * Consumers that want to gate on a known subset (e.g. ignore an\n * optional or advisory workflow) set\n * `prReviewPolicy.ciVerification.requiredWorkflows`.\n *\n * @see PrReviewCiVerificationConfig\n * @see PrReviewCiVerificationConfig.requiredWorkflows\n */\nexport const DEFAULT_REQUIRED_WORKFLOWS: ReadonlyArray<string> = [];\n\n/**\n * Fully-resolved PR review policy. Every field is defaulted so\n * downstream renderers can reason about a single canonical shape.\n *\n * Two sub-rules are configurable today: the doc-only carve-out\n * against the size threshold (`autoMerge.pathsExemptFromSize`) and\n * the CI-verification fallback's required-workflow list\n * (`ciVerification.requiredWorkflows`). Additional knobs for other\n * rules in the policy may be added in future versions of\n * `PrReviewPolicyConfig`.\n */\nexport interface ResolvedPrReviewPolicy {\n  readonly autoMerge: ResolvedPrReviewAutoMerge;\n  readonly ciVerification: ResolvedPrReviewCiVerification;\n}\n\n/**\n * Fully-resolved `auto-merge` half of the policy.\n *\n * `pathsExemptFromSize` is always populated — the default\n * (`[\"docs/**\"]`) ships when the consumer omits the option.\n */\nexport interface ResolvedPrReviewAutoMerge {\n  readonly pathsExemptFromSize: ReadonlyArray<string>;\n}\n\n/**\n * Fully-resolved `ci-verification` half of the policy.\n *\n * `requiredWorkflows` is always populated — the default (`[]`, i.e.\n * \"treat every observed Actions run as required\") ships when the\n * consumer omits the option.\n */\nexport interface ResolvedPrReviewCiVerification {\n  readonly requiredWorkflows: ReadonlyArray<string>;\n}\n\n/**\n * Resolve a (possibly absent) `PrReviewPolicyConfig` into a canonical\n * `ResolvedPrReviewPolicy` with every field filled in. Unset fields\n * cascade from their documented defaults.\n *\n * Malformed configs (empty / whitespace-only path entries) throw a\n * descriptive `Error` — callers should not need to guard against it\n * at runtime.\n */\nexport function resolvePrReviewPolicy(\n  config?: PrReviewPolicyConfig,\n): ResolvedPrReviewPolicy {\n  const pathsExemptFromSize =\n    config?.autoMerge?.pathsExemptFromSize ?? DEFAULT_PATHS_EXEMPT_FROM_SIZE;\n  const requiredWorkflows =\n    config?.ciVerification?.requiredWorkflows ?? DEFAULT_REQUIRED_WORKFLOWS;\n\n  assertValidPathsExemptFromSize(pathsExemptFromSize);\n  assertValidRequiredWorkflows(requiredWorkflows);\n\n  return {\n    autoMerge: {\n      pathsExemptFromSize: [...pathsExemptFromSize],\n    },\n    ciVerification: {\n      requiredWorkflows: [...requiredWorkflows],\n    },\n  };\n}\n\n/**\n * Synth-time validation hook. Throws a descriptive `Error` when the\n * supplied `PrReviewPolicyConfig` is malformed. Called by\n * `AgentConfig.preSynthesize` before any rendering so a misconfigured\n * policy fails the build instead of silently shipping broken carve-out\n * globs. Returns the resolved policy unchanged so callers can write\n * `const policy = validatePrReviewPolicyConfig(config)` in one line.\n *\n * Malformed cases rejected here:\n *\n * - `pathsExemptFromSize` entries that are empty or whitespace-only —\n *   such an entry would either silently match nothing or match every\n *   path, both of which are almost certainly a typo.\n * - `requiredWorkflows` entries that are empty or whitespace-only — a\n *   blank workflow name can never match an Actions-run `name`, so the\n *   intended gate would silently never fire.\n */\nexport function validatePrReviewPolicyConfig(\n  config?: PrReviewPolicyConfig,\n): ResolvedPrReviewPolicy {\n  return resolvePrReviewPolicy(config);\n}\n\nfunction assertValidPathsExemptFromSize(paths: ReadonlyArray<string>): void {\n  for (const path of paths) {\n    if (typeof path !== \"string\" || path.trim().length === 0) {\n      throw new Error(\n        \"prReviewPolicy.autoMerge.pathsExemptFromSize entries must be non-empty strings\",\n      );\n    }\n  }\n}\n\nfunction assertValidRequiredWorkflows(workflows: ReadonlyArray<string>): void {\n  for (const workflow of workflows) {\n    if (typeof workflow !== \"string\" || workflow.trim().length === 0) {\n      throw new Error(\n        \"prReviewPolicy.ciVerification.requiredWorkflows entries must be non-empty strings\",\n      );\n    }\n  }\n}\n","import { AgentRuleBundle, PrReviewPolicyConfig } from \"../agent-config-options\";\nimport {\n  DELEGATION_ELIGIBLE_ORIGIN_LIST,\n  DELEGATION_ELIGIBLE_ORIGIN_PHRASE,\n  ORIGIN_AGENT_LABEL,\n  ORIGIN_ISSUE_WORKER_LABEL,\n} from \"./origin-label\";\nimport { buildBabysitPrsSkill } from \"./pr-babysitting\";\nimport {\n  ResolvedPrReviewPolicy,\n  resolvePrReviewPolicy,\n} from \"./pr-review-policy\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport { DEFAULT_SHARED_INDEX_PATHS } from \"./shared-editing\";\nimport {\n  AGENT_MODEL,\n  AGENT_RULE_SCOPE,\n  AgentSkill,\n  AgentSubAgent,\n} from \"../types\";\n\n/*******************************************************************************\n *\n * PR Reviewer sub-agent — verifies a PR against its linked issue's\n * acceptance criteria and orchestrates approve / squash-merge / cleanup.\n *\n ******************************************************************************/\n\nconst prReviewerSubAgent: AgentSubAgent = {\n  name: \"pr-reviewer\",\n  description:\n    \"Reviews a pull request against its linked issue's acceptance criteria, then enables squash auto-merge or comments with findings\",\n  model: AGENT_MODEL.POWERFUL,\n  maxTurns: 40,\n  platforms: { cursor: { exclude: true } },\n  prompt: [\n    \"# PR Reviewer Agent\",\n    \"\",\n    \"You review a single pull request in **{{repository.owner}}/{{repository.name}}**\",\n    \"against its linked issue's acceptance criteria, verify code quality and\",\n    \"convention compliance, and then either enable squash auto-merge or leave\",\n    \"a review comment with findings. You handle exactly **one PR per session**\",\n    \"unless invoked from the multi-PR loop skill (`/review-prs`), in which case\",\n    \"you process each eligible PR in turn.\",\n    \"\",\n    \"---\",\n    \"\",\n    ...PROJECT_CONTEXT_READER_SECTION,\n    \"## Invocation Flags\",\n    \"\",\n    \"Your invocation prompt may include flags that modify how you select and\",\n    \"process PRs. Parse the prompt for these flags before starting Phase 1:\",\n    \"\",\n    \"- **`--allow-human-author`** — opt-in flag that allows the reviewer to\",\n    \"  process PRs authored by humans in addition to bot-authored PRs\",\n    `  (those carrying ${DELEGATION_ELIGIBLE_ORIGIN_LIST}). When absent, the`,\n    \"  reviewer only processes bot-authored PRs; when present, human-authored\",\n    \"  PRs are also eligible for this invocation only. The flag does **not**\",\n    \"  persist across invocations.\",\n    \"\",\n    \"Phase 4's invocation guard enforces the bot-only default and the\",\n    \"`--allow-human-author` opt-out. PRs carrying **no** origin label are\",\n    \"still classified, commented on, reacted to, and (in\",\n    \"`auto-merge` mode) auto-merged when the AC/CI checks pass — only the\",\n    \"delegation hand-off to `issue-worker` is gated.\",\n    \"\",\n    \"---\",\n    \"\",\n    \"## CI Verification (primary read + Actions-runs fallback)\",\n    \"\",\n    \"Every CI-status decision in this agent — the Phase 1.5 eligibility\",\n    \"filter, the Phase 3 checklist, the Phase 4 merge gate, the Phase 4\",\n    \"step (h) re-enable condition, and the Phase 4.5 sticky `CI status`\",\n    \"field — resolves CI through the procedure below. It yields one of\",\n    \"three verdicts: **green** (every required check succeeded),\",\n    \"**pending** (no failures, but at least one required check is still\",\n    \"running or queued), or **red** (at least one required check\",\n    \"failed). Never enable auto-merge unless the verdict is **green**.\",\n    \"\",\n    \"### Step 1: Primary read — check-runs / statusCheckRollup\",\n    \"\",\n    \"Read CI from the GitHub check-runs rollup, the canonical source\",\n    \"GitHub itself uses to gate branch protection:\",\n    \"\",\n    \"```bash\",\n    \"gh pr checks <pr-number>\",\n    \"# equivalently, the rollup field:\",\n    \"gh pr view <pr-number> --json statusCheckRollup\",\n    \"```\",\n    \"\",\n    \"This read aggregates **every** check context — GitHub Actions,\",\n    \"third-party CI, GitHub Apps, and commit statuses. When it returns\",\n    \"one or more readable contexts, it is authoritative: map each\",\n    \"required context's conclusion with the table in Step 4 and do\",\n    \"**not** fall back. It is strictly more complete than the\",\n    \"Actions-runs view in Step 3.\",\n    \"\",\n    \"### Step 2: Detect the fine-grained-PAT 403\",\n    \"\",\n    \"The primary read fails closed for one specific credential: a\",\n    \"**fine-grained personal access token**. GitHub exposes no `Checks`\",\n    \"permission for fine-grained PATs (it is GitHub-App-only), so the\",\n    \"check-runs / `statusCheckRollup` request returns:\",\n    \"\",\n    \"```\",\n    \"HTTP 403: Resource not accessible by personal access token\",\n    \"```\",\n    \"\",\n    \"Trigger the Step 3 fallback **only** when the primary read either:\",\n    \"\",\n    \"- returns an explicit **403** (`Resource not accessible by personal\",\n    \"  access token`) on the check-runs / `statusCheckRollup` request,\",\n    \"  **or**\",\n    \"- returns **no readable check contexts at all** (an empty rollup)\",\n    \"  for a head SHA that does have CI configured.\",\n    \"\",\n    \"A primary read that returns one or more readable contexts is\",\n    \"authoritative — **never** fall back in that case (GitHub-App and\",\n    \"classic-PAT consumers keep the complete check-runs view). **Never**\",\n    \"treat a 403 or an unreadable check as green: the 403 is a\",\n    \"visibility failure, not a passing signal.\",\n    \"\",\n    \"### Step 3: Fallback read — Actions runs API\",\n    \"\",\n    \"A fine-grained PAT with `Actions: Read-only` (which **is**\",\n    \"grantable) can read workflow-run conclusions even when check-runs\",\n    \"is denied. Read every workflow run for the PR's head SHA:\",\n    \"\",\n    \"```bash\",\n    \"head_sha=$(gh pr view <pr-number> --json headRefOid --jq '.headRefOid')\",\n    'gh api \"repos/{{repository.owner}}/{{repository.name}}/actions/runs?head_sha=${head_sha}&per_page=100\"',\n    \"```\",\n    \"\",\n    \"Each run carries a `name`, `status`, and `conclusion`. **Collapse\",\n    \"re-runs:** when a workflow `name` appears more than once for the\",\n    \"same head SHA, keep only the most recent run (highest\",\n    \"`run_number` / latest `created_at`) for that name.\",\n    \"\",\n    \"This fallback only sees GitHub Actions runs. It is sound for repos\",\n    \"whose CI is entirely GitHub Actions; if a consumer adds a\",\n    \"non-Actions required check, a fine-grained-PAT credential cannot\",\n    \"see it and the consumer must move the reviewer to a GitHub App /\",\n    \"classic PAT to regain the complete check-runs view.\",\n    \"\",\n    \"### Step 4: Map conclusions to a verdict\",\n    \"\",\n    \"Apply this mapping to the set of required checks (Step 5 defines\",\n    '\"required\"):',\n    \"\",\n    \"| status / conclusion | Treatment |\",\n    \"|---------------------|-----------|\",\n    \"| `completed` / `success` | pass |\",\n    \"| `completed` / `skipped` | non-blocking (ignore) |\",\n    \"| `completed` / `neutral` | non-blocking (ignore) |\",\n    \"| `completed` / `failure` | **block → red** |\",\n    \"| `completed` / `cancelled` | **block → red** |\",\n    \"| `completed` / `timed_out` | **block → red** |\",\n    \"| `completed` / `action_required` | **block → red** |\",\n    \"| `in_progress` / `queued` / `requested` / `waiting` / null conclusion | not-yet-green (pending) |\",\n    \"\",\n    \"- If any required check is **red**, the verdict is **red**.\",\n    \"- Else if any required check is **pending**, the verdict is\",\n    \"  **pending**.\",\n    \"- Else (every required check passed or was non-blocking) the\",\n    \"  verdict is **green**.\",\n    \"\",\n    '### Step 5: Which workflows are \"required\"',\n    \"\",\n    'In the **Step 1 primary path**, \"required\" means the contexts',\n    \"GitHub marks required under branch protection — the rollup already\",\n    \"reflects this.\",\n    \"\",\n    \"In the **Step 3 fallback path**, the Actions runs API does not say\",\n    \"which workflows are required, so consult the policy's\",\n    \"`ci-verification.required-workflows` list (rendered in the\",\n    \"`PR Review Policy` block in CLAUDE.md):\",\n    \"\",\n    \"- **Non-empty list** — gate only on the workflow `name`s in the\",\n    \"  list. A listed workflow with **no** run for the head SHA is\",\n    \"  treated as not-yet-green (pending), never green.\",\n    \"- **Empty list (default)** — treat **every** workflow run observed\",\n    \"  for the head SHA as required. This is the conservative\",\n    \"  zero-config default: an unknown failing workflow blocks rather\",\n    \"  than slips through.\",\n    \"\",\n    \"---\",\n    \"\",\n    \"## Phase 1: Identify the PR\",\n    \"\",\n    \"If a PR number was provided in your instructions, use that. Otherwise stop\",\n    \"and report that you need a PR number — do not pick one yourself.\",\n    \"\",\n    \"## Phase 1.5: Pre-flight Eligibility Filter\",\n    \"\",\n    \"Before spending turns on a full review, run a cheap eligibility check:\",\n    \"\",\n    \"```bash\",\n    \"gh pr view <pr-number> --json number,title,body,headRefName,mergeable,mergeStateStatus,statusCheckRollup\",\n    \"```\",\n    \"\",\n    \"The PR is **eligible** only when **all** of the following hold:\",\n    \"\",\n    '1. `mergeable == \"MERGEABLE\"` (no merge conflicts). A',\n    '   `mergeable == \"CONFLICTING\"` PR is **not** an automatic',\n    \"   disqualification — see the **already-`CONFLICTING` handling**\",\n    \"   below, which may auto-correct it via delegation before falling\",\n    \"   back to a hard reject.\",\n    \"2. No **failing** required checks in `statusCheckRollup` — CI must be\",\n    \"   green or still pending. Any `FAILURE`, `TIMED_OUT`, `CANCELLED`, or\",\n    \"   `ERROR` conclusion on a required check disqualifies the PR. If the\",\n    \"   `statusCheckRollup` read returns a 403 `Resource not accessible by\",\n    \"   personal access token` (fine-grained PAT) or an empty rollup,\",\n    \"   resolve CI via the **CI Verification** section's Actions-runs\",\n    \"   fallback before deciding eligibility — do **not** treat the 403 as\",\n    \"   either a pass or an automatic disqualification.\",\n    \"3. The PR body contains at least one linked issue via a closing\",\n    \"   keyword (`Closes #N`, `Fixes #N`, `Resolves #N`, case-insensitive).\",\n    \"   Resolve this mechanically — do **not** eyeball the body:\",\n    \"\",\n    \"```bash\",\n    \".claude/procedures/check-closing-keywords.sh <pr-number>\",\n    \"```\",\n    \"\",\n    \"   The procedure is the single source of truth for closing-keyword\",\n    \"   parsing in this pipeline. It emits one `CLOSES #<n> line=<L>` line\",\n    \"   per reference GitHub will honour, one\",\n    \"   `STRANDED #<n> line=<L> keyword=<kw> first=#<n>` line per reference\",\n    \"   GitHub will silently ignore, then a summary line. It skips fenced\",\n    \"   code blocks, blockquotes, and inline code spans, so a body that\",\n    \"   merely discusses closing keywords does not confuse it.\",\n    \"\",\n    \"   - Exit `5` / `NO_CLOSING_KEYWORD` — check (3) **fails**; the PR has\",\n    \"     no linked issue.\",\n    \"   - Exit `0` / `CLOSING_KEYWORDS_OK` — check (3) passes. Record the\",\n    \"     `CLOSES` set as the **linked-issue set** for the rest of the pass.\",\n    \"   - Exit `1` / `CLOSING_KEYWORDS_MALFORMED` — check (3) **passes**\",\n    \"     (there is a linked issue), but the body would strand every\",\n    \"     `STRANDED` issue. This is **not** an eligibility rejection — the\",\n    \"     code is not at fault. Record both the `CLOSES` and `STRANDED`\",\n    \"     sets as the linked-issue set and carry the malformed finding into\",\n    \"     Phase 4 and Phase 5.\",\n    \"\",\n    \"If the **CI** check (2) or the **linked-issue** check (3) fails, post\",\n    \"a short comment explaining the reason and stop. Do not proceed to\",\n    \"full review.\",\n    \"\",\n    \"```bash\",\n    \"gh pr comment <pr-number> --body '<reason>'\",\n    \"```\",\n    \"\",\n    \"Typical reasons:\",\n    \"\",\n    \"- `Not reviewable: required CI check <name> is failing.`\",\n    \"- `Not reviewable: PR body is missing a linked issue (Closes #N / Fixes #N / Resolves #N).`\",\n    \"\",\n    \"### Already-`CONFLICTING` handling (auto-correct, then reject)\",\n    \"\",\n    'When the merge check (1) reports `mergeable == \"CONFLICTING\"`, do',\n    \"**not** unconditionally reject. A bot-authored PR that is already\",\n    \"conflicting when the orchestrator finds it is exactly the case the\",\n    \"conflict-resolution delegation flow exists to auto-correct — there\",\n    \"is no reason to make a human rebase it by hand when `issue-worker`\",\n    \"can. Before rejecting, evaluate checks (2) and (3) above first: a\",\n    \"`CONFLICTING` PR that **also** has failing CI or no linked issue is\",\n    \"rejected for that reason via the comment-and-stop path above, since\",\n    \"the delegation cannot succeed without a linked issue and green-able\",\n    \"CI anyway.\",\n    \"\",\n    \"Otherwise, hand off to the **Shared Procedure: Conflict-Resolution\",\n    \"Delegation** section. It evaluates the guards (auto-merge mode, the\",\n    \"delegation invocation guard, a free `review:fixing` lease, no\",\n    \"generated / projen / lockfile conflicts), classifies the conflicting\",\n    \"files, and either delegates a conflict resolution to `issue-worker`\",\n    \"or falls through to its own fallback. Invoke it with this entry\",\n    \"point's parameters:\",\n    \"\",\n    \"- **Entry point:** `already-conflicting`. There is no failed\",\n    \"  `gh pr update-branch` to read conflicting paths from — identify\",\n    \"  the conflicting files from the PR's merge state as documented in\",\n    \"  the shared procedure's entry-point step (a local merge attempt\",\n    \"  whose `<<<<<<<` / `=======` / `>>>>>>>` markers name the\",\n    \"  conflicting files). The guards and classification are identical to\",\n    \"  the Phase 4 entry point.\",\n    \"- **On the procedure returning `delegated`:** a conflict resolution\",\n    \"  has been durably queued for `issue-worker` (the PR now carries\",\n    \"  `review:needs-worker` and the `review:fixing` lease); stop this\",\n    \"  pass. A top-level `issue-worker` session pulls the marker and\",\n    \"  pushes the merged branch, then a follow-up reviewer pass confirms\",\n    \"  the result and releases the lease — no human re-invocation is\",\n    \"  required for the loop to complete.\",\n    \"- **On the procedure returning `skipped` (a guard denied delegation\",\n    \"  or the guards failed):** fall back to the original hard reject —\",\n    \"  post the merge-conflict rejection comment and stop. Use this\",\n    \"  comment **only** in the skipped case, never before the shared\",\n    \"  procedure has had its chance to auto-correct:\",\n    \"\",\n    \"```bash\",\n    \"gh pr comment <pr-number> --body 'Not reviewable: merge conflicts — please rebase onto the default branch.'\",\n    \"```\",\n    \"\",\n    \"## Phase 2: Gather Context\",\n    \"\",\n    \"```bash\",\n    \"gh pr view <pr-number> --json number,title,body,headRefName,baseRefName,isDraft,state,labels,reviews,files,additions,deletions\",\n    \"gh pr diff <pr-number>\",\n    \"gh pr checks <pr-number>\",\n    \"```\",\n    \"\",\n    \"Use the **linked-issue set** already computed in Phase 1.5 — the union\",\n    \"of the `CLOSES` and `STRANDED` issue numbers the\",\n    \"`check-closing-keywords.sh` run reported. Do not re-derive it by\",\n    \"reading the body yourself.\",\n    \"\",\n    \"Most PRs link exactly one issue, and every phase below reads naturally\",\n    \"in the singular. When the set has more than one member, treat **every**\",\n    \"member as a linked issue: fetch each one, union their acceptance\",\n    \"criteria in Phase 3, and close each one in Phase 5. The **primary**\",\n    \"linked issue — the one cited in the sticky summary and the structured\",\n    \"report — is the first `CLOSES` entry.\",\n    \"\",\n    \"Then fetch each linked issue, including its `issueType` so Phase 2.75\",\n    \"can evaluate the issue-type portion of the review policy:\",\n    \"\",\n    \"```bash\",\n    \"gh issue view <issue-number> --json number,title,body,labels,state,issueType\",\n    \"```\",\n    \"\",\n    \"When several issues are linked, Phase 2.75's issue-type rule matches if\",\n    \"**any** linked issue's type is in `human-required.issue-types` — the\",\n    \"conservative reading, consistent with the policy's mixed-signal rule.\",\n    \"\",\n    \"## Phase 2.5: Gather Comments\",\n    \"\",\n    \"Before deciding review mode, collect every human comment on the PR so\",\n    \"that Phase 3.5 can classify each one and Phase 4.5 can render the\",\n    \"sticky **Reviewer notes** summary. GitHub exposes PR comments across\",\n    \"three distinct endpoints; the reviewer merges all three into a single\",\n    \"queue.\",\n    \"\",\n    \"### Step 1: Fetch all three comment sources\",\n    \"\",\n    \"```bash\",\n    \"# PR-level issue comments (top-level discussion thread)\",\n    \"gh pr view <pr-number> --json comments\",\n    \"\",\n    \"# Inline code-review comments (line-anchored in the diff)\",\n    \"gh api repos/{{repository.owner}}/{{repository.name}}/pulls/<pr-number>/comments\",\n    \"\",\n    \"# Formal review bodies and their APPROVED / CHANGES_REQUESTED / COMMENTED state\",\n    \"gh api repos/{{repository.owner}}/{{repository.name}}/pulls/<pr-number>/reviews\",\n    \"```\",\n    \"\",\n    \"For each item, capture: the comment id, author login, body, creation\",\n    \"time, the URL, and any reactions already present (including which\",\n    \"reactions the reviewer itself has previously applied). For inline\",\n    \"review comments, also capture the thread / conversation resolution\",\n    \"state so Step 2 can drop resolved threads.\",\n    \"\",\n    \"### Step 2: Apply filtering rules\",\n    \"\",\n    \"Drop a comment from classification when **any** of the following hold:\",\n    \"\",\n    \"1. **Reviewer's own comments.** The author login matches the invoking\",\n    \"   agent identity (for example, the bot account used to post prior\",\n    \"   reviewer replies, sticky summaries, or fix-list comments). The\",\n    \"   reviewer never classifies or reacts to its own output.\",\n    \"2. **Bot authors.** The author login matches `*[bot]` — CI bots,\",\n    \"   Dependabot, CodeRabbit, GitHub Actions, and similar automation.\",\n    \"3. **Terminal reviewer reactions already present.** The comment\",\n    \"   already carries a reaction **authored by the reviewer** in the set\",\n    \"   `+1` (accepted), `rocket` (landed), or `-1` (declined as\",\n    \"   out-of-scope). These signal the item has reached a terminal state\",\n    \"   on a previous pass and requires no further action.\",\n    \"4. **Resolved threads.** Inline comments belonging to a conversation\",\n    \"   that GitHub marks as resolved.\",\n    \"\",\n    \"A comment whose only reviewer-authored reaction is `eyes` is **not**\",\n    'terminal. `eyes` means \"seen on a previous pass but not yet resolved\"',\n    \"— keep it in the queue so Phase 3.5 can re-evaluate and possibly\",\n    \"promote it to a terminal state once the corresponding action\",\n    \"completes.\",\n    \"\",\n    \"A comment whose only reviewer-authored reaction is `thinking_face` is\",\n    \"also **not** terminal — it indicates an open dispute the reviewer\",\n    \"raised on a prior pass that has not yet been resolved by the human.\",\n    \"Phase 4 uses the presence of unresolved `thinking_face` reactions as\",\n    \"the pushback gate.\",\n    \"\",\n    \"### Step 3: Record the gathered set\",\n    \"\",\n    \"Persist the filtered comment list in memory for Phase 3.5 and Phase\",\n    \"4.5. For each surviving comment record at minimum:\",\n    \"\",\n    \"```\",\n    \"- id: <comment or review id>\",\n    \"  source: <pr-comment | inline-comment | review-body>\",\n    \"  author: <login>\",\n    \"  url: <html_url>\",\n    \"  body: <text>\",\n    \"  reactions: <list of reactions with authors>\",\n    \"```\",\n    \"\",\n    \"If there are no unhandled comments after filtering, record that fact\",\n    \"and proceed — Phase 3.5 will short-circuit, and the Phase 4.5 sticky\",\n    \"summary will simply list no outstanding items.\",\n    \"\",\n    \"## Phase 2.75: Determine Review Mode\",\n    \"\",\n    \"Before comparing the diff to the acceptance criteria, evaluate the PR\",\n    \"against the **PR Review Policy** embedded in this repository's\",\n    \"`CLAUDE.md` (rendered from the `pr-review-policy` rule). The decision\",\n    \"here governs whether Phase 4 enables auto-merge or hands off to a\",\n    \"human reviewer.\",\n    \"\",\n    \"### Step 1: Load the policy\",\n    \"\",\n    \"Read `CLAUDE.md` from the repo root and extract the fenced YAML block\",\n    \"under the `## PR Review Policy` heading. Parse the block into an\",\n    \"in-memory object with the following top-level fields: `version`,\",\n    \"`default`, `human-required`, `auto-merge`.\",\n    \"\",\n    \"If the policy section is missing or unparseable, fall back to\",\n    \"`mode = human-required` with `reason = 'policy missing or unreadable'`\",\n    \"and skip to Step 3. Do **not** auto-merge when the policy is absent.\",\n    \"\",\n    \"### Step 2: Evaluate in precedence order\",\n    \"\",\n    \"Walk the following checks in order. The **first match wins** and fixes\",\n    \"the mode; record the triggering condition as the `reason` **and**\",\n    \"record the numeric **`matched_rule`** index (one of `2`, `3`, `4`,\",\n    \"`5`, or `6` for any human-required match — see the rule numbers\",\n    \"below) so later phases can branch on which precedence rule fired.\",\n    \"When rule 1 (force-auto label) or rule 7 (default) fixes the mode,\",\n    \"record `matched_rule: null` — only the human-required rules carry an\",\n    \"actionable index. Mixed-match PRs (signals from both sides) resolve\",\n    \"conservatively to `human-required` — force-auto only wins when it is\",\n    \"the single highest match and no later human-required signal changes\",\n    \"the outcome under step 2c.\",\n    \"\",\n    \"1. **Force-auto label** — if the PR carries any label listed under\",\n    \"   `auto-merge.labels-that-force-auto` (e.g. `review:auto-ok`), set\",\n    \"   `mode = auto-merge`.\",\n    \"2. **Force-human label (reserved)** — if the PR carries a\",\n    \"   `review:human-required` label, set `mode = human-required`.\",\n    \"3. **Labels that force human** — if the PR carries any label listed\",\n    \"   under `human-required.labels-that-force-human` (e.g.\",\n    \"   `review:human-required`), set `mode = human-required`. Evaluate\",\n    \"   the PR's **own** labels only — rules 1–3 never traverse the\",\n    \"   `Closes #N` link to read the linked issue's labels. `priority:*`\",\n    \"   and `status:*` are issue-triage labels for the orchestrator's\",\n    \"   scheduling queue, not merge-risk signals, and are never listed\",\n    \"   here.\",\n    \"4. **Path globs** — if any file in the PR diff matches any glob in\",\n    \"   `human-required.paths`, set `mode = human-required`. Record the\",\n    \"   first matching path + glob pair as the reason.\",\n    \"5. **Issue type** — if the linked issue's GitHub issue type\",\n    \"   (fetched in Phase 2) matches any entry in\",\n    \"   `human-required.issue-types` (case-insensitive), set\",\n    \"   `mode = human-required`.\",\n    \"6. **Size thresholds** — first read\",\n    \"   `auto-merge.paths-exempt-from-size` from the policy (defaults to\",\n    \"   the documented carve-out list). For every file in the PR diff,\",\n    \"   evaluate whether the file path matches at least one glob in the\",\n    \"   carve-out list. If **every** changed path matches the carve-out,\",\n    \"   **skip rule #6** entirely and continue to rule #7 — the PR is\",\n    \"   exempt from the size threshold regardless of its `files` or\",\n    \"   `insertions` count. Otherwise (any changed path falls outside\",\n    \"   the carve-out list), apply the size check: if the PR exceeds\",\n    \"   either threshold under `human-required.size` (`files` count or\",\n    \"   `insertions` count), set `mode = human-required` and record the\",\n    \"   triggered axis (files vs. insertions) as the reason.\",\n    \"7. **Default** — if no rule above matched, apply the `default` field\",\n    \"   from the policy (typically `auto-merge`).\",\n    \"\",\n    \"#### Mixed-match resolution\",\n    \"\",\n    \"Apart from rule (1), which is an explicit opt-in and wins outright,\",\n    \"**any** match from rules (2) through (6) forces `human-required` even\",\n    \"if a non-force-auto signal would otherwise have allowed auto-merge.\",\n    \"The conservative choice wins. Rule (1) is the sole escape hatch and\",\n    \"requires a maintainer to have applied the force-auto label.\",\n    \"\",\n    \"### Step 3: Record the decision\",\n    \"\",\n    \"Persist the evaluated mode, the reason, and the matched-rule index\",\n    \"for later phases so Phase 4 and any downstream summary writer can\",\n    \"cite them:\",\n    \"\",\n    \"```\",\n    \"Review mode: <auto-merge | human-required>\",\n    \"Reason: <short explanation — label name, path+glob, issue type, size threshold, default>\",\n    \"Matched rule: <2 | 3 | 4 | 5 | 6 | null>\",\n    \"```\",\n    \"\",\n    \"`Matched rule` is the numeric index of the precedence rule that\",\n    \"fixed the mode in Step 2. It is populated only for human-required\",\n    \"matches (rules 2–6) — force-auto (rule 1) and default (rule 7)\",\n    \"record `null`. Phase 4's `gh pr update-branch` gate consults this\",\n    \"field to decide whether the size-only carve-out (rule 6) allows the\",\n    \"bot to keep a human-required branch fresh against the default branch.\",\n    \"\",\n    \"Phases 3 (acceptance-criteria comparison) and CI verification run\",\n    \"unchanged regardless of mode. Only the terminal action in Phase 4\",\n    \"branches on the decided mode.\",\n    \"\",\n    \"## Phase 2.8: Label Reconciliation\",\n    \"\",\n    \"A PR can never carry **mutually-exclusive review-workflow labels**\",\n    \"after a reviewer pass — this is the PR equivalent of the\",\n    '\"exactly one `status:*`\" discipline issues already follow.',\n    \"Successive passes that layer labels with no reconciler can drive a\",\n    \"PR into an impossible state (a real PR once held\",\n    \"`review:awaiting-human` + `status:needs-attention` + `review:fixing`\",\n    \"+ `review:needs-worker` simultaneously). Humans cannot tell what\",\n    \"state such a PR is in, and downstream phases branch on contradictory\",\n    \"signals. This phase detects violations and resolves them to the\",\n    \"**single correct state** implied by the mode decided in Phase 2.75\",\n    \"and the current loop position, logging every correction in the\",\n    \"sticky `## Reviewer notes` comment.\",\n    \"\",\n    \"Run this phase **early** — after Phase 2.75 fixes the review mode and\",\n    \"after the **Confirm a Completed Delegation** detection step reads the\",\n    \"lease state, but **before** Phase 3.5 / Phase 4 branch on review\",\n    \"state to decide actions. It must operate on a clean label set so no\",\n    \"later phase inherits a contradiction. It runs on **every** pass.\",\n    \"\",\n    \"### The review-label invariants\",\n    \"\",\n    \"These are the workflow labels this phase governs (see the\",\n    \"`pr-review-feedback-protocol` label glossary for full meanings):\",\n    \"`review:awaiting-human`, `review:needs-worker`, `review:fixing`,\",\n    \"plus the additive `status:needs-attention`. (`review:human-required`\",\n    \"and `review:auto-ok` are **policy inputs** read in Phase 2.75, not\",\n    \"workflow-state labels — this phase never adds or removes them.)\",\n    \"\",\n    \"1. **`review:awaiting-human` is mutually exclusive with the\",\n    \"   fix-delegation labels.** A PR is **either** in the fix-delegation\",\n    \"   loop (`review:needs-worker` and/or `review:fixing`) **or** handed\",\n    \"   off to a human (`review:awaiting-human`) — **never both**. The\",\n    \"   combination `review:awaiting-human` + `review:needs-worker`,\",\n    \"   `review:awaiting-human` + `review:fixing`, or all three together\",\n    \"   is a **violation**.\",\n    \"2. **`review:fixing` WITHOUT `review:needs-worker` is NOT a\",\n    \"   violation** — it is the **confirm-pending** state (the worker\",\n    \"   finished and cleared its marker; a confirm pass owns the PR and\",\n    \"   will release the lease). Do **not** strip `review:fixing` here.\",\n    \"3. **`review:fixing` WITH `review:needs-worker` is NOT a violation**\",\n    \"   — it is a valid **in-flight delegation** (the work is durably\",\n    \"   queued and a top-level `issue-worker` pass will consume it). Do\",\n    \"   **not** treat this combination as a contradiction.\",\n    \"4. **`status:needs-attention` is additive but must not coexist with\",\n    \"   an in-flight delegation that is making progress.** When the PR\",\n    \"   carries an active in-flight delegation (`review:fixing` +\",\n    \"   `review:needs-worker`) with a fix-list newer than the flag and no\",\n    \"   failed-fix pushback, `status:needs-attention` contradicts the\",\n    \"   live progress signal and is a **violation**. (A\",\n    \"   `status:needs-attention` flag that coexists with a *stalled* or\",\n    \"   *failed* delegation, an unresolved `thinking_face` pushback, or a\",\n    \"   `human-required` hand-off is **legitimate** — leave it.)\",\n    \"\",\n    \"### Canonical resolution table\",\n    \"\",\n    \"For each detected violation, resolve to the single correct state\",\n    \"below. The winning label is chosen by the **mode the reviewer is\",\n    \"about to act in** (Phase 2.75) and the **current loop position**\",\n    \"(the lease/marker labels present), so the surviving set always\",\n    \"matches the action this pass will actually take:\",\n    \"\",\n    \"| Violation combo | Loop position / mode | Resolution (winner) | Why |\",\n    \"|-----------------|----------------------|---------------------|-----|\",\n    \"| `review:awaiting-human` + (`review:needs-worker` and/or `review:fixing`) | A fix-delegation is in-flight or confirm-pending (`review:needs-worker` and/or `review:fixing` present) **and** mode is `auto-merge` | **Remove `review:awaiting-human`** | The PR is in the fix-delegation loop; the loop must run to completion (worker → confirm) before any hand-off. `review:awaiting-human` was layered by a stale pass and contradicts the live delegation. |\",\n    \"| `review:awaiting-human` + (`review:needs-worker` and/or `review:fixing`) | This pass decided `human-required` (rules 2–5) **and** no delegation is actually in flight (no fresh fix-list / no worker activity) | **Remove `review:needs-worker` and `review:fixing`** | The reviewer is handing the PR to a human; the fix-delegation labels are stale leftovers. The hand-off wins, the delegation labels lose. Release the lease and clear the marker so the human owns a clean state. |\",\n    \"| `status:needs-attention` + active in-flight delegation making progress (`review:fixing` + `review:needs-worker`, fix-list newer than the flag, no failed-fix pushback) | mode `auto-merge`, delegation live | **Remove `status:needs-attention`** | The delegation is progressing autonomously; the triage flag is contradictory. Re-flag only if the delegation later stalls or fails. |\",\n    \"\",\n    \"Resolution is **conservative about human intent**: when the pass is\",\n    \"genuinely `human-required` the human-facing labels win and the\",\n    \"fix-delegation labels are cleared; when the pass is `auto-merge` and\",\n    \"a delegation is live, the delegation wins and the stray\",\n    \"`review:awaiting-human` is cleared. Never resolve a violation by\",\n    \"*adding* a label — only by removing the contradicting one(s) per the\",\n    \"table.\",\n    \"\",\n    \"### Detect and apply\",\n    \"\",\n    \"1. List the PR's current labels:\",\n    \"\",\n    \"   ```bash\",\n    \"   gh pr view <pr-number> --json labels --jq '.labels[].name'\",\n    \"   ```\",\n    \"\",\n    \"2. Evaluate the invariants above against the label set, the mode from\",\n    \"   Phase 2.75, and the lease/marker position. If no violation exists,\",\n    \"   record `Label reconciliation: consistent` and proceed — this is\",\n    \"   the common case and the phase is a cheap no-op.\",\n    \"\",\n    \"3. For each violation, remove the losing label(s) named in the\",\n    \"   resolution table:\",\n    \"\",\n    \"   ```bash\",\n    \"   gh pr edit <pr-number> --remove-label '<losing-label>'\",\n    \"   ```\",\n    \"\",\n    \"4. **Log every correction in the sticky `## Reviewer notes` comment**\",\n    \"   (Phase 4.5) on a `**Label reconciliation:**` line, naming the\",\n    \"   detected violation combo, the labels removed, and the surviving\",\n    \"   self-consistent set — for example:\",\n    \"   `Label reconciliation: removed review:awaiting-human (contradicted in-flight review:fixing+review:needs-worker delegation); set is now {review:fixing, review:needs-worker}`.\",\n    \"   The correction is part of the audit trail; it must never be a\",\n    \"   silent label mutation.\",\n    \"\",\n    \"After this phase the PR holds a **self-consistent** review-label set:\",\n    \"at most one of {`review:awaiting-human`} versus the fix-delegation\",\n    \"pair, and no `status:needs-attention` shadowing a live delegation.\",\n    \"Phase 3.5 and Phase 4 then branch on a clean state.\",\n    \"\",\n    \"## Phase 3: Compare Diff to Acceptance Criteria\",\n    \"\",\n    \"Read the issue body for an **Acceptance Criteria** (or equivalent) section.\",\n    \"Build a checklist from it. For each item:\",\n    \"\",\n    \"1. Locate the changes in the diff that satisfy it.\",\n    \"2. Mark it as `met`, `partial`, or `missing`.\",\n    \"3. Record the specific files / functions / tests that provide evidence.\",\n    \"\",\n    \"Also evaluate:\",\n    \"\",\n    \"- **Convention compliance** — PR title uses a conventional commit prefix,\",\n    \"  body includes a closing keyword, branch name follows project conventions\",\n    \"- **Closing-keyword integrity** — the Phase 1.5\",\n    \"  `check-closing-keywords.sh` run exited `0`. A\",\n    \"  `CLOSING_KEYWORDS_MALFORMED` result is a **Suggested** finding (not\",\n    \"  blocking): the diff is unaffected, and Phase 5 closes the stranded\",\n    \"  issues deterministically, so gating the merge on it would wedge a\",\n    \"  correct PR over a body typo. Record every `STRANDED #<n>` in the\",\n    \"  findings and in the sticky summary so the malformed body is visible\",\n    \"  rather than silent.\",\n    \"- **Test coverage** — new or changed behavior has tests\",\n    \"- **CI status** — resolve CI via the **CI Verification** section\",\n    \"  (primary check-runs read, with the Actions-runs fallback on a\",\n    \"  fine-grained-PAT 403). The verdict must be **green**.\",\n    \"- **Scope creep** — diff stays within the issue's stated scope\",\n    \"\",\n    \"## Phase 3.5: Classify Comments\",\n    \"\",\n    \"For every comment that survived Phase 2.5 filtering, assign exactly\",\n    \"one classification and take the corresponding action. The reviewer\",\n    \"acts only on unhandled comments; anything already in a terminal state\",\n    \"was dropped in Phase 2.5 and is left alone.\",\n    \"\",\n    \"### Classifications\",\n    \"\",\n    \"#### `in-scope`\",\n    \"\",\n    \"The comment requests a change that falls **inside** the linked\",\n    \"issue's acceptance criteria (or is an obvious defect in code the PR\",\n    \"itself introduced).\",\n    \"\",\n    \"Action on this pass:\",\n    \"\",\n    \"- React `eyes` on the comment to mark it seen.\",\n    \"- Queue the comment for delegation in the Phase 4 delegation flow.\",\n    \"  When the invocation guard permits delegation, Phase 4 builds a\",\n    \"  fix-list comment from the queued items and hands the work off to\",\n    \"  `issue-worker` in feedback mode. When delegation is denied\",\n    \"  (human-authored PR with no `--allow-human-author` opt-in), the\",\n    \"  queued items remain `eyes`-only and Phase 4.5 lists them as\",\n    \"  outstanding for the human to resolve.\",\n    \"- Do **not** apply `+1` or `rocket` yet. Those are terminal\",\n    \"  reactions reserved for later passes once the fix has been accepted\",\n    \"  into the PR (`+1`) and actually landed on the branch (`rocket` —\",\n    \"  applied by Phase 4 step (f) once the worker reports the item\",\n    \"  handled).\",\n    \"\",\n    \"```bash\",\n    \"# React eyes on a PR-level issue comment\",\n    \"gh api repos/{{repository.owner}}/{{repository.name}}/issues/comments/<comment-id>/reactions \\\\\",\n    \"  -X POST -f content=eyes\",\n    \"\",\n    \"# React eyes on an inline code-review comment\",\n    \"gh api repos/{{repository.owner}}/{{repository.name}}/pulls/comments/<comment-id>/reactions \\\\\",\n    \"  -X POST -f content=eyes\",\n    \"```\",\n    \"\",\n    \"#### `out-of-scope`\",\n    \"\",\n    \"The comment requests work that falls **outside** the linked issue's\",\n    \"acceptance criteria — new functionality, a refactor that would\",\n    \"expand the diff, a cleanup in a neighbouring module, and so on. It\",\n    \"is a legitimate request, just not for this PR.\",\n    \"\",\n    \"Action:\",\n    \"\",\n    \"1. Create a new tracking issue following the `Create Issue Workflow`\",\n    \"   in CLAUDE.md. Derive the title prefix (`feat:`, `fix:`, `chore:`,\",\n    \"   etc.) from the content of the comment. Apply the correct\",\n    \"   `type:*`, `priority:*`, and `status:*` labels and assign the\",\n    \"   GitHub issue type via the documented GraphQL mutation.\",\n    \"2. Reply to the original comment with a link to the new issue:\",\n    \"   `Tracked separately in #<new-issue>.`\",\n    \"3. React `-1` on the original comment. `-1` is the terminal\",\n    \"   reaction for out-of-scope and is only applied **after** the new\",\n    \"   issue has been successfully created and the reply posted.\",\n    \"\",\n    \"```bash\",\n    \"# Reply on the same thread\",\n    \"gh pr comment <pr-number> --body 'Tracked separately in #<new-issue>.'\",\n    \"\",\n    \"# React -1 on the original comment once the new issue exists\",\n    \"gh api repos/{{repository.owner}}/{{repository.name}}/issues/comments/<comment-id>/reactions \\\\\",\n    \"  -X POST -f content=-1\",\n    \"```\",\n    \"\",\n    \"#### `dispute`\",\n    \"\",\n    \"The comment conflicts with an acceptance criterion, a documented\",\n    \"CLAUDE.md convention, or the project-context doc; or it is ambiguous\",\n    \"enough that implementation would require guessing at intent. The\",\n    \"reviewer pushes back rather than silently complying.\",\n    \"\",\n    \"Action:\",\n    \"\",\n    \"1. React `thinking_face` on the comment to mark it as disputed.\",\n    \"   This reaction is **not** terminal — it persists until the human\",\n    \"   resolves the dispute.\",\n    \"2. Post a reply on the same thread explaining the pushback. Cite\",\n    \"   the specific acceptance criterion, convention, or project-context\",\n    \"   section that the comment conflicts with, or name the ambiguity\",\n    \"   that needs resolution.\",\n    \"3. The presence of an unresolved `thinking_face` reaction by the\",\n    \"   reviewer blocks auto-merge in Phase 4 regardless of the review\",\n    \"   mode decided in Phase 2.75.\",\n    \"\",\n    \"```bash\",\n    \"# React thinking_face on the disputed comment\",\n    \"gh api repos/{{repository.owner}}/{{repository.name}}/issues/comments/<comment-id>/reactions \\\\\",\n    \"  -X POST -f content=confused\",\n    \"\",\n    \"# Post the pushback reply\",\n    \"gh pr comment <pr-number> --body '<pushback explanation>'\",\n    \"```\",\n    \"\",\n    \"Note: GitHub's reactions API uses `confused` as the content string\",\n    \"for the `thinking_face` reaction; use `content=confused` when\",\n    \"POSTing the reaction.\",\n    \"\",\n    \"#### `nit` / `question`\",\n    \"\",\n    \"The comment is a minor stylistic preference, a clarifying question\",\n    \"with a short answer, or a drive-by note that does not request a\",\n    \"code change.\",\n    \"\",\n    \"Action:\",\n    \"\",\n    \"- React `eyes` to mark the comment seen.\",\n    \"- Optionally post a brief reply when the question has a short,\",\n    \"  factual answer. Skip the reply when there is nothing useful to\",\n    \"  add — an `eyes` reaction alone is sufficient.\",\n    \"- Never apply `+1`, `rocket`, or `-1` to a `nit` / `question`\",\n    \"  comment; those reactions are reserved for their documented\",\n    \"  terminal meanings.\",\n    \"\",\n    \"### Reaction protocol summary\",\n    \"\",\n    \"| Reaction | Meaning | Terminal? |\",\n    \"|----------|---------|-----------|\",\n    \"| `eyes` | Seen by reviewer; awaiting further action | No |\",\n    \"| `thinking_face` (`confused`) | Reviewer disputes this comment | No |\",\n    \"| `+1` | Reviewer accepts the comment's request | **Yes** |\",\n    \"| `rocket` | The accepted change has landed on the branch | **Yes** |\",\n    \"| `-1` | Reviewer declined as out-of-scope; tracked in a new issue | **Yes** |\",\n    \"\",\n    \"Terminal reactions (`+1`, `rocket`, `-1`) **must only be applied**\",\n    \"when the corresponding action is truly complete:\",\n    \"\",\n    \"- `+1` — only after the reviewer has confirmed the comment's\",\n    \"  request is in-scope and the fix has been accepted for this PR.\",\n    \"- `rocket` — only after the accepted fix has actually landed on the\",\n    \"  PR's branch (a commit addressing the comment is present).\",\n    \"- `-1` — only after a new tracking issue has been successfully\",\n    \"  created for the out-of-scope request and the reply linking to it\",\n    \"  has been posted.\",\n    \"\",\n    \"Never pre-emptively apply a terminal reaction. Applying one signals\",\n    \"to humans and to future reviewer passes that the item is closed;\",\n    \"applying it early creates a false record of completion.\",\n    \"\",\n    \"## Phase 4: Decide and Act\",\n    \"\",\n    \"### Invocation guard (runs before any delegation in this phase)\",\n    \"\",\n    \"Before delegating any in-scope fix to `issue-worker`, verify the\",\n    \"delegation is permitted by author identity:\",\n    \"\",\n    `- If the PR carries the \\`${ORIGIN_ISSUE_WORKER_LABEL}\\` label **or** the`,\n    `  \\`${ORIGIN_AGENT_LABEL}\\` label, delegation is permitted. Both are`,\n    \"  agent-origin labels and both are delegation-eligible:\",\n    `  \\`${ORIGIN_ISSUE_WORKER_LABEL}\\` marks a PR opened by the \\`issue-worker\\``,\n    `  agent specifically; \\`${ORIGIN_AGENT_LABEL}\\` is the umbrella label the`,\n    \"  phased analyst/writer family stamps on the PRs it opens. Treat them\",\n    \"  identically for this guard — neither requires `--allow-human-author`.\",\n    \"- If the invocation prompt contains the literal flag\",\n    \"  `--allow-human-author`, delegation is permitted for this invocation\",\n    \"  only.\",\n    \"- Otherwise (no agent-origin label and no opt-in flag) the reviewer\",\n    \"  **must not delegate**. It still classifies comments (Phase 3.5),\",\n    \"  posts replies, applies reactions, updates the sticky summary, and\",\n    \"  (when in `auto-merge` mode and the AC/CI checks pass) enables\",\n    \"  auto-merge. Fix-list production and the issue-worker invocation are\",\n    \"  left to the human PR author. Record the reason in the Phase 4.5\",\n    \"  sticky summary as `delegation skipped: human-authored PR`.\",\n    \"\",\n    \"Skip the entire delegation flow below when the invocation guard\",\n    \"denies delegation. The pushback gate, the AC/CI evaluation, and the\",\n    \"Phase 4.5 sticky update still run.\",\n    \"\",\n    \"### Pushback gate (runs before every merge decision)\",\n    \"\",\n    \"Before taking any merge-enabling action in this phase, verify that no\",\n    \"**unresolved `thinking_face` reactions by the reviewer** remain on\",\n    \"any comment gathered in Phase 2.5.\",\n    \"\",\n    \"A `thinking_face` reaction is considered **unresolved** when:\",\n    \"\",\n    \"- The reviewer applied it on this pass or a prior pass, and\",\n    \"- The underlying comment has not since received a resolution signal\",\n    \"  from the human — for example, the comment has not been withdrawn,\",\n    \"  the human has not posted a clarifying reply that the reviewer has\",\n    \"  since marked `+1`, and no `review:auto-ok` label has been applied\",\n    \"  to the PR as an explicit override.\",\n    \"\",\n    \"If any unresolved `thinking_face` reaction exists, **do not enable\",\n    \"auto-merge** and **do not apply `review:awaiting-human` as a success\",\n    \"hand-off**. This gate fires regardless of the review mode decided in\",\n    \"Phase 2.75 — pushback blocks the merge pathway even when the mode is\",\n    \"`auto-merge`. Skip straight to Phase 4.5 to update the sticky summary\",\n    \"with the outstanding pushbacks, then stop. A downstream issue\",\n    \"refines this gate further; for now, pushback simply blocks the\",\n    \"merge pathway.\",\n    \"\",\n    \"If no unresolved `thinking_face` reactions exist, proceed with the\",\n    \"branches below based on the review mode decided in Phase 2.75.\",\n    \"\",\n    \"### Delegation flow (in-scope fixes)\",\n    \"\",\n    \"When the invocation guard above permits delegation **and** Phase 3.5\",\n    \"queued one or more `in-scope` items, the reviewer hands the fix work\",\n    \"off to `issue-worker` via a **pull-based** marker. The reviewer never\",\n    \"edits the PR's branch itself and never spawns `issue-worker` in\",\n    \"session — it posts the fix-list, applies the `review:needs-worker`\",\n    \"marker, holds the `review:fixing` lease across sessions, and exits.\",\n    \"A top-level `issue-worker` session pulls the work; a later reviewer\",\n    \"pass confirms it via the **Shared Procedure: Confirm a Completed\",\n    \"Delegation**.\",\n    \"\",\n    \"Run steps (a) through (e) below in order. They apply in **both**\",\n    \"`auto-merge` and `human-required` review modes — the mode-specific\",\n    \"auto-merge decision is deferred to the confirm pass, which only\",\n    \"re-enables auto-merge in `auto-merge` mode (in `human-required` mode\",\n    \"the confirm pass leaves `review:awaiting-human` applied and lets the\",\n    \"human own the final merge).\",\n    \"\",\n    \"#### a. Handle AC drift first\",\n    \"\",\n    \"For every queued `in-scope` item, re-check whether the comment is\",\n    \"actually a request to **change the linked issue's acceptance\",\n    \"criteria** rather than to change code that already meets the AC. If\",\n    \"it is AC drift, do **not** delegate the item:\",\n    \"\",\n    \"1. Reply on the PR thread the comment came from with the exact text:\",\n    \"   `This belongs in #<issue> — please update the issue's acceptance criteria first.`\",\n    \"2. Post a second comment on the **linked issue** with a concrete\",\n    \"   suggested edit to its Acceptance Criteria section that captures\",\n    \"   what the PR comment is asking for.\",\n    \"3. React `thinking_face` (`content=confused`) on the original PR\",\n    \"   comment. AC-drift items count as pushbacks and the standing\",\n    \"   pushback gate above will block any later auto-merge re-enable.\",\n    \"4. Drop the item from the delegation fix-list — only non-AC-drift\",\n    \"   in-scope items proceed to step (b) onwards.\",\n    \"\",\n    \"```bash\",\n    \"# Reply on the PR thread\",\n    'gh pr comment <pr-number> --body \"This belongs in #<issue> — please update the issue\\'s acceptance criteria first.\"',\n    \"\",\n    \"# Suggest the AC edit on the linked issue\",\n    \"gh issue comment <issue-number> --body '<concrete suggested AC edit>'\",\n    \"\",\n    \"# React thinking_face on the PR comment (treats as pushback)\",\n    \"gh api repos/{{repository.owner}}/{{repository.name}}/issues/comments/<comment-id>/reactions \\\\\",\n    \"  -X POST -f content=confused\",\n    \"```\",\n    \"\",\n    \"If **every** queued in-scope item is AC drift, the delegation\",\n    \"fix-list is empty — skip to Phase 4.5 to record the state and stop.\",\n    \"Do not invoke issue-worker with an empty list.\",\n    \"\",\n    \"#### b. Disable auto-merge\",\n    \"\",\n    \"Before mutating the PR, disable any pending auto-merge so a fast CI\",\n    \"pass cannot land the PR mid-delegation. The command is idempotent —\",\n    \"running it when auto-merge was never enabled is a safe no-op.\",\n    \"\",\n    \"```bash\",\n    \"gh pr merge <pr-number> --disable-auto\",\n    \"```\",\n    \"\",\n    \"#### c. Acquire the `review:fixing` lease\",\n    \"\",\n    \"Add the `review:fixing` label to the PR. The label is a mutual\",\n    \"exclusion lease — only one delegation may be in flight against a\",\n    \"given PR at a time:\",\n    \"\",\n    \"```bash\",\n    \"gh pr edit <pr-number> --add-label 'review:fixing'\",\n    \"```\",\n    \"\",\n    \"Before adding the label, list the PR's existing labels. If\",\n    \"`review:fixing` is **already present**, another delegation is\",\n    \"in-flight (or a previous delegation crashed without releasing the\",\n    \"lease). Stop immediately, log the contention to the sticky summary,\",\n    \"and exit. Do not invoke issue-worker, do not write a fix-list, and do\",\n    \"not remove the existing label — a human must investigate and clear\",\n    \"the lease manually.\",\n    \"\",\n    \"#### d. Write the fix-list comment\",\n    \"\",\n    \"Post a single PR-level comment whose body matches the format the\",\n    \"issue-worker feedback mode parses. The comment must contain a human\",\n    \"checkbox summary followed by a fenced ```json fix-list``` block. The\",\n    \"JSON block is the **authoritative** list of work — the checkbox\",\n    \"summary is for humans only.\",\n    \"\",\n    \"```markdown\",\n    \"## Reviewer: fix list for @issue-worker\",\n    \"\",\n    \"- [ ] @<author> — <instruction summary> (<file>:<line>)\",\n    \"\",\n    \"```json fix-list\",\n    \"{\",\n    '  \"pr\": <pr-number>,',\n    '  \"branch\": \"<head-ref-name>\",',\n    '  \"generated_at\": \"<ISO-8601 timestamp>\",',\n    '  \"items\": [',\n    '    {\"comment_id\": \"<id>\", \"author\": \"<login>\", \"file\": \"<path>\", \"line\": <n>, \"instruction\": \"<imperative instruction>\"}',\n    \"  ]\",\n    \"}\",\n    \"```\",\n    \"```\",\n    \"\",\n    \"Each `items[]` entry corresponds to one queued in-scope comment that\",\n    \"survived AC-drift handling. Preserve `comment_id` exactly as returned\",\n    \"by the GitHub API in Phase 2.5 — issue-worker reports back using the\",\n    \"same id so the reviewer can react on the correct source comment in\",\n    \"step (f).\",\n    \"\",\n    \"Post the comment via `gh pr comment <pr-number> --body-file <path>`\",\n    \"(or `--body` if the body is short). Capture the resulting comment id\",\n    \"in memory so Phase 4.5 can cite the fix-list URL in the sticky.\",\n    \"\",\n    \"#### e. Apply the `review:needs-worker` marker and exit `delegated`\",\n    \"\",\n    \"Hand the fix work off to `issue-worker` **by marker, not by spawn**.\",\n    \"Do **not** invoke `issue-worker` via the `Agent` tool from this pass:\",\n    \"the reviewer frequently runs at depth-1 (the orchestrator's PR sweep\",\n    \"dispatches it as a sub-agent), and the runtime forbids a depth-1\",\n    \"sub-agent from spawning a depth-2 sub-agent — an in-session dispatch\",\n    \"would silently abort and the fix-list would never be consumed.\",\n    \"Instead, apply the durable `review:needs-worker` marker so a\",\n    \"top-level `issue-worker` session discovers the PR and pulls the\",\n    \"fix-list:\",\n    \"\",\n    \"```bash\",\n    \"gh pr edit <pr-number> --add-label 'review:needs-worker'\",\n    \"```\",\n    \"\",\n    \"Then **exit this pass returning `delegated`**, holding the\",\n    \"`review:fixing` lease across sessions. Do **not** wait for the\",\n    \"worker, do **not** process a report, and do **not** re-enable\",\n    \"auto-merge in this pass. The worker applies the fix-list in its own\",\n    \"top-level session, pushes, writes a structured worker-report comment,\",\n    \"and clears `review:needs-worker`. A **subsequent** reviewer pass\",\n    \"detects the lease-without-marker state and runs the **Shared\",\n    \"Procedure: Confirm a Completed Delegation** below — that is where the\",\n    \"`rocket` / `thinking_face` reactions, the AC/CI re-evaluation, the\",\n    \"auto-merge re-enablement, and the `review:fixing` release happen.\",\n    \"\",\n    \"Before exiting, fall through to Phase 4.5 to update the sticky\",\n    \"`## Reviewer notes` comment with the delegation state. Cite at\",\n    \"minimum:\",\n    \"\",\n    \"- The fix-list comment URL produced in step (d).\",\n    \"- That the PR now carries `review:needs-worker` and is awaiting a\",\n    \"  top-level `issue-worker` pass.\",\n    \"- That `review:fixing` is held across sessions until a confirm pass\",\n    \"  releases it.\",\n    \"- The next-step: a top-level `issue-worker` run pulls the fix-list,\",\n    \"  then a follow-up reviewer pass confirms.\",\n    \"\",\n    \"Per-item `handled` / `failed` outcomes, the pushed commit SHAs, and\",\n    \"the auto-merge decision are recorded on the **confirm pass**, not\",\n    \"here — this pass has not yet seen the worker's result.\",\n    \"\",\n    \"### If all acceptance criteria are met and CI is green\",\n    \"\",\n    \"#### Pre-merge closing-keyword check\",\n    \"\",\n    \"Run this **before** branching on the review mode — it applies in both\",\n    \"modes and is the last cheap moment to catch a body that would strand\",\n    \"issues on merge:\",\n    \"\",\n    \"```bash\",\n    \".claude/procedures/check-closing-keywords.sh <pr-number>\",\n    \"```\",\n    \"\",\n    \"Re-run it here rather than reusing the Phase 1.5 result: the body may\",\n    \"have been edited since, and the merge is about to make the answer\",\n    \"permanent.\",\n    \"\",\n    \"- **Exit `0`** — nothing to do; every linked issue will auto-close.\",\n    \"- **Exit `1`** — the body strands at least one issue. Do **not** block\",\n    \"  the merge; post one comment naming the stranded issues and the\",\n    \"  corrected block, then continue. Phase 5 closes the survivors\",\n    \"  explicitly, so the malformed body costs a comment, not a wedged PR.\",\n    \"\",\n    \"```bash\",\n    \"gh pr comment <pr-number> --body 'GitHub honours only one issue reference per closing keyword, so this body would close #<first> and silently leave #<stranded…> open. Give each issue its own keyword, one per line:\",\n    \"\",\n    \"Closes #<first>\",\n    \"Closes #<stranded>\",\n    \"\",\n    \"Merging anyway — Phase 5 will close the stranded issues explicitly.'\",\n    \"```\",\n    \"\",\n    \"Carry the full stranded set into Phase 5 verbatim.\",\n    \"\",\n    \"Then branch on the **review mode** decided in Phase 2.75:\",\n    \"\",\n    \"#### Mode `auto-merge`\",\n    \"\",\n    \"Enable squash auto-merge with branch deletion. This queues the merge to\",\n    \"happen once required checks pass; no separate approval review is needed.\",\n    \"\",\n    \"```bash\",\n    \"gh pr merge <pr-number> --auto --squash --delete-branch \\\\\",\n    \"  --subject '<conventional-commit-title>' \\\\\",\n    \"  --body '<extended-description>'\",\n    \"```\",\n    \"\",\n    \"The squash-merge subject should follow conventional commit format (e.g.\",\n    \"`feat(scope): description`). The body should bullet the changes and end\",\n    \"with `Closes #<issue-number>`.\",\n    \"\",\n    \"##### Update the branch when `mergeStateStatus` is `BEHIND`\",\n    \"\",\n    \"After enabling auto-merge, re-read the PR's `mergeStateStatus` so a\",\n    \"branch that fell behind the default branch lands on the next CI tick\",\n    \"instead of sitting in the auto-merge queue indefinitely:\",\n    \"\",\n    \"```bash\",\n    \"gh pr view <pr-number> --json mergeStateStatus --jq '.mergeStateStatus'\",\n    \"```\",\n    \"\",\n    \"Before running `gh pr update-branch`, evaluate the **eligibility\",\n    \"gate** below. The step runs when `mergeStateStatus == BEHIND` **AND**\",\n    \"either of the following holds:\",\n    \"\",\n    \"- The review mode decided in Phase 2.75 is `auto-merge`, **or**\",\n    \"- The review mode is `human-required` **and** `matched_rule == 6`\",\n    \"  (size threshold is the sole trigger that fixed the mode).\",\n    \"\",\n    \"All other `human-required` matches (rules 2–5) continue to block\",\n    \"`update-branch`. Concretely, **never** run `gh pr update-branch`\",\n    \"when the mode is `human-required` and any of the following fired:\",\n    \"\",\n    \"- rule 2 (`review:human-required` label),\",\n    \"- rule 3 (any `labels-that-force-human` label),\",\n    \"- rule 4 (`human-required.paths` glob match), or\",\n    \"- rule 5 (`human-required.issue-types` match).\",\n    \"\",\n    \"The rationale: rule 6 fires on the **volume** of the diff alone —\",\n    \"there is nothing about the changed paths or labels that suggests a\",\n    \"human reviewer has explicit ownership of the branch's lifecycle.\",\n    \"Pushing the default branch into a size-tripped human-required PR\",\n    \"keeps it from sitting stale while the human is still drafting\",\n    \"their review. By contrast, each of rules 2–5 signals a human\",\n    \"reviewer who owns the branch's lifecycle; silently pushing main\",\n    \"into those PRs expands the diff under review without their consent.\",\n    \"\",\n    \"When the gate **denies** `update-branch` (`human-required` mode and\",\n    \"`matched_rule` in 2–5), record\",\n    \"`Branch updated: not eligible (human-required by rule <N>)` and skip\",\n    \"the rest of this sub-section. The human reviewer keeps branch-\",\n    \"lifecycle ownership.\",\n    \"\",\n    \"When the gate **permits** `update-branch`, attempt to bring the head\",\n    \"branch current with the default branch via `gh pr update-branch`\",\n    \"(default merge strategy — **never** `--rebase`, which would rewrite\",\n    \"commits on a published branch):\",\n    \"\",\n    \"```bash\",\n    \"gh pr update-branch <pr-number>\",\n    \"```\",\n    \"\",\n    \"Branch on the outcome:\",\n    \"\",\n    \"- **Success** — record `Branch updated: yes` for the per-PR report and\",\n    \"  stop. Auto-merge (when enabled) will fire when required checks pass\",\n    \"  on the new head SHA. Do **not** poll for the merge here — Phase 5\",\n    \"  owns polling.\",\n    \"- **Failure for reasons other than a merge conflict** (permission\",\n    \"  denied, branch protection refusing the merge commit, transient\",\n    \"  network error) — record `Branch updated: failed (<reason>)`, post a\",\n    \"  short comment explaining the failure, and stop. Do not retry.\",\n    \"- **Failure because the merge would conflict** — proceed to the\",\n    \"  conflict-resolution delegation flow below.\",\n    \"\",\n    \"When `mergeStateStatus` is **not** `BEHIND` (`CLEAN`, `BLOCKED`,\",\n    \"`UNSTABLE`, `HAS_HOOKS`, `UNKNOWN`), record `Branch updated: not needed`\",\n    \"and skip the rest of this sub-section. Only the `BEHIND` state triggers\",\n    \"an `update-branch` attempt — every other state either has nothing to do\",\n    \"or is already gated on a different signal that Phase 5 picks up.\",\n    \"\",\n    \"##### Conflict-resolution delegation (BEHIND + conflicts)\",\n    \"\",\n    \"When `gh pr update-branch <pr-number>` fails because the merge would\",\n    \"produce conflicts, hand off to the **Shared Procedure:\",\n    \"Conflict-Resolution Delegation** section below. That procedure owns\",\n    \"the guards, the `shared-index` vs `generic` classification, the two\",\n    \"typed recipes, and the fallback — defined once and shared with the\",\n    \"Phase 1.5 already-`CONFLICTING` entry point. Invoke it with this\",\n    \"entry point's parameters:\",\n    \"\",\n    \"- **Entry point:** `update-branch-conflict`. The set of conflicting\",\n    \"  files is the list reported by the failed `gh pr update-branch`\",\n    \"  (cross-referenced with `gh pr view <pr-number> --json files`).\",\n    \"- **On the procedure returning `delegated`:** record\",\n    \"  `Branch updated: delegated (PR #<n>)` for the per-PR report.\",\n    \"- **On the procedure returning `skipped` (a guard denied delegation\",\n    \"  or the guards failed):** the procedure has already posted the\",\n    \"  fallback comment and recorded\",\n    \"  `Branch updated: failed (conflicts; <short reason>)`. Stop.\",\n    \"\",\n    \"#### Mode `human-required`\",\n    \"\",\n    \"Do **not** run `gh pr merge --auto`. Instead, hand the PR off to a\",\n    \"human reviewer:\",\n    \"\",\n    \"1. Apply the `review:awaiting-human` label so the PR is discoverable\",\n    \"   in the human-review queue:\",\n    \"\",\n    \"   ```bash\",\n    \"   gh pr edit <pr-number> --add-label 'review:awaiting-human'\",\n    \"   ```\",\n    \"\",\n    \"2. **If `matched_rule == 6`** (size threshold was the sole trigger),\",\n    \"   run the `Update the branch when `mergeStateStatus` is `BEHIND``\",\n    \"   step from the `Mode auto-merge` branch above before exiting. The\",\n    \"   eligibility gate documented in that sub-section explicitly permits\",\n    \"   `gh pr update-branch` on size-only human-required PRs so the bot\",\n    \"   keeps the branch fresh against the default branch while the human\",\n    \"   reviews. Skip this sub-step for `matched_rule` in 2–5 — the gate\",\n    \"   denies `update-branch` there and the human owns branch-lifecycle.\",\n    \"\",\n    \"3. Exit cleanly after the acceptance-criteria check completes and any\",\n    \"   summary comment the reviewer posts. Proceed to Phase 5 only if a\",\n    \"   merge occurred — in `human-required` mode the reviewer stops at\",\n    \"   the hand-off and does not poll for merge.\",\n    \"\",\n    \"The reason captured in Phase 2.75 should be included in any summary\",\n    \"comment so maintainers know why human review was required (path hit,\",\n    \"issue type, size threshold, label, or default).\",\n    \"\",\n    \"### If any criterion is missing, partial, or CI is failing\",\n    \"\",\n    \"Post a plain comment (not a formal review block) with grouped findings:\",\n    \"\",\n    \"```bash\",\n    \"gh pr comment <pr-number> --body '<grouped findings>'\",\n    \"```\",\n    \"\",\n    \"Group findings by severity (**Blocking** / **Suggested** / **Nitpick**).\",\n    \"For each blocking finding, cite the unmet acceptance criterion and the\",\n    \"file or function the gap lives in. Do **not** merge, and do **not** push\",\n    \"any commits to the PR's branch.\",\n    \"\",\n    \"Rationale for using a plain comment rather than `gh pr review\",\n    \"--request-changes`: it is lighter-weight, doesn't require the author to\",\n    \"dismiss a formal review, and composes cleanly with the multi-PR loop.\",\n    \"\",\n    \"## Phase 4.5: Update Sticky Summary\",\n    \"\",\n    \"On **every pass**, create or update a single **`## Reviewer notes`**\",\n    \"comment on the PR. This sticky comment is the human-facing single\",\n    \"source of truth for the PR's state — one comment per PR, edited in\",\n    \"place across passes, never duplicated. Do not post a fresh\",\n    '\"pass N summary\" on each iteration.',\n    \"\",\n    \"### Step 1: Find the existing sticky comment (if any)\",\n    \"\",\n    \"List PR-level comments and look for one authored by the reviewer\",\n    \"whose body starts with `## Reviewer notes`:\",\n    \"\",\n    \"```bash\",\n    \"gh api repos/{{repository.owner}}/{{repository.name}}/issues/<pr-number>/comments\",\n    \"```\",\n    \"\",\n    \"If multiple candidates exist (an older run double-posted before this\",\n    \"phase existed), keep the earliest and plan to delete the duplicates\",\n    \"on a later pass. Never delete another author's comment.\",\n    \"\",\n    \"### Step 2: Compose the sticky body\",\n    \"\",\n    \"The body uses the following shape:\",\n    \"\",\n    \"```\",\n    \"## Reviewer notes\",\n    \"\",\n    \"**Mode:** auto-merge | human-required — <reason from Phase 2.75>\",\n    \"**AC status:** <met / partial / missing> (evidence links)\",\n    \"**CI status:** green | pending | red\",\n    \"**Outstanding:** <list of comments still open with their classification and author>\",\n    \"**Pushbacks:** <list of disputes with reasons>\",\n    \"**Label reconciliation:** <consistent | corrections applied this pass>\",\n    \"**Closing keywords:** ok | malformed — strands #<n>[, #<n>…]\",\n    \"**Last pass:** <ISO timestamp>\",\n    \"```\",\n    \"\",\n    \"Populate each field from the phases above:\",\n    \"\",\n    \"- **Mode / reason** — the mode and reason recorded in Phase 2.75.\",\n    \"- **AC status** — the checklist produced in Phase 3 (met, partial,\",\n    \"  or missing), with links to the files or tests that provide the\",\n    \"  evidence.\",\n    \"- **CI status** — the verdict from the **CI Verification** section\",\n    \"  (primary check-runs read, or the Actions-runs fallback when\",\n    \"  check-runs returns a fine-grained-PAT 403).\",\n    \"- **Outstanding** — the comments still carrying a non-terminal\",\n    \"  reviewer reaction from Phase 3.5 (typically `eyes` for queued\",\n    \"  in-scope items and `nit` / `question` items that remain open).\",\n    \"  List each as `<classification>: <author> — <short summary> (<url>)`.\",\n    \"- **Pushbacks** — every comment the reviewer reacted\",\n    \"  `thinking_face` to on this or any prior pass, with the reason\",\n    \"  captured in the pushback reply. Empty list when there are none.\",\n    \"- **Label reconciliation** — the outcome of Phase 2.8: either\",\n    \"  `consistent` (no mutually-exclusive labels found) or a list of\",\n    \"  the corrections applied this pass (the detected violation combo,\",\n    \"  the label(s) removed, and the resulting self-consistent set).\",\n    \"  Every reconciliation correction is recorded here for auditability.\",\n    \"- **Closing keywords** — the\",\n    \"  `.claude/procedures/check-closing-keywords.sh` verdict: `ok`, or\",\n    \"  `malformed` plus every `STRANDED #<n>` the body would leave open.\",\n    \"  Recorded on every pass so a body that strands issues is visible to a\",\n    \"  human before the merge, not only after Phase 5 repairs it.\",\n    \"- **Last pass** — the ISO 8601 timestamp of this run.\",\n    \"\",\n    \"### Step 3: Create or edit in place\",\n    \"\",\n    \"If no existing sticky comment was found in Step 1, create one:\",\n    \"\",\n    \"```bash\",\n    \"gh pr comment <pr-number> --body '<sticky body>'\",\n    \"```\",\n    \"\",\n    \"If an existing sticky comment was found, edit it in place using the\",\n    \"comment id. Do not delete and re-create — editing preserves the\",\n    \"comment's URL and any reactions humans have added to the summary:\",\n    \"\",\n    \"```bash\",\n    \"gh api repos/{{repository.owner}}/{{repository.name}}/issues/comments/<sticky-comment-id> \\\\\",\n    \"  -X PATCH -f body='<sticky body>'\",\n    \"```\",\n    \"\",\n    \"The sticky summary must be updated on every pass through Phase 4.5,\",\n    \"including passes that ended in a pushback-gated skip, a\",\n    \"`NEEDS_CHANGES` findings comment, or the `human-required` hand-off.\",\n    \"Humans rely on the sticky comment to see the current state of the\",\n    \"PR at a glance — it must never go stale while the reviewer is\",\n    \"actively processing the PR.\",\n    \"\",\n    \"## Shared Procedure: Conflict-Resolution Delegation\",\n    \"\",\n    \"This procedure resolves a PR that cannot land because its head\",\n    \"branch conflicts with the default branch. It is invoked from **two**\",\n    \"entry points, both of which reuse the identical guards,\",\n    \"classification, typed recipes, and fallback defined here — the flow\",\n    \"is defined **once** and shared:\",\n    \"\",\n    \"- **Phase 4 `update-branch-conflict`** — a PR that was MERGEABLE at\",\n    \"  Phase 1.5 went BEHIND, and `gh pr update-branch` then failed\",\n    \"  because the merge would conflict.\",\n    \"- **Phase 1.5 `already-conflicting`** — the orchestrator handed the\",\n    \"  reviewer a PR that is **already** `CONFLICTING` (its\",\n    '  `mergeable == \"CONFLICTING\"`) before any review work began.',\n    \"\",\n    \"The reviewer **may** delegate conflict resolution to `issue-worker`\",\n    \"via the feedback-mode delegation contract (the same path Phase 4's\",\n    \"in-scope-fix delegation uses). The reviewer never hand-resolves\",\n    \"conflicts itself — branch mutations always belong to `issue-worker`.\",\n    \"\",\n    \"### Entry-point parameters\",\n    \"\",\n    \"The caller supplies which entry point it is and how the conflicting\",\n    \"files are identified. Everything after this step is identical across\",\n    \"both entry points.\",\n    \"\",\n    \"- **`update-branch-conflict`** — the conflicting-file set is the\",\n    \"  list reported by the failed `gh pr update-branch` (cross-referenced\",\n    \"  with `gh pr view <pr-number> --json files`).\",\n    \"- **`already-conflicting`** — there is no failed `update-branch` to\",\n    \"  read conflicting paths from. Identify the conflicting files from\",\n    \"  the PR's merge state instead: attempt a local merge of the default\",\n    \"  branch into the head branch in a scratch checkout (or read the\",\n    \"  conflicting paths git reports) and collect the files that carry\",\n    \"  `<<<<<<<` / `=======` / `>>>>>>>` conflict markers. Use that set\",\n    \"  as the conflicting-file list. The reviewer inspects these markers\",\n    \"  read-only to classify; it does **not** stage, commit, or push any\",\n    \"  resolution — the actual merge-and-resolve is delegated to\",\n    \"  `issue-worker` exactly as in the other entry point.\",\n    \"\",\n    \"### Guards\",\n    \"\",\n    \"Delegate **only when all** of the following hold. If any guard fails,\",\n    \"fall through to the **Fallback** at the end of this procedure and\",\n    \"return `skipped`.\",\n    \"\",\n    \"1. **Review mode is `auto-merge`.** Never delegate conflict\",\n    \"   resolution on `human-required` PRs — pushing worker-resolved\",\n    \"   merge content into them expands the diff under review without\",\n    \"   the human reviewer's consent. (Unlike the `update-branch` step,\",\n    \"   which permits a size-only `human-required` carve-out, the\",\n    \"   conflict-resolution delegation flow is auto-merge-only across\",\n    \"   the board: a worker's conflict-resolution merge reconciles both\",\n    \"   sides of each conflict into the branch, a stronger change to the\",\n    \"   reviewed diff than the clean merge-commit `gh pr update-branch`\",\n    \"   performs on a no-conflict branch.)\",\n    \"2. **Delegation invocation guard permits the hand-off** — the PR\",\n    `   carries the \\`${ORIGIN_ISSUE_WORKER_LABEL}\\` label or the`,\n    `   \\`${ORIGIN_AGENT_LABEL}\\` label, **or** the reviewer was`,\n    \"   invoked with `--allow-human-author`. The same guard used for the\",\n    \"   in-scope-fix delegation flow applies here unchanged — both\",\n    \"   agent-origin labels are delegation-eligible.\",\n    \"3. **The `review:fixing` lease is currently free.** If\",\n    \"   `review:fixing` is already on the PR, another delegation is\",\n    \"   in-flight; skip conflict-resolution delegation, log the contention\",\n    \"   to the sticky summary, and fall through to the fallback.\",\n    \"4. **No conflicting file is generated or projen-managed.** Inspect\",\n    \"   the conflicting paths from the entry-point step above. If **any**\",\n    \"   conflicting path matches one of the following globs, the conflict\",\n    \"   is unsafe to resolve mechanically and the reviewer must skip\",\n    \"   delegation:\",\n    \"    - `**/*.lock` and `pnpm-lock.yaml` / `yarn.lock` / `package-lock.json`\",\n    \"    - `**/.projen/**`\",\n    \"    - any file whose first 5 lines contain the marker\",\n    \"      `~~ Generated by projen` or `// Generated by`.\",\n    \"   The lockfile guard exists because lockfile conflicts often need a\",\n    \"   regen (`pnpm i`) rather than a textual merge; the projen / generated\",\n    \"   guard exists because those files are derived from `.projenrc.ts`\",\n    \"   and conflicts there should be resolved by re-running synth, not by\",\n    \"   merging the conflict markers.\",\n    \"\",\n    \"### Classify each conflicting file\",\n    \"\",\n    \"When every guard above passes, **classify each conflicting file**\",\n    \"before composing the fix-list. The classification picks one of two\",\n    \"typed recipes — a precise `shared-index` resolver when every\",\n    \"conflict is a row-insert race on a registry / index / feature-matrix\",\n    \"file, or the generic conflict-resolution recipe in every other case.\",\n    \"\",\n    \"**Classification step.** For each conflicting path, decide whether\",\n    \"the file is `shared-index` or `generic` against these criteria (the\",\n    \"shared-index glob set comes from the `shared-editing-safety` rule —\",\n    \"see the bundle's `shared-editing.ts` for the canonical constant):\",\n    \"\",\n    \"- `shared-index` — the path matches one of the shared-editing glob\",\n    \"  patterns:\",\n    ...DEFAULT_SHARED_INDEX_PATHS.map((p) => `    - \\`${p}\\``),\n    \"  **AND** the conflict diff is bounded to row insertions only.\",\n    \"  Inspect the merge conflict diff for the file: every `<<<<<<<` /\",\n    \"  `=======` / `>>>>>>>` hunk must touch only data rows (lines that\",\n    \"  start with `| ` and are not the table header or the `|---|---|`\",\n    \"  separator). The conflict must **not** touch:\",\n    \"    - The frontmatter block (lines between the opening and\",\n    \"      closing `---` fences at the top of the file).\",\n    \"    - The page H1 or any surrounding prose paragraphs.\",\n    \"    - The table header row (the first `| Column | ... |` row of\",\n    \"      any table).\",\n    \"    - The separator row (`|---|---|...|`).\",\n    \"  If the conflict hunks touch any of the above, classify the file\",\n    \"  as `generic` — the mechanical row-insert recipe cannot safely\",\n    \"  reconcile structural edits.\",\n    \"- `generic` — anything else (path outside the shared-editing glob\",\n    \"  set, **or** conflict hunks touch the frontmatter / header /\",\n    \"  separator / surrounding prose).\",\n    \"\",\n    \"**Branching emit step.**\",\n    \"\",\n    \"- **Every conflicting file is `shared-index`** — emit the typed\",\n    '  fix-list item with `comment_id: \"synthetic:rebase-shared-index\"`',\n    \"  carrying the explicit re-insert recipe (see step 3 below). The\",\n    \"  worker mechanically re-inserts each row in declared sort order\",\n    \"  against the merged file.\",\n    \"- **Any conflicting file is `generic`** — emit the existing generic\",\n    '  fix-list item with `comment_id: \"synthetic:rebase-behind-main\"`',\n    \"  (see step 3 below). The worker performs a hand-merge of the\",\n    \"  conflict markers.\",\n    \"\",\n    \"**Marker name vs. operation.** The two `comment_id` values retain\",\n    \"their historical `rebase` spelling as a **stable cross-session\",\n    \"identifier** — a fix-list posted by an older reviewer and consumed\",\n    \"by a newer worker still matches. The operation they now select is a\",\n    \"**merge** of the default branch into the PR branch, **not** a\",\n    \"rebase: the PR branch is already pushed and diverged, so a rebase\",\n    \"would rewrite its published history and force the worker into a\",\n    \"`--force-with-lease` push that the never-force-push rule forbids. A\",\n    \"merge commit is fast-forward-pushable with a plain `git push`, so\",\n    \"the recipe stays publishable.\",\n    \"\",\n    \"### Hand off to `issue-worker`\",\n    \"\",\n    \"Hand off to `issue-worker` with the chosen single synthetic\",\n    \"fix-list item:\",\n    \"\",\n    \"1. **Disable auto-merge** so a fast CI pass cannot land the PR\",\n    \"   mid-delegation (idempotent — safe no-op when auto-merge was never\",\n    \"   enabled). This mirrors step (b) of the in-scope-fix flow:\",\n    \"\",\n    \"   ```bash\",\n    \"   gh pr merge <pr-number> --disable-auto\",\n    \"   ```\",\n    \"\",\n    \"2. **Acquire the `review:fixing` lease** by adding the label\",\n    \"   (mirrors step (c) of the in-scope-fix flow). On contention, abort\",\n    \"   the delegation and fall through to the fallback:\",\n    \"\",\n    \"   ```bash\",\n    \"   gh pr edit <pr-number> --add-label 'review:fixing'\",\n    \"   ```\",\n    \"\",\n    \"3. **Post a fix-list comment** containing exactly one synthetic item\",\n    \"   describing the conflict resolution. The `comment_id` field selects\",\n    \"   the typed recipe (both perform a **merge** of the default branch\",\n    \"   into the PR branch — see the marker-name note above):\",\n    \"\",\n    \"   - `synthetic:rebase-behind-main` — generic conflict; the worker\",\n    \"     resolves conflicting hunks by hand.\",\n    \"   - `synthetic:rebase-shared-index` — every conflict is a pure\",\n    \"     row-insert race on a shared-index file; the worker re-inserts\",\n    \"     each row in declared sort order against the merged file.\",\n    \"\",\n    \"   The next reviewer pass identifies the item by its `comment_id`.\",\n    \"\",\n    \"   **Generic shape (`synthetic:rebase-behind-main`):**\",\n    \"\",\n    \"   ```markdown\",\n    \"   ## Reviewer: fix list for @issue-worker\",\n    \"\",\n    \"   - [ ] @reviewer — merge origin/<default-branch> into the PR branch and resolve conflicts in: <space-separated list of conflicting files>\",\n    \"\",\n    \"   ```json fix-list\",\n    \"   {\",\n    '     \"pr\": <pr-number>,',\n    '     \"branch\": \"<head-ref-name>\",',\n    '     \"generated_at\": \"<ISO-8601 timestamp>\",',\n    '     \"items\": [',\n    '       {\"comment_id\": \"synthetic:rebase-behind-main\", \"author\": \"reviewer\", \"file\": \"<first-conflicting-file>\", \"instruction\": \"Branch is BEHIND default-branch with merge conflicts. Fetch and merge the default branch into the PR branch: `git fetch origin && git merge --no-edit origin/<default-branch>`. Resolve the conflicts in <conflicting-files> by reconciling both sides (`<<<<<<< HEAD` is this PR\\'s change), `git add` each resolved file, then `git commit --no-edit` to complete the merge commit. Push the merged branch with a plain non-force `git push origin <branch>` — the merge commit is fast-forward-pushable, so no force-push is needed — and report success.\"}',\n    \"     ]\",\n    \"   }\",\n    \"   ```\",\n    \"   ```\",\n    \"\",\n    \"   **Typed shape (`synthetic:rebase-shared-index`).** The\",\n    \"   `instruction` field carries the full re-insert recipe — the\",\n    \"   worker reads it imperatively, so spell every step out:\",\n    \"\",\n    \"   ```markdown\",\n    \"   ## Reviewer: fix list for @issue-worker\",\n    \"\",\n    \"   - [ ] @reviewer — merge origin/<default-branch> into the PR branch and re-insert shared-index rows in: <space-separated list of conflicting files>\",\n    \"\",\n    \"   ```json fix-list\",\n    \"   {\",\n    '     \"pr\": <pr-number>,',\n    '     \"branch\": \"<head-ref-name>\",',\n    '     \"generated_at\": \"<ISO-8601 timestamp>\",',\n    '     \"items\": [',\n    '       {\"comment_id\": \"synthetic:rebase-shared-index\", \"author\": \"reviewer\", \"file\": \"<first-conflicting-file>\", \"instruction\": \"Branch is BEHIND default-branch with shared-index row-insert conflicts only. Apply this recipe: (1) Fetch and merge the default branch into the PR branch: `git fetch origin && git merge --no-edit origin/<default-branch>`. (2) For each conflicting shared-index file: the conflict has this PR\\'s row on the `<<<<<<< HEAD` side and the other PR\\'s row on the `>>>>>>> origin/<default-branch>` side — extract this PR\\'s row and re-insert that row in declared sort order alongside the other PR\\'s row using the file\\'s documented sort key (alphabetical on the first column by default) so both rows survive, remove the conflict markers, stage the file with `git add <path>`. (3) Run the commit-path verification for each row: `count=$(git show :<path> | grep -Fc <row-unique-marker>) && [ \\\\\"$count\\\\\" = \\\\\"1\\\\\" ] || exit 1`. (4) Complete the merge with `git commit --no-edit` and push with a plain non-force `git push origin <branch>` — the merge commit is fast-forward-pushable, so no force-push is needed. (5) If any conflict marker touches the frontmatter, table header row, `|---|---|` separator, or surrounding prose, abort with `git merge --abort` and emit `BLOCKED <reason>` — the precondition guards from the reviewer\\'s classification step were violated.\"}',\n    \"     ]\",\n    \"   }\",\n    \"   ```\",\n    \"   ```\",\n    \"\",\n    \"4. **Apply the durable `review:needs-worker` marker** so a\",\n    \"   subsequent (top-level) `issue-worker` pass discovers the PR and\",\n    \"   pulls the fix-list. Do **not** spawn `issue-worker` yourself — the\",\n    \"   reviewer often runs at depth-1 (the orchestrator's PR sweep\",\n    \"   dispatches it as a sub-agent) where nested sub-agent spawning is\",\n    \"   forbidden, so an in-session `Agent` dispatch would silently abort.\",\n    \"   The hand-off is pull-based: the marker is the signal, the\",\n    \"   `review:fixing` lease (acquired in step 2) is held **across\",\n    \"   sessions** until the worker clears the marker and a later reviewer\",\n    \"   pass confirms.\",\n    \"\",\n    \"   ```bash\",\n    \"   gh pr edit <pr-number> --add-label 'review:needs-worker'\",\n    \"   ```\",\n    \"\",\n    \"5. **Exit returning `delegated`.** The delegation is complete for\",\n    \"   this pass: the fix-list is posted, the lease is held, and the\",\n    \"   marker is set. Do **not** wait for the worker, do **not** process\",\n    \"   a worker report, and do **not** re-enable auto-merge in this pass.\",\n    \"   The worker runs in its own top-level session; a **subsequent**\",\n    \"   reviewer pass detects the worker finished (PR carries\",\n    \"   `review:fixing` but **not** `review:needs-worker`), reacts on the\",\n    \"   source comment, re-evaluates AC/CI against the merged branch,\",\n    \"   re-enables auto-merge, and releases the `review:fixing` lease. See\",\n    \"   the **Confirm pass** section below.\",\n    \"\",\n    \"Return `delegated` to the caller once the marker is applied and the\",\n    \"fix-list posted — the delegation itself is the action taken. Unlike a\",\n    \"merge, `delegated` does **not** imply the fix landed in this pass; it\",\n    \"means the work is durably queued for the pull-based consumer and a\",\n    \"later confirm pass will finish the loop.\",\n    \"\",\n    \"### Fallback\",\n    \"\",\n    \"**Fallback when delegation is not permitted or guards fail.** Post a\",\n    \"short comment explaining why the branch could not be updated\",\n    \"automatically and stop. Do not push commits, do not force, do not\",\n    \"retry. Record `Branch updated: failed (conflicts; <short reason>)`\",\n    \"and return `skipped` to the caller.\",\n    \"\",\n    \"```bash\",\n    \"gh pr comment <pr-number> --body 'Branch is BEHIND <default-branch> with conflicts. <short reason delegation was skipped — e.g. human-required mode, generated-file conflicts, or in-flight review:fixing lease>. A human (or the next reviewer pass after the branch is updated) will need to resolve.'\",\n    \"```\",\n    \"\",\n    \"## Shared Procedure: Confirm a Completed Delegation\",\n    \"\",\n    \"Delegation is **pull-based and spans sessions**: the reviewer that\",\n    \"posts a fix-list never finishes the loop in the same pass. It posts\",\n    \"the fix-list, acquires the `review:fixing` lease, applies the durable\",\n    \"`review:needs-worker` marker, and exits returning `delegated`. A\",\n    \"**separate** top-level `issue-worker` session then discovers the\",\n    \"marker, applies the fix-list (an editorial fix or a conflict-resolution\",\n    \"merge), pushes,\",\n    \"writes a structured worker-report comment, and **clears**\",\n    \"`review:needs-worker` — leaving `review:fixing` in place for the\",\n    \"reviewer to release. The confirm pass below is how a later reviewer\",\n    \"pass closes the loop. It runs in **both** delegation flows (the\",\n    \"Phase 4 in-scope-fix flow and the Shared Conflict-Resolution\",\n    \"Procedure) — the marker, not the flow, is what a confirm pass keys\",\n    \"on.\",\n    \"\",\n    \"### Detecting a completed delegation\",\n    \"\",\n    \"Early in any reviewer pass (after Phase 2 gathers labels), inspect\",\n    \"the PR's labels for the **lease-without-marker** state:\",\n    \"\",\n    \"- `review:fixing` is **present** (a delegation lease is held), **and**\",\n    \"- `review:needs-worker` is **absent** (the worker cleared its marker\",\n    \"  on completion).\",\n    \"\",\n    \"When both hold, a delegation the previous pass kicked off has been\",\n    \"consumed and pushed by the worker. Run the confirm steps below before\",\n    \"proceeding with the rest of the pass.\",\n    \"\",\n    \"When **both** `review:fixing` and `review:needs-worker` are present,\",\n    \"the delegation is still in flight (the worker has not yet picked it\",\n    \"up or has not finished). Do **not** re-post the fix-list and do\",\n    \"**not** re-acquire the lease — log the in-flight state to the sticky\",\n    \"summary and exit; a later pass confirms once the worker clears the\",\n    \"marker.\",\n    \"\",\n    \"### Confirm steps\",\n    \"\",\n    \"1. **Read the worker's report.** Find the most recent structured\",\n    \"   worker-report comment the `issue-worker` posted on the PR (it\",\n    \"   cites the pushed commit SHAs and a per-item `handled` / `failed`\",\n    \"   outcome keyed by `comment_id`). Use it to drive the reactions\",\n    \"   below — the same per-item logic the in-session report processing\",\n    \"   used to perform.\",\n    \"2. **React on the source comments.** For each item:\",\n    \"   - **`handled`** — react `rocket` on the original source comment\",\n    \"     (the fix-list comment for a synthetic conflict-resolution item)\",\n    \"     to signal the accepted change has landed.\",\n    \"   - **`failed`** — react `thinking_face` (`content=confused`) on the\",\n    \"     source comment and post a reply citing the worker's failure\",\n    \"     reason.\",\n    \"3. **Re-evaluate AC/CI against the merged branch.** Re-run the Phase\",\n    \"   3 acceptance-criteria comparison and the **CI Verification** check\",\n    \"   against the **updated** head SHA the worker pushed — do not reuse\",\n    \"   any pre-delegation result.\",\n    \"4. **Conditionally re-enable auto-merge** under the same four\",\n    \"   conditions as the in-scope-fix flow's step (h): mode still\",\n    \"   `auto-merge`, all AC met against the updated diff, no unresolved\",\n    \"   `thinking_face` pushbacks, and CI green-or-pending.\",\n    \"5. **Release the `review:fixing` lease** — always, even when an item\",\n    \"   failed:\",\n    \"\",\n    \"   ```bash\",\n    \"   gh pr edit <pr-number> --remove-label 'review:fixing'\",\n    \"   ```\",\n    \"\",\n    \"6. **Update the sticky summary** with the per-item outcomes, the\",\n    \"   commit SHAs from the worker report, and the auto-merge decision.\",\n    \"\",\n    \"### Stale-lease reclaim\",\n    \"\",\n    \"A crashed worker must not wedge a PR forever. A `review:fixing` lease\",\n    \"is **orphaned** when it has no `review:needs-worker` companion\",\n    \"**and** no consuming worker is making progress — i.e. the lease is\",\n    \"older than the stale threshold (the same in-progress threshold the\",\n    \"maintenance sweep applies, 72h by default) with no worker-report\",\n    \"comment newer than the fix-list. The reclaim is wired into the\",\n    \"maintenance sweep, not a reviewer pass: the sweep **re-applies**\",\n    \"`review:needs-worker` (re-arming the durable work marker, leaving the\",\n    \"`review:fixing` lease untouched) and posts an audit-trail note\",\n    \"comment, so the Phase B1 feedback drain retries the delegation\",\n    \"autonomously — no human is needed to free the lease. The maintenance\",\n    \"sweep also auto-reconciles the **consumed-but-uncleared** wedge (both\",\n    \"labels present, branch HEAD advanced past the fix-list, no\",\n    \"worker-report) by removing `review:needs-worker` so the reviewer\",\n    \"confirm pass can merge. A lease is never silently force-released — every\",\n    \"reconcile posts an audit-trail note comment. See the **Stale-lease\",\n    \"reclaim** subsection of the `pr-review-feedback-protocol` rule for the\",\n    \"full lifecycle.\",\n    \"\",\n    \"## Phase 5: Branch Cleanup and Issue Closure Verification\",\n    \"\",\n    \"Skip this phase entirely when the review mode from Phase 2.75 is\",\n    \"`human-required` — no merge was initiated, so there is nothing to poll\",\n    \"and no branch to clean up. Report the hand-off and stop.\",\n    \"\",\n    \"In `auto-merge` mode, auto-merge may not be immediate. Poll the PR\",\n    \"state up to 10 times, waiting 30 seconds between polls:\",\n    \"\",\n    \"```bash\",\n    \"gh pr view <pr-number> --json state --jq '.state'\",\n    \"```\",\n    \"\",\n    \"- **`MERGED`** — clean up locally **and** verify **every** linked issue\",\n    \"  closed:\",\n    \"  ```bash\",\n    \"  git checkout {{repository.defaultBranch}}\",\n    \"  git pull origin {{repository.defaultBranch}}\",\n    \"  git fetch --prune origin\",\n    \"  git branch -d <branch-name> 2>/dev/null || git branch -D <branch-name> 2>/dev/null || true\",\n    \"  ```\",\n    \"\",\n    \"  **Post-merge closure verification.** Iterate the **full linked-issue\",\n    \"  set** from Phase 1.5 — the union of the `CLOSES` and `STRANDED`\",\n    \"  numbers `check-closing-keywords.sh` reported — not just the primary\",\n    \"  issue. This loop is the structural guard against the stranded-issue\",\n    \"  defect class: GitHub honours only one issue reference per closing\",\n    \"  keyword, so a body written as `Closes #A, #B` closes `#A` and leaves\",\n    \"  `#B` open forever with no signal anywhere. Because the reviewer\",\n    \"  already knows the full set, every survivor is closed here\",\n    \"  deterministically instead of being discovered months later by an\",\n    \"  audit.\",\n    \"\",\n    \"  For **each** issue in the set, in order:\",\n    \"\",\n    \"  1. Transition it to `status:done` (replaces whichever of\",\n    \"     `status:ready-for-review` or `status:in-progress` it was carrying):\",\n    \"  ```bash\",\n    \"  gh issue edit <issue-number> \\\\\",\n    '    --remove-label \"status:ready-for-review\" \\\\',\n    '    --remove-label \"status:in-progress\" \\\\',\n    '    --add-label \"status:done\"',\n    \"  ```\",\n    \"  2. Check its state:\",\n    \"  ```bash\",\n    \"  gh issue view <issue-number> --json state --jq '.state'\",\n    \"  ```\",\n    \"  3. If the issue is **not** `CLOSED`, close it explicitly (this covers\",\n    \"     both a missing closing keyword and an issue stranded by a\",\n    \"     multi-issue keyword):\",\n    \"  ```bash\",\n    \"  gh issue close <issue-number> --reason completed\",\n    \"  gh issue comment <issue-number> --body 'PR #<pr-number> merged. Closing issue.'\",\n    \"  ```\",\n    \"  4. Once `status:done` is applied (either via the edit above or the\",\n    \"     explicit close path), run the targeted unblock sweep so any\",\n    \"     dependents waiting on this issue flip from `status:blocked` to\",\n    \"     `status:ready` immediately:\",\n    \"  ```bash\",\n    \"  .claude/procedures/unblock-dependents.sh <issue-number>\",\n    \"  ```\",\n    \"\",\n    \"  Log the sweep's output (one line per processed dependent:\",\n    \"  `UNBLOCKED #<n>` / `STILL_BLOCKED #<n>` / `NO_DEPENDENTS #<m>`)\",\n    \"  in the PR review summary. See the **Agent-driven unblocking**\",\n    \"  section in `CLAUDE.md` for the full contract.\",\n    \"\",\n    \"  Report one `Issue #<n>: <closed-by-github | closed-explicitly>` line\",\n    \"  per member of the set. Any issue that needed the explicit close was\",\n    \"  stranded by the PR body — say so in the summary so the authoring\",\n    \"  defect is visible, not just repaired.\",\n    \"- **`CLOSED` (not merged)** — leave the branch in place; report the closure.\",\n    \"- **Still `OPEN`** — auto-merge is pending; report and stop without deleting.\",\n    \"\",\n    \"---\",\n    \"\",\n    \"## Output Format\",\n    \"\",\n    \"Return a structured report:\",\n    \"\",\n    \"```\",\n    \"PR #<number> — <title>\",\n    \"Linked issue: #<issue-number>\",\n    \"Linked issue set: #<n> [, #<n>…]   (from check-closing-keywords.sh)\",\n    \"Closing keywords: <ok | malformed: strands #<n>[, #<n>…]>\",\n    \"Review mode: <auto-merge | human-required>\",\n    \"Reason: <short explanation from Phase 2.75>\",\n    \"Verdict: AUTO_MERGE_ENABLED | AWAITING_HUMAN | DELEGATED_TO_WORKER | NEEDS_CHANGES | INELIGIBLE | BLOCKED\",\n    \"\",\n    \"Acceptance criteria:\",\n    \"  [x] <criterion> — <evidence>\",\n    \"  [~] <criterion> — partial: <gap>\",\n    \"  [ ] <criterion> — missing\",\n    \"\",\n    \"Findings:\",\n    \"  - Blocking: <items>\",\n    \"  - Suggested: <items>\",\n    \"  - Nitpick: <items>\",\n    \"\",\n    \"Action taken: <enable-auto-merge | label-awaiting-human | delegated-to-worker | confirmed-delegation | commented-on-the-pr | none>\",\n    \"Branch updated: <yes | not needed | failed (<reason>) | delegated (PR #<n>) | n/a>\",\n    \"Branch state: <merged | open | closed>\",\n    \"Issue state: <closed | open>\",\n    \"```\",\n    \"\",\n    \"**`DELEGATED_TO_WORKER` semantics.** This verdict means the reviewer\",\n    \"posted a fix-list, applied the `review:needs-worker` marker, and\",\n    \"exited holding the `review:fixing` lease — the fix-list is **durably\",\n    \"queued** for a top-level `issue-worker` pass, but it has **not** yet\",\n    \"been applied in this pass. `delegated` is never a terminal\",\n    \"completion: the loop closes only when a top-level worker consumes the\",\n    \"marker and a later reviewer confirm pass releases the lease. Likewise\",\n    \"`Branch updated: delegated (PR #<n>)` records that a conflict\",\n    \"resolution was queued for the worker, not that the branch is already\",\n    \"current.\",\n    \"\",\n    \"---\",\n    \"\",\n    \"## Rules\",\n    \"\",\n    \"1. **One PR per session** when invoked directly (`/review-pr`). When\",\n    \"   invoked from the multi-PR loop (`/review-prs`), process every eligible\",\n    \"   PR in turn.\",\n    \"2. **Never merge without a linked issue.** If the PR body has no\",\n    \"   `Closes #N` / `Fixes #N` / `Resolves #N`, comment and stop.\",\n    \"2a. **Never merge without verifying every linked issue closes.** Resolve\",\n    \"    the linked-issue set with\",\n    \"    `.claude/procedures/check-closing-keywords.sh <pr-number>`, never by\",\n    \"    eyeballing the body. GitHub honours only one issue reference per\",\n    \"    closing keyword, so a `STRANDED` line means that issue will stay\",\n    \"    open after the merge unless Phase 5 closes it. Phase 5 must iterate\",\n    \"    the **whole** set — `CLOSES` plus `STRANDED` — and explicitly close\",\n    \"    every issue GitHub left open.\",\n    \"3. **Never merge with failing CI.** Even if every criterion is met,\",\n    \"   block on red checks. Resolve CI status via the **CI\",\n    \"   Verification** section: read check-runs first, and only on a\",\n    \"   fine-grained-PAT 403 (or an empty rollup) fall back to the\",\n    \"   Actions runs API. A 403 is a visibility failure, **never** a\",\n    \"   passing check — do not treat an unreadable check as green.\",\n    \"4. **Never bypass review conventions.** Always use `--squash`, `--auto`,\",\n    \"   and `--delete-branch` for merges. Do not force-merge.\",\n    \"5. **Never auto-merge a `human-required` PR.** When Phase 2.75 resolves\",\n    \"   to `human-required`, Phase 4 applies `review:awaiting-human` and\",\n    \"   exits. Even if every acceptance criterion is met and CI is green,\",\n    \"   `gh pr merge --auto` is forbidden in that mode.\",\n    `6. **Never push commits to the PR's branch yourself.** The reviewer is a decision-maker and orchestrator, not an implementer. When in-scope review comments require code changes **and** the PR carries ${DELEGATION_ELIGIBLE_ORIGIN_PHRASE} (or the invocation prompt explicitly allows human-authored PRs via \\`--allow-human-author\\`), delegate the fix **by marker, not by spawn**: post a fix-list comment on the PR, apply the \\`review:needs-worker\\` label, hold the \\`review:fixing\\` lease, and exit returning \\`delegated\\`. Do **not** invoke \\`issue-worker\\` via the \\`Agent\\` tool — the reviewer often runs at depth-1 where nested sub-agent spawning is forbidden, so an in-session dispatch would silently abort. A top-level \\`issue-worker\\` session pulls the marker and applies the fix; a later reviewer confirm pass releases the lease. You must never call \\`git commit\\`, \\`git push\\`, \\`git rebase\\`, or \\`gh pr edit\\` against the head branch from this agent — all branch mutations belong to \\`issue-worker\\`.`,\n    \"7. **Do not implement code.** You review, decide, and orchestrate. If\",\n    \"   the PR needs code changes and delegation is not permitted by Rule\",\n    \"   #6, comment and stop — do not attempt to fix it yourself.\",\n    \"8. **In loop mode (`/review-prs`), never stop early.** If any review\",\n    \"   fails, comment and move to the next PR. Only abort the loop on a\",\n    \"   fatal error (e.g. `gh` auth failure, network outage).\",\n    \"9. **Follow CLAUDE.md conventions** for all `git` and `gh` operations.\",\n    \"10. **Follow the reaction protocol.** Use `eyes` to mark a comment\",\n    \"    seen, `thinking_face` (`confused`) to dispute it, `+1` to accept\",\n    \"    its request, `rocket` when the accepted change has landed, and\",\n    \"    `-1` when the request is out-of-scope and has been tracked in a\",\n    \"    new issue. Apply reactions on the same comment endpoint the\",\n    \"    comment came from (`issues/comments/...` for PR-level, \",\n    \"    `pulls/comments/...` for inline).\",\n    \"11. **Terminal reactions require completed actions.** `+1`, `rocket`,\",\n    \"    and `-1` must only be applied once the corresponding action is\",\n    \"    truly complete (respectively: the fix accepted, the fix landed,\",\n    \"    or the new out-of-scope issue created and linked in a reply).\",\n    \"    Never apply a terminal reaction pre-emptively; doing so falsely\",\n    \"    signals to humans and to future reviewer passes that the item\",\n    \"    is closed.\",\n    \"12. **Maintain one sticky `## Reviewer notes` comment per PR.** On\",\n    \"    each pass, find the existing sticky comment authored by the\",\n    \"    reviewer and edit it in place with `gh api ... -X PATCH`;\",\n    \"    create it only when none exists. Never post per-pass summary\",\n    \"    comments alongside the sticky — the sticky is the single\",\n    \"    human-facing source of truth for PR state.\",\n    \"13. **Pushback blocks auto-merge.** Any unresolved `thinking_face`\",\n    \"    reaction authored by the reviewer on any comment must prevent\",\n    \"    Phase 4 from enabling auto-merge, regardless of the review mode\",\n    \"    decided in Phase 2.75. The gate clears only when the human has\",\n    \"    resolved the dispute — by withdrawing the comment, by replying\",\n    \"    in a way that satisfies the reviewer (who then replaces the\",\n    \"    `thinking_face` with `+1`), or by applying the `review:auto-ok`\",\n    \"    label as an explicit override.\",\n    \"14. **Never re-enable auto-merge while disputes, human-required\",\n    \"    hand-offs, or an in-flight delegation are still pending.** The\",\n    \"    auto-merge re-enable happens on the **confirm pass** (the Shared\",\n    \"    Procedure: Confirm a Completed Delegation), never on the pass\",\n    \"    that posts the fix-list. A confirm pass may only run\",\n    \"    `gh pr merge --auto` when the PR carries `review:fixing` but\",\n    \"    **not** `review:needs-worker` (the worker finished and cleared\",\n    \"    its marker), **and** **no** unresolved `thinking_face` reactions\",\n    \"    authored by the reviewer remain on any PR comment, **and** the\",\n    \"    `review:awaiting-human` label is **not** present. While\",\n    \"    `review:needs-worker` is still applied the delegation is\",\n    \"    unconsumed and auto-merge stays disabled. Any AC-drift pushback,\",\n    \"    any failed-fix pushback, and any human-required hand-off all keep\",\n    \"    auto-merge disabled until the human resolves the underlying\",\n    \"    state.\",\n    \"15. **Restrict `gh pr update-branch` on `human-required` PRs.** The\",\n    \"    `update-branch` step is permitted when the review mode is\",\n    \"    `auto-merge`, **or** when the mode is `human-required` **and**\",\n    \"    Phase 2.75's `matched_rule == 6` (size threshold was the sole\",\n    \"    trigger). All other human-required matches (rule 2 force-human\",\n    \"    label, rule 3 listed force-human label, rule 4 path glob, rule 5\",\n    \"    issue type) continue to block `update-branch`: pushing main into\",\n    \"    those PRs expands the diff under review without the human\",\n    \"    reviewer's consent. The same restriction applies to delegating\",\n    \"    conflict resolution to `issue-worker`: never delegate a\",\n    \"    conflict resolution on a `human-required` PR regardless of\",\n    \"    `matched_rule` — the typed-recipe delegation flow stays\",\n    \"    auto-merge-only because a worker's merge injects reconciled\",\n    \"    content into a human-required branch, expanding the reviewed\",\n    \"    diff more than the clean merge-commit `gh pr update-branch`\",\n    \"    performs.\",\n    \"16. **Never delegate conflict resolution involving generated or\",\n    \"    projen-managed files.** When `gh pr update-branch` fails on a\",\n    \"    BEHIND PR with conflicts and any conflicting path is a lockfile,\",\n    \"    a `**/.projen/**` file, or a file marked\",\n    \"    `~~ Generated by projen` / `// Generated by`, the reviewer must\",\n    \"    skip the `issue-worker` delegation and fall back to the comment\",\n    \"    pathway. Mechanical merge of generated content is unsafe — those\",\n    \"    files are derived from `.projenrc.ts` and must be regenerated,\",\n    \"    not merged.\",\n  ].join(\"\\n\"),\n};\n\n/*******************************************************************************\n *\n * /review-pr skill — user-invocable entry point for a single PR.\n *\n ******************************************************************************/\n\nconst reviewPrSkill: AgentSkill = {\n  name: \"review-pr\",\n  description:\n    \"Review a single pull request against its linked issue's acceptance criteria, then enable squash auto-merge or comment with findings\",\n  disableModelInvocation: true,\n  userInvocable: true,\n  context: \"fork\",\n  agent: \"pr-reviewer\",\n  platforms: { cursor: { exclude: true } },\n  instructions: [\n    \"# Review Pull Request\",\n    \"\",\n    \"Run a full PR review against the linked issue's acceptance criteria,\",\n    \"then either enable squash auto-merge or post a findings comment.\",\n    \"\",\n    \"## Usage\",\n    \"\",\n    \"/review-pr <pr-number> [--allow-human-author]\",\n    \"\",\n    \"### Flags\",\n    \"\",\n    \"- **`--allow-human-author`** — opt the reviewer into processing\",\n    \"  human-authored PRs for **this invocation only**. By default, the\",\n    \"  reviewer only processes bot-authored PRs (those carrying\",\n    `  ${DELEGATION_ELIGIBLE_ORIGIN_LIST}); pass this flag to review a`,\n    \"  human-authored PR. The flag does not persist — subsequent\",\n    \"  invocations return to the bot-only default.\",\n    \"\",\n    \"## What This Skill Does\",\n    \"\",\n    \"1. Runs a pre-flight eligibility filter (mergeable, CI not failing, has linked issue)\",\n    \"2. Fetches the PR, its diff, CI status, and the linked issue\",\n    \"3. Builds a checklist from the issue's acceptance criteria\",\n    \"4. Compares the diff against each criterion\",\n    \"5. Verifies PR conventions (title, closing keyword, branch name)\",\n    \"6. Verifies CI is green\",\n    \"7. **If all checks pass:** enables squash auto-merge (with `--delete-branch`)\",\n    \"8. **If any check fails:** posts a findings comment via `gh pr comment`\",\n    \"9. After merge, verifies the linked issue is closed and closes it if not\",\n    \"10. Cleans up the local branch after merge\",\n    \"\",\n    \"Passing `--allow-human-author` opts the reviewer into processing\",\n    \"human-authored PRs for this invocation only (the default scope is\",\n    `bot-authored PRs carrying ${DELEGATION_ELIGIBLE_ORIGIN_LIST}).`,\n    \"\",\n    \"## Input\",\n    \"\",\n    \"Provide the PR number to review. The skill resolves the linked issue from\",\n    \"the PR body (`Closes #N` / `Fixes #N` / `Resolves #N`).\",\n    \"\",\n    \"## Output\",\n    \"\",\n    \"A structured report covering verdict, per-criterion status, findings\",\n    \"grouped by severity, the action taken, and the final branch / issue state.\",\n    \"\",\n    \"## Composability\",\n    \"\",\n    \"This skill is generic and can be composed with the `github-workflow`\",\n    \"bundle. The reviewer never implements code and never pushes to the PR\",\n    \"branch — it only reviews, decides, and orchestrates merge or comment.\",\n  ].join(\"\\n\"),\n};\n\n/*******************************************************************************\n *\n * /review-prs skill — loops over every eligible open PR in the repo.\n *\n ******************************************************************************/\n\nconst reviewPrsSkill: AgentSkill = {\n  name: \"review-prs\",\n  description:\n    \"Loop over every eligible open pull request in the repository and review each one through the full pipeline\",\n  disableModelInvocation: true,\n  userInvocable: true,\n  context: \"fork\",\n  agent: \"pr-reviewer\",\n  platforms: { cursor: { exclude: true } },\n  instructions: [\n    \"# Review All Eligible Pull Requests\",\n    \"\",\n    \"Run the pr-reviewer pipeline over every eligible open PR in\",\n    \"**{{repository.owner}}/{{repository.name}}**, one after another, until\",\n    \"the eligible queue is empty.\",\n    \"\",\n    \"## Usage\",\n    \"\",\n    \"/review-prs [--allow-human-author]\",\n    \"\",\n    \"### Flags\",\n    \"\",\n    \"- **`--allow-human-author`** — opt the reviewer into processing\",\n    \"  human-authored PRs for **this invocation only**. By default, the\",\n    \"  loop only processes bot-authored PRs (those carrying\",\n    `  ${DELEGATION_ELIGIBLE_ORIGIN_LIST}); pass this flag to include`,\n    \"  human-authored PRs in the queue. The flag does not persist —\",\n    \"  subsequent invocations return to the bot-only default.\",\n    \"\",\n    \"## What This Skill Does\",\n    \"\",\n    \"### Step 1: Enumerate open PRs\",\n    \"\",\n    \"```bash\",\n    \"gh pr list --json number,title,body,headRefName,mergeable,mergeStateStatus,statusCheckRollup --limit 50\",\n    \"```\",\n    \"\",\n    \"### Step 2: Filter to eligible PRs\",\n    \"\",\n    \"A PR is **eligible** when all of the following hold:\",\n    \"\",\n    '1. `state == \"OPEN\"` (implicit from `gh pr list`).',\n    '2. `mergeable == \"MERGEABLE\"` (no conflicts).',\n    \"3. No required check in `statusCheckRollup` has a failing conclusion\",\n    \"   (`FAILURE`, `TIMED_OUT`, `CANCELLED`, `ERROR`). CI green or still\",\n    \"   pending is fine. When `statusCheckRollup` is empty or denied with\",\n    \"   a fine-grained-PAT 403, keep the PR in the queue — the per-PR\",\n    \"   pipeline resolves CI authoritatively via the reviewer's CI\",\n    \"   Verification Actions-runs fallback.\",\n    \"4. The PR body contains a linked issue (`Closes #N` / `Fixes #N` /\",\n    \"   `Resolves #N`, case-insensitive).\",\n    \"\",\n    \"Drop any PR that fails the filter from the queue. Do not comment on\",\n    \"them from this skill — the individual `/review-pr` invocation handles\",\n    \"the inline rejection comment when run on a specific PR.\",\n    \"\",\n    \"### Step 3: Process each eligible PR\",\n    \"\",\n    \"For every eligible PR, invoke the full pr-reviewer pipeline\",\n    \"(Phases 1 through 5) as if `/review-pr <number>` had been called\",\n    \"directly:\",\n    \"\",\n    \"- Gather context (diff, checks, linked issue)\",\n    \"- Compare diff to acceptance criteria\",\n    \"- Decide and act (enable auto-merge **or** post findings comment)\",\n    \"- Verify branch / issue cleanup after merge\",\n    \"\",\n    \"Continue to the next PR after each one completes. Never stop the loop\",\n    \"early because a single PR's review failed — comment and move on.\",\n    \"\",\n    \"### Step 4: Stop when the queue is empty\",\n    \"\",\n    \"When no eligible PRs remain, emit a final summary listing every PR\",\n    \"processed and the verdict for each, then stop.\",\n    \"\",\n    \"Passing `--allow-human-author` opts the reviewer into including\",\n    \"human-authored PRs in the queue for this invocation only (the default\",\n    `scope is bot-authored PRs carrying ${DELEGATION_ELIGIBLE_ORIGIN_LIST}).`,\n    \"\",\n    \"## Output\",\n    \"\",\n    \"Per-PR structured report (same shape as `/review-pr`), followed by a\",\n    \"one-line-per-PR summary at the end:\",\n    \"\",\n    \"```\",\n    \"Summary:\",\n    \"  PR #<n>: <verdict>\",\n    \"  PR #<n>: <verdict>\",\n    \"  ...\",\n    \"Total processed: <count>\",\n    \"```\",\n    \"\",\n    \"## Failure Handling\",\n    \"\",\n    \"Only abort the loop on a fatal error (e.g. `gh` authentication failure,\",\n    \"network outage). A failed review for an individual PR is not fatal —\",\n    \"comment on that PR and continue with the next.\",\n  ].join(\"\\n\"),\n};\n\n/*******************************************************************************\n *\n * Bundle definition — opt-in. Consumers must include via `includeBundles`\n * (or it auto-detects through the appliesWhen below). No hardcoded\n * domain-specific content.\n *\n ******************************************************************************/\n\n/**\n * Build the `pr-review` bundle with the supplied (possibly absent)\n * PR review policy override.\n *\n * The bundle is mostly static — the agent prompt, the feedback-\n * protocol prose, the skills, the sub-agent, and the labels are all\n * fixed across consumers. The one dynamic surface is the rendered\n * `pr-review-policy` rule's YAML block and precedence walk, which\n * reflect the resolved `pathsExemptFromSize` carve-out so consumers\n * tuning the doc-only carve-out see their override land in the\n * rendered CLAUDE.md.\n *\n * When `policy` is omitted, the bundle ships with the documented\n * defaults baked in (`pathsExemptFromSize: [\"docs/**\"]`).\n */\nexport function buildPrReviewBundle(\n  policy: ResolvedPrReviewPolicy = resolvePrReviewPolicy(),\n): AgentRuleBundle {\n  return {\n    name: \"pr-review\",\n    description:\n      \"Pull request review workflow: verifies PRs against their linked issues' acceptance criteria and orchestrates squash-merge, single or looped over all eligible PRs\",\n\n    // Default-apply: the PR review workflow is safe to include everywhere,\n    // and keeping review/merge policy centralised in the pr-reviewer agent\n    // means consumers get consistent behaviour out of the box. Consumers can\n    // still exclude it explicitly via `excludeBundles` if desired.\n    appliesWhen: () => true,\n\n    rules: [\n      {\n        name: \"pr-review-policy\",\n        description:\n          \"Declarative policy that tells the pr-reviewer which PRs may auto-merge and which must wait for a human reviewer\",\n        scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n        // Bundle defaults exclude paths into configulator's own source\n        // (only meaningful when configulator is a workspace package).\n        // codedrifters/packages restores them via\n        // `agentConfig.additionalRulePaths`.\n        filePatterns: [\n          \".claude/agents/pr-reviewer.md\",\n          \".claude/skills/review-pr/**\",\n          // The operator skill quotes the policy's CI-verification\n          // contract verbatim; loading the policy when it is edited\n          // keeps the two from drifting.\n          \".claude/skills/babysit-prs/**\",\n        ],\n        content: [\n          \"# PR Review Policy\",\n          \"\",\n          \"The `pr-reviewer` sub-agent evaluates every PR it reviews against the\",\n          \"policy below and routes the PR into one of two modes:\",\n          \"\",\n          \"- **`auto-merge`** — the reviewer may enable squash auto-merge once\",\n          \"  all acceptance criteria are met and CI is green.\",\n          \"- **`human-required`** — the reviewer runs the full AC/CI check but\",\n          \"  never calls `gh pr merge --auto`. It applies the\",\n          \"  `review:awaiting-human` label and hands off to a human reviewer.\",\n          \"\",\n          \"## Policy\",\n          \"\",\n          \"```yaml\",\n          \"version: 1\",\n          \"default: auto-merge\",\n          \"\",\n          \"human-required:\",\n          \"  paths:\",\n          '    - \"docs/src/content/docs/project-context.md\"',\n          '    - \".github/workflows/**\"',\n          '    - \".github/CODEOWNERS\"',\n          '    - \".projenrc.ts\"',\n          '    - \"projenrc/**\"',\n          '    - \"CLAUDE.md\"',\n          '    - \".claude/**\"',\n          '    - \"packages/**/package.json\"',\n          \"  issue-types:\",\n          \"    - release\",\n          \"    - hotfix\",\n          \"  size:\",\n          \"    files: 10\",\n          \"    insertions: 500\",\n          \"  labels-that-force-human:\",\n          '    - \"review:human-required\"',\n          \"\",\n          \"auto-merge:\",\n          \"  labels-that-force-auto:\",\n          '    - \"review:auto-ok\"',\n          \"  paths-exempt-from-size:\",\n          ...renderPathsExemptFromSizeYaml(\n            policy.autoMerge.pathsExemptFromSize,\n          ),\n          \"\",\n          \"ci-verification:\",\n          \"  required-workflows:\",\n          ...renderRequiredWorkflowsYaml(\n            policy.ciVerification.requiredWorkflows,\n          ),\n          \"```\",\n          \"\",\n          \"## Precedence\",\n          \"\",\n          \"The reviewer walks the following checks in order. The **first match**\",\n          \"fixes the mode; any mixed-match PR (signals from both sides) resolves\",\n          \"conservatively to `human-required` — `auto-merge` only wins when the\",\n          \"force-auto label is the single top-priority match.\",\n          \"\",\n          \"1. **`auto-merge.labels-that-force-auto`** — if the PR carries any of\",\n          \"   these labels (e.g. `review:auto-ok`), the mode is `auto-merge`\",\n          \"   outright. This is the only escape hatch from the conservative\",\n          \"   default; it requires a maintainer to apply the label explicitly.\",\n          \"2. **`review:human-required` label** — reserved force-human label;\",\n          \"   if present (and no force-auto label beat it in step 1), the mode\",\n          \"   is `human-required`.\",\n          \"3. **`human-required.labels-that-force-human`** — if the PR\",\n          \"   carries any label listed here (e.g. `review:human-required`),\",\n          \"   the mode is `human-required`.\",\n          \"4. **`human-required.paths`** — if any file in the PR diff matches\",\n          \"   any glob here, the mode is `human-required`. Matching uses\",\n          \"   standard glob semantics (`**` for recursive directories,\",\n          \"   `*` for a single path segment).\",\n          \"5. **`human-required.issue-types`** — if the linked issue's GitHub\",\n          \"   issue type matches any entry (case-insensitive), the mode is\",\n          \"   `human-required`.\",\n          \"6. **`human-required.size`** — first read\",\n          \"   `auto-merge.paths-exempt-from-size` from the policy block above.\",\n          \"   For every file in the PR diff, evaluate whether the file path\",\n          \"   matches at least one glob in that carve-out list. If **every**\",\n          \"   changed path matches the carve-out, **skip rule #6** entirely\",\n          \"   and continue to rule #7 — the PR is exempt from the size\",\n          \"   threshold regardless of its `files` or `insertions` count.\",\n          \"   Otherwise (any changed path falls outside the carve-out list),\",\n          \"   apply the size check: if the PR exceeds either the `files`\",\n          \"   count or the `insertions` count, the mode is `human-required`.\",\n          \"7. **`default`** — applied only when no rule above matched\",\n          \"   (normally `auto-merge`).\",\n          \"\",\n          \"**Label-check scope.** All label checks in rules 1–3 evaluate\",\n          \"the PR's **own** labels only. Never traverse the `Closes #N`\",\n          \"link to read the linked issue's labels for a label rule. Rule 5\",\n          \"is the only rule that reads the linked issue, and it reads the\",\n          \"issue **type**, not its labels.\",\n          \"\",\n          \"**`priority:*` / `status:*` are not merge-risk signals.**\",\n          \"`priority:*` and `status:*` are issue-triage labels consumed by\",\n          \"the orchestrator for scheduling — `priority:*` sequences the\",\n          \"work queue and `status:*` tracks workflow position. They say\",\n          \"nothing about a PR's merge risk and must never appear in any\",\n          \"`labels-that-force-*` list. Gating merge on `priority:critical`\",\n          \"in particular inverts the intended behaviour: the most urgent\",\n          \"work would wait the longest for a human merge. Merge risk is\",\n          \"already covered by the path globs (rule 4), the\",\n          \"`release` / `hotfix` issue-types (rule 5), and the size\",\n          \"thresholds (rule 6).\",\n          \"\",\n          \"The `auto-merge.paths-exempt-from-size` carve-out exists so\",\n          \"**doc-only PRs** that routinely exceed the 500-insertion size\",\n          \"threshold (large migrations, bulk additions, refresh passes)\",\n          \"are not forced into `human-required` mode for a reason that does\",\n          \"not reflect production risk. The default carve-out exempts the\",\n          \"entire `docs/**` tree — every consumer of configulator places its\",\n          \"Starlight docs site there. A PR mixing docs and code still falls\",\n          \"into `human-required` at rule #6 because the non-docs path fails\",\n          \"the carve-out check, so the rule only relaxes the threshold for\",\n          \"PRs whose **every** changed path is doc-only.\",\n          \"\",\n          \"### ADRs auto-merge as `Proposed`\",\n          \"\",\n          \"Architectural Decision Records (under\",\n          \"`docs/src/content/docs/requirements/architectural-decisions/**`)\",\n          \"are **not** a `human-required.paths` trigger. An ADR-only PR with\",\n          \"green CI and met acceptance criteria resolves to `auto-merge` and\",\n          \"squash-merges with no `review:awaiting-human` and no human action.\",\n          \"\",\n          \"Auto-merging an ADR does **not** ratify the decision it records.\",\n          \"An ADR is authored in `Proposed` status, and merging it simply\",\n          \"lands the proposal in the docs tree as written — its status stays\",\n          \"`Proposed`. Promotion `Proposed` → `Accepted` is a separate\",\n          \"human / governance step performed out of band by a\",\n          \"decision-maker; it is **not** a merge gate and nothing in the\",\n          \"review loop flips an ADR to `Accepted`. Routing ADRs to\",\n          \"`human-required` only piled them up at `review:awaiting-human`\",\n          \"waiting for a merge decision that was never the human's job —\",\n          \"the human's job is the later acceptance decision, not the merge.\",\n          \"\",\n          \"The `requirements-writer` flow already authors ADRs in\",\n          \"`Proposed` status (its Decision section reads\",\n          '\"Pending human review\"), so the merged-as-`Proposed` terminal',\n          \"state is supplied by the author, not enforced at the merge gate.\",\n          \"Consumers that genuinely need a human to gate ADR *merges* (not\",\n          \"just acceptance) cannot re-add the glob via policy config — the\",\n          \"`human-required.paths` list is not consumer-configurable today;\",\n          \"they would apply the `review:human-required` label per-PR or\",\n          \"fork the bundle.\",\n          \"\",\n          \"The `pr-reviewer` sub-agent records the decided mode, the\",\n          \"triggering reason, and the numeric **matched-rule index** (2–6\",\n          \"for human-required matches; `null` for rule 1 force-auto or\",\n          \"rule 7 default) in its Phase 2.75 output. Downstream phases and\",\n          \"the sticky summary cite the specific rule that applied.\",\n          \"\",\n          \"### Rule-#6 carve-out for `gh pr update-branch`\",\n          \"\",\n          \"The reviewer's BEHIND-branch refresh step (`gh pr update-branch`)\",\n          \"is normally restricted to `auto-merge` PRs because pushing the\",\n          \"default branch into a `human-required` PR expands the diff the\",\n          \"human is reviewing without their consent. A narrow exception\",\n          \"applies when rule #6 (size threshold) is the **sole** trigger\",\n          \"for `human-required` mode: the bot may still run `gh pr\",\n          \"update-branch` so a code-heavy size-tripped PR does not sit\",\n          \"BEHIND while the human drafts their review.\",\n          \"\",\n          \"The exception is keyed on the matched-rule index recorded in\",\n          \"Phase 2.75. All other `human-required` triggers — rule 2\",\n          \"(`review:human-required` label), rule 3 (any\",\n          \"`labels-that-force-human` label), rule 4\",\n          \"(`human-required.paths` glob match), and rule 5\",\n          \"(`human-required.issue-types` match) — continue to block\",\n          \"`update-branch` because each one signals a human reviewer who\",\n          \"has explicit ownership of the branch's lifecycle.\",\n          \"\",\n          \"This carve-out is largely belt-and-suspenders given the doc-only\",\n          \"size carve-out above. Doc-only PRs that trip rule #6 now route\",\n          \"directly to `auto-merge`, so the rule-#6 `update-branch` carve-\",\n          \"out only kicks in for **code-heavy** PRs that legitimately trip\",\n          \"rule #6 (mixed-content diffs whose non-doc paths fail the\",\n          \"`paths-exempt-from-size` check, or consumers that disable the\",\n          \"doc-only carve-out entirely).\",\n          \"\",\n          \"## CI Verification\",\n          \"\",\n          \"Before enabling auto-merge the reviewer confirms CI is green.\",\n          \"The **primary** read is the GitHub check-runs rollup\",\n          \"(`gh pr checks` / `statusCheckRollup`) — the same source\",\n          \"GitHub uses for branch protection, covering **every** check\",\n          \"context (Actions, third-party CI, GitHub Apps, commit\",\n          \"statuses). It stays primary for every consumer because it is\",\n          \"strictly more complete than the Actions-only fallback below.\",\n          \"\",\n          \"### Fine-grained-PAT fallback to the Actions runs API\",\n          \"\",\n          \"When the reviewer authenticates with a **fine-grained personal\",\n          \"access token**, the check-runs read returns\",\n          \"`HTTP 403: Resource not accessible by personal access token`.\",\n          \"This is not grantable away: GitHub exposes **no `Checks`\",\n          \"permission for fine-grained tokens** (it is GitHub-App-only),\",\n          \"so the token permission picker has no entry to add. On that\",\n          \"specific 403 (or when the rollup returns no readable contexts\",\n          \"at all), the reviewer falls back to the **Actions runs API**:\",\n          \"\",\n          \"```\",\n          \"GET /repos/{owner}/{repo}/actions/runs?head_sha={head_sha}&per_page=100\",\n          \"```\",\n          \"\",\n          \"which a fine-grained PAT with `Actions: Read-only` **can**\",\n          \"read. Auto-merge is then gated on the required workflows'\",\n          \"latest run per workflow name concluding `success`\",\n          \"(`skipped` / `neutral` are non-blocking; `failure` /\",\n          \"`cancelled` / `timed_out` / `action_required` block; a run\",\n          \"still `in_progress` / `queued`, or a required workflow with no\",\n          \"run at all, counts as not-yet-green). The 403 is detected\",\n          \"explicitly and is **never** treated as a passing check — it is\",\n          \"a visibility failure, not a green signal.\",\n          \"\",\n          \"The fallback fires **only** when the primary check-runs read\",\n          \"is denied, so GitHub-App and classic-PAT consumers (which can\",\n          \"read check-runs) are unaffected and keep the complete view.\",\n          \"The fallback only sees GitHub Actions runs; a consumer whose\",\n          \"CI includes a non-Actions required check cannot verify it on a\",\n          \"fine-grained PAT and must move the reviewer to a GitHub App /\",\n          \"classic PAT to regain the complete check-runs view.\",\n          \"\",\n          \"### Configuring required workflows\",\n          \"\",\n          \"The `ci-verification.required-workflows` list in the policy\",\n          \"YAML names the workflows the fallback gates on:\",\n          \"\",\n          \"- **Non-empty list** — gate only on those workflow `name`s.\",\n          \"  A listed workflow with no run for the head SHA is treated as\",\n          \"  not-yet-green (pending), never green.\",\n          \"- **Empty list (the default)** — treat **every** workflow run\",\n          \"  observed for the head SHA as required. This is the\",\n          \"  conservative zero-config default so an unknown failing\",\n          \"  workflow blocks rather than slips through.\",\n          \"\",\n          \"Consumers tune the list via\",\n          \"`agentConfig.prReviewPolicy.ciVerification.requiredWorkflows`.\",\n          \"The list governs **only** the fallback path; the primary\",\n          'check-runs read derives \"required\" from branch protection',\n          \"directly.\",\n        ].join(\"\\n\"),\n        tags: [\"policy\", \"review\"],\n      },\n      {\n        name: \"pr-review-workflow\",\n        description:\n          \"Describes the /review-pr and /review-prs skills and their delegation to the pr-reviewer sub-agent\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# PR Review Workflow\",\n          \"\",\n          \"Two skills are available, both backed by the same `pr-reviewer`\",\n          \"sub-agent:\",\n          \"\",\n          \"- **`/review-pr <pr-number>`** — review a single targeted PR.\",\n          \"- **`/review-prs`** — loop over every eligible open PR in the\",\n          \"  repository and review each one in turn.\",\n          \"\",\n          \"The `pr-reviewer` sub-agent:\",\n          \"\",\n          \"1. Runs a pre-flight eligibility filter (mergeable, CI not failing,\",\n          \"   has a linked issue). Ineligible PRs get a short comment and are\",\n          \"   skipped.\",\n          \"2. Fetches the PR, its diff, CI status, and the linked issue\",\n          \"3. **Evaluates the PR Review Policy** (see the `PR Review Policy`\",\n          \"   section above) to decide whether the PR is `auto-merge` or\",\n          \"   `human-required`, and records the triggering reason\",\n          \"4. Builds a checklist from the issue's acceptance criteria\",\n          \"5. Verifies the diff satisfies each criterion and that CI is green\",\n          \"6. **Enables squash auto-merge** (with `--delete-branch`) when all\",\n          \"   checks pass **and** the review mode is `auto-merge`\",\n          \"7. **Applies `review:awaiting-human`** and hands off to a human\",\n          \"   reviewer when the review mode is `human-required` (no auto-merge,\",\n          \"   even if every acceptance criterion is met)\",\n          \"8. **Comments with grouped findings** when any check fails (plain\",\n          \"   `gh pr comment`, not a formal `--request-changes` review)\",\n          \"9. After a successful merge, verifies the linked issue is closed\",\n          \"   and closes it explicitly if the merge commit did not\",\n          \"10. Cleans up the local branch after merge\",\n          \"\",\n          \"The reviewer **never** implements code and **never** pushes commits\",\n          \"to a PR's branch — it only reviews, decides, and orchestrates merge\",\n          \"or comment. In loop mode, a failed review for one PR never stops\",\n          \"the loop; the reviewer comments and moves on. See the `pr-reviewer`\",\n          \"agent definition for the full phase-by-phase contract.\",\n        ].join(\"\\n\"),\n        platforms: {\n          cursor: { exclude: true },\n        },\n        tags: [\"workflow\"],\n      },\n      {\n        name: \"pr-review-feedback-protocol\",\n        description:\n          \"Documents the human-in-the-loop feedback loop on PR review: reaction state machine, pushback resolution, fix-list comment format, sticky reviewer-notes comment, label glossary, and human-author opt-in flag.\",\n        scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n        // Bundle defaults exclude paths into configulator's own source\n        // (only meaningful when configulator is a workspace package).\n        // codedrifters/packages restores them via\n        // `agentConfig.additionalRulePaths`.\n        filePatterns: [\n          \".claude/agents/pr-reviewer.md\",\n          \".claude/agents/issue-worker.md\",\n          // The operator skill's D2 handler routes on the label states\n          // this protocol defines; it must load alongside them.\n          \".claude/skills/babysit-prs/**\",\n        ],\n        content: [\n          \"# PR Review Feedback Protocol\",\n          \"\",\n          \"## Human-in-the-Loop Feedback Protocol\",\n          \"\",\n          \"The PR review pipeline is a **human-in-the-loop feedback loop**.\",\n          \"Reviewers (human or agent) leave comments on the PR; the\",\n          \"`pr-reviewer` sub-agent classifies each comment, reacts to it,\",\n          \"delegates in-scope fixes to `issue-worker`, and updates a single\",\n          \"sticky `## Reviewer notes` comment that is the canonical record of\",\n          \"PR state. The sections below document the conventions humans need\",\n          \"to read and drive that loop.\",\n          \"\",\n          \"### Trigger Model: Single-Pass, Pull-Based Delegation\",\n          \"\",\n          \"Each reviewer pass runs exactly once and does not self-chain. A\",\n          \"human (or a scheduled PR-review sweep) re-invokes\",\n          \"`/review-pr <n>` (or `/review-prs`) whenever the PR state changes\",\n          \"enough to warrant another look — a new comment, a new commit, a\",\n          \"resolved pushback, a label flip, or a worker clearing the\",\n          \"`review:needs-worker` marker. The reviewer never reschedules\",\n          \"itself.\",\n          \"\",\n          \"Delegation is **pull-based, not push-based**. The reviewer does\",\n          \"**not** spawn `issue-worker` in session — it frequently runs at\",\n          \"depth-1 (the orchestrator's PR sweep dispatches it as a\",\n          \"sub-agent), and the runtime forbids a depth-1 sub-agent from\",\n          \"spawning a depth-2 sub-agent, so an in-session dispatch would\",\n          \"silently abort. Instead the pass that decides to delegate posts a\",\n          \"fix-list, applies the durable `review:needs-worker` marker, holds\",\n          \"the `review:fixing` lease, and exits. A **separate** top-level\",\n          \"`issue-worker` session discovers the marker, applies the\",\n          \"fix-list, pushes, writes a worker-report comment, and clears\",\n          \"`review:needs-worker`. A later reviewer pass then confirms the\",\n          \"result and releases the lease. The worker's run is therefore\",\n          \"**not** the terminal step of the delegating reviewer pass — the\",\n          \"loop spans three passes (delegate → worker → confirm).\",\n          \"\",\n          \"This keeps the loop cheap to reason about: every step is\",\n          \"traceable to a label state on the PR, and the producer\",\n          \"(`pr-reviewer`, at any depth) never depends on a depth-2\",\n          \"sub-agent spawn to reach the consumer (`issue-worker`, always\",\n          \"top-level).\",\n          \"\",\n          \"### Reaction State Machine\",\n          \"\",\n          \"The reviewer signals its disposition toward each human comment via\",\n          \"GitHub reactions on that comment. Five reactions carry meaning in\",\n          \"this workflow; every other reaction is ignored.\",\n          \"\",\n          \"| Reaction | Meaning | Terminal? |\",\n          \"|----------|---------|-----------|\",\n          \"| `eyes` | Seen by reviewer; no terminal decision yet. Queued for processing on this or a later pass. | No |\",\n          \"| `+1` | Reviewer accepted the comment's request; a fix has been queued or has already landed. | **Yes** |\",\n          \"| `rocket` | The accepted fix has landed on the branch. The reviewer's reply cites the commit SHA that applied it. | **Yes** |\",\n          \"| `thinking_face` | Reviewer pushback — the comment conflicts with an acceptance criterion, a CLAUDE.md convention, the project-context doc, or is ambiguous. **Blocks auto-merge** until resolved. | No |\",\n          \"| `-1` | Declined as out-of-scope. A separate tracking issue was created; the reviewer's reply links to it. | **Yes** |\",\n          \"\",\n          \"Terminal reactions (`+1`, `rocket`, `-1`) are applied **only after**\",\n          \"the corresponding action has truly completed — the fix accepted,\",\n          \"the commit landed on the branch, or the out-of-scope tracking\",\n          \"issue created and linked in a reply. The reviewer never applies a\",\n          \"terminal reaction pre-emptively.\",\n          \"\",\n          \"A comment carrying only `eyes` or `thinking_face` from the\",\n          \"reviewer is **non-terminal** and will be re-evaluated on the next\",\n          \"pass. A comment carrying any terminal reaction authored by the\",\n          \"reviewer is dropped from future classification.\",\n          \"\",\n          \"GitHub's reactions API uses `confused` as the content string for\",\n          \"the `thinking_face` reaction (`content=confused` when POSTing).\",\n          \"\",\n          \"### Resolving a Pushback\",\n          \"\",\n          \"When the reviewer pushes back on a comment with `thinking_face`,\",\n          \"auto-merge is blocked until the dispute is resolved. Humans have\",\n          \"three ways to clear a pushback:\",\n          \"\",\n          \"1. **Withdraw the comment.** Delete the comment, or edit out the\",\n          \"   disputed request, then re-invoke `/review-pr <n>`. The reviewer\",\n          \"   drops the withdrawn item from its queue on the next pass.\",\n          \"2. **Reply with clarification.** Post a reply on the same thread\",\n          \"   that addresses the reviewer's objection (cite the acceptance\",\n          \"   criterion you meant, supply the missing context, or concede the\",\n          \"   point). Re-invoke `/review-pr <n>` — the reviewer re-classifies\",\n          \"   the thread and may promote `thinking_face` to `+1` if the\",\n          \"   clarification satisfies it.\",\n          \"3. **Force through with `review:auto-ok`.** Apply the\",\n          \"   `review:auto-ok` label to the PR as an explicit maintainer\",\n          \"   override. The reviewer will log the override in the sticky\",\n          \"   `## Reviewer notes` comment and proceed with auto-merge even\",\n          \"   though the dispute was never resolved by reply or withdrawal.\",\n          \"\",\n          \"### Fix-List Comment Format\",\n          \"\",\n          \"When Phase 4 delegates in-scope fixes to `issue-worker`, it posts\",\n          \"a single PR-level comment whose body carries both a human-readable\",\n          \"checkbox summary and a fenced ```json fix-list``` block. The JSON\",\n          \"block is the authoritative payload the worker parses; the\",\n          \"checkbox list is for humans reading the PR.\",\n          \"\",\n          \"```markdown\",\n          \"## Reviewer: fix list for @issue-worker\",\n          \"\",\n          \"- [ ] @<author> — <instruction summary> (<file>:<line>)\",\n          \"\",\n          \"```json fix-list\",\n          \"{\",\n          '  \"pr\": <pr-number>,',\n          '  \"branch\": \"<head-ref-name>\",',\n          '  \"generated_at\": \"<ISO-8601 timestamp>\",',\n          '  \"items\": [',\n          '    {\"comment_id\": \"<id>\", \"author\": \"<login>\", \"file\": \"<path>\", \"line\": <n>, \"instruction\": \"<imperative instruction>\"}',\n          \"  ]\",\n          \"}\",\n          \"```\",\n          \"```\",\n          \"\",\n          \"Each `items[]` entry corresponds to one in-scope comment the\",\n          \"reviewer queued on this pass. The `comment_id` is preserved\",\n          \"exactly as returned by the GitHub API so that `issue-worker` can\",\n          \"report per-item outcomes and the reviewer can apply `rocket` or\",\n          \"`thinking_face` to the correct source comment on the next pass.\",\n          \"\",\n          \"### Cross-Session `review:fixing` Lease Lifecycle\",\n          \"\",\n          \"Delegation hand-off is **pull-based and spans three passes**. Two\",\n          \"labels coordinate it: the `review:fixing` lease (mutual exclusion)\",\n          \"and the `review:needs-worker` marker (durable work signal). The\",\n          \"lease is held **across sessions** — it is acquired by the\",\n          \"reviewer pass that posts the fix-list and released only by a\",\n          \"later reviewer confirm pass, never within a single pass.\",\n          \"\",\n          \"| Step | Actor | Labels after the step |\",\n          \"|------|-------|-----------------------|\",\n          \"| **1. Delegate** | `pr-reviewer` | Posts the fix-list, **acquires** `review:fixing`, **applies** `review:needs-worker`, exits `delegated`. PR carries both labels. |\",\n          \"| **2. Consume** | `issue-worker` (top-level) | Discovers `review:needs-worker`, applies the fix-list, pushes, writes a worker-report comment, **clears** `review:needs-worker`. PR carries `review:fixing` only. |\",\n          \"| **3. Confirm** | `pr-reviewer` | Detects `review:fixing` **without** `review:needs-worker`, reacts on source comments from the worker report, re-evaluates AC/CI, re-enables auto-merge (auto-merge mode), **releases** `review:fixing`. PR carries neither label. |\",\n          \"\",\n          \"Key invariants:\",\n          \"\",\n          \"- The producer (`pr-reviewer`) **never spawns** the consumer\",\n          \"  (`issue-worker`) in session. The reviewer can run at depth-1,\",\n          \"  where nested sub-agent spawning is forbidden; the marker is the\",\n          \"  hand-off, not an `Agent` dispatch.\",\n          \"- The lease being held while `review:needs-worker` is still\",\n          \"  present means the delegation is **in flight** — a reviewer pass\",\n          \"  that sees both labels logs the in-flight state and exits without\",\n          \"  re-posting the fix-list or re-acquiring the lease.\",\n          \"- The lease being held **without** `review:needs-worker` is the\",\n          \"  **confirm trigger** — exactly one delegation has been consumed\",\n          \"  and is awaiting confirmation.\",\n          \"- `delegated` is never a terminal completion. A PR is only done\",\n          \"  when the confirm pass releases the lease and (in auto-merge\",\n          \"  mode) re-enables auto-merge.\",\n          \"\",\n          \"#### Stale-lease reclaim\",\n          \"\",\n          \"A crashed or never-launched worker must not wedge a PR by holding\",\n          \"the lease forever, and a worker that pushes but skips its hand-off\",\n          \"must not wedge the PR either. The **maintenance sweep** (not a\",\n          \"reviewer pass) owns reconcile for **both** stuck states — its\",\n          \"`check-blocked.sh maintenance` invocation runs the reconcile\",\n          \"directly and emits a `LEASE_RECONCILE orphaned=<N>\",\n          \"consumed_uncleared=<M>` summary line. No human is needed to free a\",\n          \"stuck PR.\",\n          \"\",\n          \"**Orphaned lease.** A `review:fixing` lease is **orphaned** when\",\n          \"**both** hold:\",\n          \"\",\n          \"- The PR carries `review:fixing` but **not**\",\n          \"  `review:needs-worker` — there is no in-flight worker still\",\n          \"  expected to clear the marker, **yet**\",\n          \"- No worker-report comment newer than the fix-list exists, **and**\",\n          \"  the fix-list comment is older than the stale in-progress\",\n          \"  threshold the maintenance sweep applies (72h by default).\",\n          \"\",\n          \"Together these mean a delegation was kicked off, the marker was\",\n          \"consumed-or-dropped, but no worker result ever landed — the lease\",\n          \"is orphaned. The maintenance sweep **re-applies**\",\n          \"`review:needs-worker` (re-arming the durable work marker so the\",\n          \"Phase B1 feedback drain retries the delegation) and posts an\",\n          \"audit-trail note comment. The `review:fixing` lease itself is left\",\n          \"untouched, so the drain stays idempotent. This is a deliberate\",\n          \"re-arm for autonomy — never a silent force-release: the note\",\n          \"comment is the audit trail proving the re-arm was the sweep's\",\n          \"doing.\",\n          \"\",\n          \"**Consumed-but-uncleared wedge.** The existing orphaned-lease\",\n          \"precondition (`review:fixing` *without* `review:needs-worker`)\",\n          \"structurally cannot see a worker that pushed its fix and then\",\n          \"skipped the hand-off — the marker is still set. The sweep detects\",\n          \"this wedge when a PR carries **both** `review:needs-worker` and\",\n          \"`review:fixing`, its branch HEAD commit is **newer** than the\",\n          \"fix-list comment, and there is **no** worker-report. It\",\n          \"auto-reconciles by **removing** `review:needs-worker` (the\",\n          \"hand-off the worker skipped) and posting an audit-trail reconcile\",\n          \"note comment, flipping the PR into the lease-without-marker\",\n          \"confirm-trigger state so the reviewer confirm pass takes over and\",\n          \"merges. As with the orphaned-lease path, the `review:fixing` lease\",\n          \"is left for that confirm pass to release.\",\n          \"\",\n          \"### Review-Label Invariants (Phase 2.8 reconciliation)\",\n          \"\",\n          \"A PR must never carry **mutually-exclusive review-workflow\",\n          \"labels** after a reviewer pass — the PR equivalent of the\",\n          '\"exactly one `status:*`\" discipline issues already follow.',\n          \"Successive passes layering labels with no reconciler can drive a\",\n          \"PR into an impossible state (a real PR once held\",\n          \"`review:awaiting-human` + `status:needs-attention` +\",\n          \"`review:fixing` + `review:needs-worker` at the same time). The\",\n          \"reviewer's **Phase 2.8 — Label Reconciliation** step enforces\",\n          \"the invariants below early in every pass, after Phase 2.75\",\n          \"decides the mode and after the confirm-trigger lease detection,\",\n          \"but before any phase branches on review state. Every correction\",\n          \"is logged on a `**Label reconciliation:**` line in the sticky\",\n          \"`## Reviewer notes` comment — labels are never mutated silently.\",\n          \"\",\n          \"**The invariants:**\",\n          \"\",\n          \"1. **`review:awaiting-human` is mutually exclusive with the\",\n          \"   fix-delegation labels (`review:needs-worker`,\",\n          \"   `review:fixing`).** A PR is **either** in the fix-delegation\",\n          \"   loop **or** handed to a human — never both. Any of\",\n          \"   `review:awaiting-human` + `review:needs-worker`,\",\n          \"   `review:awaiting-human` + `review:fixing`, or all three is a\",\n          \"   violation.\",\n          \"2. **`review:fixing` WITHOUT `review:needs-worker` is the\",\n          \"   confirm-pending state, not a violation.** The worker finished\",\n          \"   and cleared its marker; a confirm pass owns the PR and will\",\n          \"   release the lease. The reconciler must not strip it.\",\n          \"3. **`review:fixing` WITH `review:needs-worker` is a valid\",\n          \"   in-flight delegation, not a violation.** The work is durably\",\n          \"   queued for a top-level `issue-worker` pass.\",\n          \"4. **`status:needs-attention` is additive but must not coexist\",\n          \"   with a live, progressing in-flight delegation.** When\",\n          \"   `review:fixing` + `review:needs-worker` are present, the\",\n          \"   fix-list is newer than the flag, and there is no failed-fix\",\n          \"   pushback, the flag contradicts the live progress signal and is\",\n          \"   removed. A flag coexisting with a *stalled* / *failed*\",\n          \"   delegation, an unresolved `thinking_face` pushback, or a\",\n          \"   `human-required` hand-off is legitimate and stays.\",\n          \"\",\n          \"(`review:human-required` and `review:auto-ok` are **policy\",\n          \"inputs** read in Phase 2.75, not workflow-state labels — the\",\n          \"reconciler never touches them.)\",\n          \"\",\n          \"**Canonical resolution.** The losing label is chosen by the\",\n          \"Phase 2.75 mode plus the current loop position so the surviving\",\n          \"set matches the action the pass will take:\",\n          \"\",\n          \"| Violation combo | Loop position / mode | Resolution (winner) |\",\n          \"|-----------------|----------------------|---------------------|\",\n          \"| `review:awaiting-human` + fix-delegation label(s) | delegation in-flight or confirm-pending, mode `auto-merge` | **remove `review:awaiting-human`** — the delegation loop owns the PR |\",\n          \"| `review:awaiting-human` + fix-delegation label(s) | pass decided `human-required` (rules 2–5), no delegation actually in flight | **remove `review:needs-worker` + `review:fixing`** — the human hand-off wins; clear stale delegation labels |\",\n          \"| `status:needs-attention` + live progressing delegation | mode `auto-merge`, `review:fixing` + `review:needs-worker` present | **remove `status:needs-attention`** — contradicts the live progress signal |\",\n          \"\",\n          \"Resolution is **conservative about human intent**: a genuine\",\n          \"`human-required` pass clears the fix-delegation labels and keeps\",\n          \"the human-facing label; an `auto-merge` pass with a live\",\n          \"delegation keeps the delegation labels and clears the stray\",\n          \"`review:awaiting-human`. The reconciler only ever **removes** a\",\n          \"contradicting label — never adds one.\",\n          \"\",\n          \"### Sticky `## Reviewer notes` Comment\",\n          \"\",\n          \"Every PR has **one** canonical reviewer-notes comment. The\",\n          \"reviewer creates it on the first pass, then **edits it in place**\",\n          \"on every subsequent pass via\",\n          \"`gh api .../issues/comments/<id> -X PATCH`. It is never\",\n          \"duplicated and never replaced by a fresh per-pass summary.\",\n          \"\",\n          \"This sticky comment is the **single human-facing source of truth**\",\n          \"for the PR's current state. Humans scanning the PR should read\",\n          \"the sticky first, before scrolling back through individual threads.\",\n          \"It carries, at a minimum:\",\n          \"\",\n          \"- **Mode** — `auto-merge` or `human-required`, with the Phase 2.75\",\n          \"  reason that chose that mode.\",\n          \"- **AC status** — met, partial, or missing, with evidence links\",\n          \"  to files or tests.\",\n          \"- **CI status** — green, pending, or red.\",\n          \"- **Outstanding** — comments still carrying a non-terminal\",\n          \"  reviewer reaction (`eyes`, open `thinking_face`).\",\n          \"- **Pushbacks** — every unresolved `thinking_face` the reviewer\",\n          \"  has left, with the reason captured in its pushback reply.\",\n          \"- **Label reconciliation** — the Phase 2.8 outcome: `consistent`\",\n          \"  or the corrections applied this pass (violation combo, labels\",\n          \"  removed, resulting self-consistent set), recorded for audit.\",\n          \"- **Last pass** — the ISO 8601 timestamp of the most recent run.\",\n          \"\",\n          \"The sticky is updated on every pass — including passes that ended\",\n          \"in a pushback-gated skip, a `NEEDS_CHANGES` findings comment, or\",\n          \"a `human-required` hand-off — so it never goes stale while the\",\n          \"reviewer is actively processing the PR.\",\n          \"\",\n          \"### Label Glossary\",\n          \"\",\n          \"Seven review-workflow labels drive the feedback loop. They are\",\n          \"**contributed by the pr-review bundle's label set** and auto-sync\",\n          \"into every consumer's label registry — the same way the\",\n          \"`type:*` / `priority:*` / `status:*` taxonomy ships. Consumers do\",\n          \"**not** hand-declare them, so they survive a label sync run with\",\n          \"`deleteOtherLabels: true` that would otherwise prune a\",\n          \"locally-created label.\",\n          \"\",\n          \"| Label | Purpose |\",\n          \"|-------|---------|\",\n          `| \\`${ORIGIN_ISSUE_WORKER_LABEL}\\` | PR was opened by the \\`issue-worker\\` agent specifically. Eligible for auto-delegation of in-scope fixes. |`,\n          `| \\`${ORIGIN_AGENT_LABEL}\\` | **Umbrella origin label for agent-opened PRs.** Stamped by every phased analyst/writer agent (people-profile, company-profile, software-profile, customer-profile, bcm-writer, industry-discovery, business-models, standards-research, regulatory-research, maintenance-audit, meeting-analysis, agenda, research-pipeline, requirements-analyst, requirements-reviewer, requirements-writer) on the PRs it opens. Delegation-eligible on exactly the same terms as \\`${ORIGIN_ISSUE_WORKER_LABEL}\\` — the analyst family stamps this instead of \\`${ORIGIN_ISSUE_WORKER_LABEL}\\` because claiming the latter on a non-worker PR would be false. Human-authored PRs carry neither origin label and will not trigger delegation unless the reviewer is invoked with \\`--allow-human-author\\`. This label gates fix-**delegation** only; sweep and auto-merge eligibility have never been origin-gated. |`,\n          \"| `review:human-required` | Force human review regardless of what the policy would otherwise decide. The reviewer never enables auto-merge on a PR carrying this label. |\",\n          \"| `review:auto-ok` | Force auto-merge regardless of what the policy would otherwise decide. **Also resolves outstanding `thinking_face` pushbacks** as an explicit maintainer override; the reviewer logs the override in the sticky summary. |\",\n          \"| `review:awaiting-human` | Set by the reviewer when it completes its work on a `human-required` PR and is handing off the final merge decision. Cleared by a human (or by `review:auto-ok` flipping the PR back to `auto-merge` mode). |\",\n          \"| `review:fixing` | **Cross-session** delegation lease. Acquired by the reviewer pass that posts a fix-list; held across the worker's run; released only by a later reviewer **confirm** pass (PR carries `review:fixing` but not `review:needs-worker`). A lease held without `review:needs-worker` past the stale threshold with no worker report is orphaned and is auto-reconciled by the maintenance sweep — it re-applies `review:needs-worker` (re-arm) so the feedback drain retries, leaving the lease for the next confirm pass and posting an audit-trail note. |\",\n          \"| `review:needs-worker` | **Durable hand-off marker.** Applied by the reviewer alongside the fix-list so a top-level `issue-worker` session discovers the PR and pulls the work (the reviewer cannot spawn the worker in session — it may run at depth-1). Cleared by the worker when it finishes applying the fix-list, which is what triggers the reviewer's confirm pass. |\",\n          \"\",\n          \"### Reviewing Human-Authored PRs: the `--allow-human-author` Flag\",\n          \"\",\n          \"By default the reviewer only **delegates** in-scope fixes on\",\n          `bot-authored PRs — those carrying ${DELEGATION_ELIGIBLE_ORIGIN_PHRASE}.`,\n          \"Running `/review-pr <n>` or `/review-prs` on a\",\n          \"human-authored PR still produces a full review (reactions,\",\n          \"replies, sticky summary, and auto-merge when the policy allows\",\n          \"it) but skips the delegation hand-off to `issue-worker` — the\",\n          \"human author is expected to apply the fixes themselves.\",\n          \"\",\n          \"Pass `--allow-human-author` to opt into delegation on\",\n          \"human-authored PRs for a single invocation:\",\n          \"\",\n          \"```\",\n          \"/review-pr <pr-number> --allow-human-author\",\n          \"/review-prs --allow-human-author\",\n          \"```\",\n          \"\",\n          \"The flag does **not** persist across invocations. Subsequent\",\n          \"invocations return to the bot-only default and require the flag\",\n          \"to be re-supplied if delegation on a human-authored PR is desired\",\n          \"again.\",\n        ].join(\"\\n\"),\n        platforms: {\n          cursor: { exclude: true },\n        },\n        tags: [\"workflow\"],\n      },\n    ],\n\n    // `babysit-prs` is built from the resolved policy here rather than\n    // declared as a module-level const, so the consumer's\n    // `ci-verification.required-workflows` is baked into the rendered\n    // skill at bundle-build time. Nothing rewrites skill content after\n    // the bundle is assembled.\n    skills: [reviewPrSkill, reviewPrsSkill, buildBabysitPrsSkill(policy)],\n    subAgents: [prReviewerSubAgent],\n    labels: [\n      {\n        name: \"type:pr-review\",\n        color: \"5319E7\",\n        description: \"PR review tasks\",\n      },\n      {\n        name: ORIGIN_ISSUE_WORKER_LABEL,\n        color: \"5319E7\",\n        description: \"PR opened by the issue-worker agent\",\n      },\n      {\n        name: ORIGIN_AGENT_LABEL,\n        color: \"5319E7\",\n        description:\n          \"PR opened by an agent in this project's pipeline; eligible for autonomous fix delegation\",\n      },\n      {\n        name: \"review:auto-ok\",\n        color: \"0E8A16\",\n        description: \"Force auto-merge regardless of policy\",\n      },\n      {\n        name: \"review:human-required\",\n        color: \"D93F0B\",\n        description: \"Force human review regardless of policy\",\n      },\n      {\n        name: \"review:awaiting-human\",\n        color: \"FBCA04\",\n        description: \"Reviewer handed off; awaiting human merge decision\",\n      },\n      {\n        name: \"review:fixing\",\n        color: \"D4C5F9\",\n        description:\n          \"Cross-session lease held from fix-list post until a confirm pass releases it\",\n      },\n      {\n        name: \"review:needs-worker\",\n        color: \"1D76DB\",\n        description:\n          \"Durable marker: a reviewer fix-list awaits a top-level issue-worker pass\",\n      },\n    ],\n  };\n}\n\n/**\n * Render the resolved `pathsExemptFromSize` list as a YAML bullet\n * block. Each entry becomes a four-space-indented `- \"<glob>\"` line\n * so it nests cleanly under `auto-merge: paths-exempt-from-size:` in\n * the rendered policy YAML. An empty list collapses to a `[]` flow\n * sequence so the YAML stays parseable when consumers explicitly\n * disable the carve-out.\n */\nfunction renderPathsExemptFromSizeYaml(\n  paths: ReadonlyArray<string>,\n): ReadonlyArray<string> {\n  if (paths.length === 0) {\n    return [\"    []\"];\n  }\n  return paths.map((path) => `    - \"${path}\"`);\n}\n\n/**\n * Render the resolved `requiredWorkflows` list as a YAML bullet\n * block nested under `ci-verification: required-workflows:`. Each\n * entry becomes a four-space-indented `- \"<name>\"` line. An empty\n * list collapses to a `[]` flow sequence — the documented default\n * that tells the Actions-runs fallback to treat every observed run\n * for the head SHA as required.\n */\nfunction renderRequiredWorkflowsYaml(\n  workflows: ReadonlyArray<string>,\n): ReadonlyArray<string> {\n  if (workflows.length === 0) {\n    return [\"    []\"];\n  }\n  return workflows.map((workflow) => `    - \"${workflow}\"`);\n}\n\n/**\n * `pr-review` bundle built with the default policy. Preserved for\n * backward compatibility with tests and consumers that import the\n * const directly. Prefer `buildPrReviewBundle(policy)` when consumer\n * overrides are in scope.\n */\nexport const prReviewBundle: AgentRuleBundle = buildPrReviewBundle();\n\n/**\n * Re-exports so consumers and tests can construct a resolved policy\n * and feed it to `buildPrReviewBundle` without crossing into the\n * pr-review-policy helper module.\n */\nexport type { ResolvedPrReviewPolicy, PrReviewPolicyConfig };\nexport { resolvePrReviewPolicy };\n","import { Project } from \"projen/lib\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\nimport { hasDep } from \"./utils\";\n\n/**\n * Projen bundle — auto-detected when `projen` is in dependencies.\n */\nexport const projenBundle: AgentRuleBundle = {\n  name: \"projen\",\n  description: \"Projen conventions, synthesis workflow, .projenrc.ts patterns\",\n  appliesWhen: (project: Project) => hasDep(project, \"projen\"),\n  rules: [\n    {\n      name: \"development-commands\",\n      description:\n        \"Projen development commands for building, testing, linting, and validating changes\",\n      // ALWAYS scope: developers ask \"how do I build/test/lint?\" from\n      // anywhere in the repo, not only when editing projen config.\n      // Consumers that want to narrow the load can override via\n      // `agentConfig.additionalRulePaths` or `excludeRules`.\n      scope: AGENT_RULE_SCOPE.ALWAYS,\n      content: [\n        \"# Development Commands\",\n        \"\",\n        \"This project uses Projen to manage configuration and Turborepo to orchestrate builds across the monorepo. Run all commands from the **repository root** unless otherwise noted.\",\n        \"\",\n        \"## Synthesizing Projen Configuration\",\n        \"\",\n        \"After modifying any file in `projenrc/` or `.projenrc.ts`, regenerate project files using the safe three-step sequence:\",\n        \"\",\n        \"```sh\",\n        \"pnpm i\",\n        \"pnpm exec projen\",\n        \"pnpm i\",\n        \"```\",\n        \"\",\n        \"All three steps are required:\",\n        \"\",\n        \"1. The leading `pnpm i` guarantees `node_modules` matches `pnpm-lock.yaml` before synth. Without this step, `pnpm exec projen` may synth against a stale version of any pnpm-resolved component (configulator itself, projen, or any plugin) that the lockfile has already moved past — most commonly right after `git pull` updates the lockfile or on a fresh checkout. The result is phantom drift in `.claude/`, `.github/labels.yml`, `CLAUDE.md`, and other configulator-generated files that looks like a real bundle change but vanishes after running `pnpm i`.\",\n        \"2. `pnpm exec projen` regenerates files against the now-synced templates.\",\n        \"3. The trailing `pnpm i` picks up any dependency changes projen wrote into `package.json` during the synth pass and refreshes the lockfile.\",\n        \"\",\n        \"## Building\",\n        \"\",\n        \"**Full monorepo build** (compile + test + package, all sub-packages via Turborepo):\",\n        \"\",\n        \"```sh\",\n        \"pnpm build:all\",\n        \"```\",\n        \"\",\n        \"**Root project only** (synthesize + compile + lint):\",\n        \"\",\n        \"```sh\",\n        \"pnpm build\",\n        \"```\",\n        \"\",\n        \"**Single sub-package** (compile only):\",\n        \"\",\n        \"```sh\",\n        \"pnpm --filter @codedrifters/<package> compile\",\n        \"```\",\n        \"\",\n        \"Replace `<package>` with `configulator`, `constructs`, or `utils`.\",\n        \"\",\n        \"## Testing\",\n        \"\",\n        \"**Run tests for a single sub-package:**\",\n        \"\",\n        \"```sh\",\n        \"pnpm --filter @codedrifters/<package> test\",\n        \"```\",\n        \"\",\n        \"This runs ESLint + Vitest for the specified package.\",\n        \"\",\n        \"**Run only Vitest (skip lint) in a sub-package:**\",\n        \"\",\n        \"```sh\",\n        \"cd packages/@codedrifters/<package>\",\n        \"pnpm exec vitest run\",\n        \"```\",\n        \"\",\n        \"**Run a specific test file:**\",\n        \"\",\n        \"```sh\",\n        \"cd packages/@codedrifters/<package>\",\n        \"pnpm exec vitest run src/path/to/file.test.ts\",\n        \"```\",\n        \"\",\n        \"## Linting\",\n        \"\",\n        \"**Lint the root project:**\",\n        \"\",\n        \"```sh\",\n        \"pnpm eslint\",\n        \"```\",\n        \"\",\n        \"**Lint a single sub-package:**\",\n        \"\",\n        \"```sh\",\n        \"pnpm --filter @codedrifters/<package> eslint\",\n        \"```\",\n        \"\",\n        \"## Resetting Build Artifacts\",\n        \"\",\n        \"**Reset everything** (all packages + root):\",\n        \"\",\n        \"```sh\",\n        \"pnpm reset:all\",\n        \"```\",\n        \"\",\n        \"**Reset root only:**\",\n        \"\",\n        \"```sh\",\n        \"pnpm reset\",\n        \"```\",\n        \"\",\n        \"## Validating Changes Are Complete\",\n        \"\",\n        \"After finishing implementation work, validate that changes are correct by running the appropriate commands depending on what was changed:\",\n        \"\",\n        \"1. **Projen config changes** (`projenrc/`, `.projenrc.ts`):\",\n        \"   - Run the three-step regen sequence: `pnpm i`, then `pnpm exec projen`, then `pnpm i` again\",\n        \"   - Verify no unexpected generated file changes with `git diff`\",\n        \"\",\n        \"2. **Source code changes** (in a sub-package):\",\n        \"   - Compile: `pnpm --filter @codedrifters/<package> compile`\",\n        \"   - Test: `pnpm --filter @codedrifters/<package> test`\",\n        \"\",\n        \"3. **Changes spanning multiple packages**:\",\n        \"   - Run `pnpm build:all` to validate the full monorepo build\",\n        \"\",\n        \"4. **Root-level changes** (projenrc, root config):\",\n        \"   - Run `pnpm build` to validate root synthesis + compilation + lint\",\n        \"\",\n        \"## Command Reference\",\n        \"\",\n        \"| Task | Command |\",\n        \"|------|---------|\",\n        \"| Regenerate projen configuration | `pnpm i && pnpm exec projen && pnpm i` |\",\n        \"| Install deps | `pnpm i` |\",\n        \"| Full monorepo build | `pnpm build:all` |\",\n        \"| Root build only | `pnpm build` |\",\n        \"| Compile one package | `pnpm --filter @codedrifters/<pkg> compile` |\",\n        \"| Test one package | `pnpm --filter @codedrifters/<pkg> test` |\",\n        \"| Lint one package | `pnpm --filter @codedrifters/<pkg> eslint` |\",\n        \"| Lint root | `pnpm eslint` |\",\n        \"| Reset all artifacts | `pnpm reset:all` |\",\n      ].join(\"\\n\"),\n      tags: [\"workflow\"],\n    },\n    {\n      name: \"agent-rules-customization\",\n      description:\n        \"How to customize agent rules for this repo via the Projen project definition\",\n      scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n      filePatterns: [\n        \"projenrc/**/*.ts\",\n        \".projenrc.ts\",\n        \".claude/rules/*.md\",\n        \".cursor/rules/*.mdc\",\n        \"CLAUDE.md\",\n      ],\n      content: [\n        \"# Customizing Agent Rules\",\n        \"\",\n        \"Agent rules for Claude and Cursor are **generated** by configulator's `AgentConfig` component. The generated output files (`.claude/rules/`, `.cursor/rules/`, `CLAUDE.md`) must not be edited directly — they are overwritten on every `pnpm exec projen` run.\",\n        \"\",\n        \"## Adding Repo-Specific Rules\",\n        \"\",\n        \"Rules that only apply to this repository should be added to the `agentConfig.rules` array in the Projen project definition (`.projenrc.ts` or `projenrc/*.ts`):\",\n        \"\",\n        \"```typescript\",\n        \"agentConfig: {\",\n        \"  rules: [\",\n        \"    {\",\n        \"      name: 'my-repo-rule',\",\n        \"      description: 'What this rule does',\",\n        \"      scope: AGENT_RULE_SCOPE.ALWAYS, // or FILE_PATTERN with filePatterns\",\n        \"      content: '# My Rule\\\\n\\\\n- Guideline 1\\\\n- Guideline 2',\",\n        \"    },\",\n        \"  ],\",\n        \"}\",\n        \"```\",\n        \"\",\n        \"## Extending Existing Bundle Rules\",\n        \"\",\n        \"To append repo-specific content to a rule provided by a configulator bundle (without replacing it), use `agentConfig.ruleExtensions`:\",\n        \"\",\n        \"```typescript\",\n        \"agentConfig: {\",\n        \"  ruleExtensions: {\",\n        \"    'typescript-conventions': '## Additional Guidelines\\\\n\\\\n- My custom guideline',\",\n        \"  },\",\n        \"}\",\n        \"```\",\n        \"\",\n        \"The same pattern applies to bundled sub-agents and skills. Use `agentConfig.subAgentExtensions` to append project-specific content to a sub-agent prompt and `agentConfig.skillExtensions` to append content to a skill's `SKILL.md` body. Both options mirror `ruleExtensions` exactly — keys are sub-agent / skill names, values are markdown appended after a horizontal rule, and unknown keys are silently ignored.\",\n        \"\",\n        \"```typescript\",\n        \"agentConfig: {\",\n        \"  subAgentExtensions: {\",\n        \"    'requirements-writer': '## Project-Specific Gaps\\\\n\\\\n- My custom guidance',\",\n        \"  },\",\n        \"  skillExtensions: {\",\n        \"    'write-requirement': '## Project-Specific Templates\\\\n\\\\n- My custom template note',\",\n        \"  },\",\n        \"}\",\n        \"```\",\n        \"\",\n        \"## After Any Change\",\n        \"\",\n        \"Run the three-step regen sequence to regenerate the output files: `pnpm i`, then `pnpm exec projen`, then `pnpm i` again. The leading `pnpm i` syncs `node_modules` with the lockfile before synth so `pnpm exec projen` runs against the right configulator/projen/plugin versions; the trailing `pnpm i` refreshes the lockfile for any dependency changes projen made during synth.\",\n      ].join(\"\\n\"),\n      tags: [\"workflow\"],\n    },\n    {\n      name: \"projen-conventions\",\n      description: \"Projen configuration patterns and best practices\",\n      scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n      filePatterns: [\"projenrc/**/*.ts\", \".projenrc.ts\"],\n      content: [\n        \"# Projen Conventions\",\n        \"\",\n        \"## Configuration Management\",\n        \"\",\n        \"- **Never edit generated files** (`package.json`, `tsconfig.json`, etc. marked with `// ~~ Generated by projen`)\",\n        \"- Edit Projen configuration in:\",\n        \"  - `.projenrc.ts` (root)\",\n        \"  - `projenrc/*.ts` (package-specific)\",\n        \"- After making Projen changes, run the three-step regen sequence: `pnpm i`, `pnpm exec projen`, `pnpm i`. The leading `pnpm i` ensures `node_modules` matches the lockfile so synth runs against the right configulator/projen/plugin versions; without it, synth can produce phantom drift in generated files. The trailing `pnpm i` picks up dependency changes projen wrote during synth.\",\n        \"\",\n        \"## Workspace Dependencies\",\n        \"\",\n        \"When adding dependencies between packages in a monorepo:\",\n        \"\",\n        '- Use the workspace protocol: `project.addDeps(\"@org/sibling-pkg@workspace:*\")`',\n        \"- This ensures the local version is always resolved, not a registry version\",\n        '- For dev dependencies: `project.addDevDeps(\"@org/sibling-pkg@workspace:*\")`',\n        \"\",\n        \"## The `configureMyProject` Pattern\",\n        \"\",\n        \"Each package should expose a `configureMyProject(options)` factory function that creates and configures its Projen project:\",\n        \"\",\n        \"```typescript\",\n        \"export function configureMyProject(\",\n        \"  options: MyProjectOptions,\",\n        \"): TypeScriptProject {\",\n        \"  const project = new TypeScriptProject({\",\n        \"    ...options,\",\n        \"    // package-specific defaults\",\n        \"  });\",\n        \"\",\n        \"  // Attach components, configure rules, etc.\",\n        \"  return project;\",\n        \"}\",\n        \"```\",\n        \"\",\n        \"This pattern keeps `.projenrc.ts` clean and makes package configuration reusable and testable.\",\n        \"\",\n        \"## Custom Projen Components\",\n        \"\",\n        \"All custom components must extend `Component` from Projen and use a static `.of()` factory for discovery:\",\n        \"\",\n        \"```typescript\",\n        \"export class MyComponent extends Component {\",\n        \"  public static of(project: Project): MyComponent | undefined {\",\n        \"    const isDefined = (c: Component): c is MyComponent =>\",\n        \"      c instanceof MyComponent;\",\n        \"    return project.components.find(isDefined);\",\n        \"  }\",\n        \"\",\n        \"  constructor(project: Project, options: MyComponentOptions) {\",\n        \"    super(project);\",\n        \"    // Implementation\",\n        \"  }\",\n        \"}\",\n        \"```\",\n        \"\",\n        \"## Component Authoring\",\n        \"\",\n        \"- Export project types and utilities from `index.ts`\",\n        \"- Follow Projen's component lifecycle patterns\",\n        \"- Use `merge` from `ts-deepmerge` for deep merging configuration objects\",\n        \"- Components should be reusable and configurable; use TypeScript interfaces for component options\",\n        \"- Provide sensible defaults while allowing customization\",\n        \"- Document public APIs with minimal JSDoc; put extended documentation in markdown\",\n        \"\",\n        \"## Dependencies\",\n        \"\",\n        \"- Dependencies managed through Projen configuration, not directly in `package.json`\",\n        '- Use catalog dependencies when available (e.g., `\"projen\": \"catalog:\"`)',\n        \"- Peer dependencies for shared libraries (e.g., `constructs`, `projen`, `aws-cdk-lib`)\",\n        '- Use workspace protocol for internal packages: `\"@org/pkg@workspace:*\"`',\n      ].join(\"\\n\"),\n      tags: [\"workflow\"],\n    },\n  ],\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { renderClaimVerificationSection } from \"./claim-verification\";\nimport {\n  ISSUE_CLOSE_RULE_REFERENCE,\n  ISSUE_CLOSE_SECTION_TITLE,\n  renderIssueClosePolicySection,\n} from \"./issue-close\";\nimport {\n  DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n  ResolvedIssueDefaults,\n  labelsForPhase,\n} from \"./issue-defaults\";\nimport { renderIssueTypeAssignmentStep } from \"./issue-type\";\nimport { renderOriginStampSection } from \"./origin-label\";\nimport { DEFAULT_AGENT_PATHS, ResolvedAgentPaths } from \"./paths\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n  AGENT_MODEL,\n  AGENT_RULE_SCOPE,\n  AgentSkill,\n  AgentSubAgent,\n} from \"../types\";\n\n/**\n * Verbatim regulation-page template shipped to the consuming project\n * alongside the `/research-regulation` skill. Emitted as\n * `_references/templates/_template-regulation.md` under the skill\n * directory so the research-phase handler resolves it locally without\n * reaching back into configulator.\n *\n * The template is domain-neutral: it captures the structural shape of a\n * regulation page (status, applicability, key requirements, jurisdiction\n * variations, enforcement, penalties, related standards) without\n * hardcoding any specific regulation, regulator, industry, or\n * jurisdiction. Concrete values are filled in by the research phase.\n */\nconst TEMPLATE_REGULATION = `---\ntitle: \"<Regulation Name>\"\ndescription: \"Research on <Regulation Name> — scope, key requirements, jurisdiction variations, enforcement, and penalties.\"\nregulation: <REGULATION_SLUG>\njurisdiction: <federal | state | provincial | international | local>\nindustry: <industry-slug or 'platform'>\n---\n\n| Field | Value |\n|-------|-------|\n| **Official name** | <full legal name> |\n| **Short name** | <common acronym or short title> |\n| **Governing body** | <regulator / enforcement agency> |\n| **Jurisdiction** | <federal / state / international / local + country / region> |\n| **Status** | <in force / proposed / sunset / superseded> |\n| **Effective date** | YYYY-MM-DD |\n| **Last reviewed** | YYYY-MM-DD |\n\n## Overview\n\n<2–3 paragraphs on the regulation's purpose, its history, who authored\nit, and why it matters to the consuming project's industry or\nplatform.>\n\n## Scope and Triggers\n\n### Who Must Comply\n\n<Describe the categories of organization or system this regulation\napplies to. Cite the triggering section of the regulation.>\n\n### What Activities Trigger It\n\n<Describe the activities, data types, or transactions that bring an\norganization in scope. Cite the triggering sections.>\n\n### Exemptions\n\n| Exemption | Scope | Citation |\n|-----------|-------|----------|\n| <exemption name> | <what is exempt> | <section reference> |\n\n## Key Requirements\n\nEvery requirement cites the specific section, article, clause, or\nparagraph number. Generic statements without citations are not\nacceptable.\n\n| Requirement Area | Summary | Citation |\n|------------------|---------|----------|\n| <area> | <what is required> | <section / article reference> |\n\n## Jurisdiction Variations\n\n### Base Jurisdiction\n\n| Requirement Area | Base Requirement | Citation |\n|------------------|------------------|----------|\n| <area> | <what is required> | <section reference> |\n\n### Variations\n\nList jurisdictions where the regulation varies from the base. Skip\njurisdictions that adopt the base unchanged.\n\n#### <Jurisdiction Name>\n\n| Requirement Area | Local Variation | How It Differs | Citation |\n|------------------|-----------------|----------------|----------|\n| <area> | <local requirement> | <stricter / looser / different scope> | <local law reference> |\n\nIf no significant jurisdiction variations exist, replace this section\nwith \\`No significant jurisdiction variations identified.\\`\n\n## Enforcement\n\n| Enforcement Mechanism | Description | Citation |\n|-----------------------|-------------|----------|\n| <mechanism> | <how it is enforced> | <section reference> |\n\n### Enforcement History\n\n<Brief summary of notable enforcement actions or regulator guidance.\nCite each action.>\n\n## Penalties\n\n| Violation Type | Penalty Range | Citation |\n|----------------|---------------|----------|\n| <type> | <monetary / operational / criminal> | <section reference> |\n\n## Effective Dates and Timelines\n\n| Milestone | Date | Notes |\n|-----------|------|-------|\n| <event> | <date> | <what changed> |\n\n## Related Regulations\n\n| Regulation | Relationship | Link |\n|------------|--------------|------|\n| <name> | <supersedes / complements / overlaps / references> | <relative link> |\n\n## Related Standards\n\nInteroperability standards or technical standards that this regulation\nmandates or references. Link to standards-research pages when available.\n\n| Standard | Mandated Version | How It's Referenced | Link |\n|----------|------------------|---------------------|------|\n| <standard> | <version> | <citation> | <relative link> |\n\nIf this regulation does not cite any technical standards, replace this\ntable with \\`Not applicable — regulation does not cite technical\nstandards.\\`\n\n## Enforcement Bodies\n\n| Organization | Role | Link |\n|--------------|------|------|\n| <body> | <rulemaking / enforcement / audit> | <relative link> |\n\n## Open Questions\n\n<Questions a human legal or compliance reviewer must resolve before\ndownstream requirements are drafted. Keep each item to a sentence.>\n\n## Sources\n\n1. [<Title>](<URL>) — <brief description>\n\n## Revision History\n\n| Date | Author | Changes |\n|------|--------|---------|\n| YYYY-MM-DD | <author> | Initial research page |\n`;\n\n/**\n * Reference files emitted alongside the `/research-regulation` SKILL.md.\n * Currently just the regulation-page template; kept as a\n * `ReadonlyArray` so future reference material (e.g. a source-tier\n * guide) can be added without changing the bundle shape.\n */\nconst REGULATORY_RESEARCH_REFERENCE_FILES: ReadonlyArray<{\n  readonly path: string;\n  readonly content: string;\n}> = [\n  {\n    path: \"_references/templates/_template-regulation.md\",\n    content: TEMPLATE_REGULATION,\n  },\n];\n\n/**\n * Sub-agent that runs jurisdictional regulatory compliance research,\n * deep-dives on individual regulations, and synthesizes impact\n * analyses that hand off to the requirements pipeline as SEC\n * (security & compliance) category seeds.\n *\n * The prompt is deliberately domain-neutral. Concrete regulation\n * names, regulator acronyms, jurisdictions, industry categories, and\n * penalty ranges come from the invoking issue body,\n * `docs/src/content/docs/project-context.md`, or the consuming\n * project's `agentConfig.rules` — not from the bundle.\n */\nfunction buildRegulatoryResearchAnalystSubAgent(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSubAgent {\n  return {\n    name: \"regulatory-research-analyst\",\n    description:\n      \"Authors jurisdictional compliance research through a 3-phase pipeline (scan → research → impact). Enumerates applicable regulations by jurisdiction and business activity, researches each in depth, and produces an impact analysis that hands off actionable obligations to the requirements-analyst as req:scan seeds in the SEC category. One phase per session, tracked by regulatory:* GitHub issue labels with filesystem-based durability between phases.\",\n    model: AGENT_MODEL.POWERFUL,\n    maxTurns: 80,\n    platforms: { cursor: { exclude: true } },\n    prompt: [\n      \"# Regulatory Research Analyst Agent\",\n      \"\",\n      \"You run a structured jurisdictional compliance research pipeline:\",\n      \"scan applicable regulations by jurisdiction and business activity,\",\n      \"research each regulation in depth, and produce an impact analysis\",\n      \"that hands off actionable obligations to the requirements pipeline\",\n      \"as SEC (security & compliance) category seeds. Each phase runs as\",\n      \"its **own agent session**, triggered by a GitHub issue with a\",\n      \"`regulatory:*` phase label. You handle exactly **one phase per\",\n      \"session** — read the issue to determine which phase to execute.\",\n      \"\",\n      \"This agent is **domain-neutral**. It makes no assumptions about\",\n      \"which regulations matter, which industries they govern, which\",\n      \"jurisdictions are in scope, or which regulators apply. All concrete\",\n      \"vocabulary — regulation names, regulator acronyms, jurisdiction\",\n      \"identifiers, industry categories, and penalty schedules — comes\",\n      \"from the invoking issue body,\",\n      `\\`${paths.docsRoot}/project-context.md\\`, or the consuming`,\n      \"project's configuration.\",\n      \"\",\n      \"This agent **documents** regulatory obligations; it does **not**\",\n      \"interpret them. Legal interpretation, compliance strategy, and risk\",\n      \"assessment are human responsibilities. When regulation text is\",\n      \"ambiguous or regulator guidance conflicts, flag the ambiguity as an\",\n      \"open question and block — never guess at the interpretation.\",\n      \"\",\n      \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n      \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...PROJECT_CONTEXT_READER_SECTION,\n      \"## Design Principles\",\n      \"\",\n      \"1. **Jurisdiction-aware.** The same regulation may apply differently\",\n      \"   at local, state, federal, and international levels. Document each\",\n      \"   level explicitly — do not collapse variations into one page when\",\n      \"   they materially differ.\",\n      \"2. **Trace to the source.** Every regulatory requirement must cite\",\n      \"   the specific section, article, clause, or paragraph number.\",\n      '   Generic statements like \"regulation X requires encryption\" are',\n      \"   insufficient — the citation must be specific enough that a human\",\n      \"   reviewer can locate the exact passage.\",\n      \"3. **Document, do not interpret.** This agent captures what a\",\n      \"   regulation says, not what it means. When interpretation is\",\n      \"   ambiguous, flag the ambiguity as an open question for legal or\",\n      \"   compliance review. Never guess at regulatory meaning.\",\n      \"4. **Impact-driven.** Regulatory obligations are only useful when\",\n      \"   connected to concrete product requirements. The impact phase is\",\n      \"   the load-bearing step that closes the loop between documented\",\n      \"   regulation and actionable `req:scan` seeds in the SEC category.\",\n      \"5. **Filesystem durability.** Every phase persists its output to a\",\n      \"   file on disk before closing its issue. Downstream phases read\",\n      \"   those files — never rely on session memory.\",\n      \"6. **Issue graph = state machine.** Phase ordering is encoded with\",\n      \"   `Depends on: #N` links between phase issues. Research runs only\",\n      \"   after the scan identifies it; impact runs only after research\",\n      \"   completes.\",\n      \"7. **Generic over specific.** No hardcoded regulation names,\",\n      \"   regulator acronyms, jurisdiction identifiers, or industry\",\n      \"   categories. Use placeholders that the invoking issue or consuming\",\n      \"   project fills in.\",\n      \"8. **Research, not authoring.** This pipeline produces scan reports,\",\n      \"   regulation pages, and impact analyses. It never writes requirement\",\n      \"   documents, capability models, or canonical profiles — those are\",\n      \"   the responsibility of the `requirements-writer`, `bcm-writer`,\",\n      \"   `company-profile`, and `people-profile` bundles. Surfaced work is\",\n      \"   delegated to those bundles via issues.\",\n      \"9. **No fabrication.** Every factual claim must trace to a cited\",\n      \"   source — regulation text, regulator guidance, or a reputable\",\n      \"   compliance publication. When source material is insufficient,\",\n      \"   block the issue rather than filling gaps from general knowledge.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Source Credibility\",\n      \"\",\n      \"Regulatory research is held to a stricter evidence standard than\",\n      \"other research pipelines because regulatory errors have real\",\n      \"compliance consequences.\",\n      \"\",\n      \"| Tier | Description | Examples | Usage Rules |\",\n      \"|------|-------------|----------|-------------|\",\n      \"| **Tier 1** | Official, authoritative sources | Regulation text on an official government publisher, regulator guidance documents, peer-reviewed legal publications | A single Tier 1 source is sufficient to mark a claim as supported. Regulatory citations **require** at least one Tier 1 source. |\",\n      \"| **Tier 2** | Reputable professional sources | Major law-firm client alerts, trade-association compliance guides, established industry-press coverage of enforcement actions | Acceptable as supporting context for a claim already grounded in Tier 1. Never sufficient on their own for a regulatory citation. |\",\n      \"| **Tier 3** | Informal sources | Blog posts, community forums, vendor marketing, social media, Wikipedia | Never used for regulatory claims. Acceptable only for colour around enforcement history or adoption context, and always flagged. |\",\n      \"\",\n      \"**Every requirement in a regulation page must have a Tier 1\",\n      \"citation.** No exceptions.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## State Machine Overview\",\n      \"\",\n      \"Regulatory research flows through **3 phases**:\",\n      \"\",\n      \"```\",\n      \"┌──────────┐   ┌──────────┐   ┌──────────┐\",\n      \"│ 1. SCAN  │──▶│ 2. RESE- │──▶│ 3. IMPACT│\",\n      \"│ Enumerate│   │    ARCH  │   │ Assess   │\",\n      \"│ regs by  │   │ One reg  │   │ impact;  │\",\n      \"│ juris. + │   │ at a     │   │ hand off │\",\n      \"│ activity │   │ time;    │   │ SEC      │\",\n      \"│          │   │ reqs,    │   │ req:scan │\",\n      \"│          │   │ dates,   │   │ seeds    │\",\n      \"│          │   │ penalties│   │          │\",\n      \"└──────────┘   └──────────┘   └──────────┘\",\n      \"```\",\n      \"\",\n      \"**Issue labels encode the phase:**\",\n      \"\",\n      \"| Label | Phase | Session work |\",\n      \"|-------|-------|-------------|\",\n      \"| `regulatory:scan` | 1. Scan | Enumerate regulations applicable to an industry, jurisdiction, or platform. Write a scan report. Create `regulatory:research` issues for each prioritized regulation. 4–8 targeted web searches. |\",\n      \"| `regulatory:research` | 2. Research | Research one regulation in depth — scope, triggers, key requirements, jurisdiction variations, enforcement, penalties. Populate the regulation page from the ship-with template. Create the blocked `regulatory:impact` issue. 6–12 targeted web searches. |\",\n      \"| `regulatory:impact` | 3. Impact | Assess product impact, document capability gaps, hand off each actionable obligation as a `req:scan` issue in the SEC category. No web searches — synthesis and issue creation only. |\",\n      \"\",\n      \"All issues also carry `type:regulatory-research` and a `status:*` label.\",\n      \"\",\n      \"**Issue count per regulation:** 1 research + 1 impact = **2\",\n      \"sessions** (scan is shared across an industry or platform scope).\",\n      \"\",\n      \"**Shortened paths:**\",\n      \"- Research a single regulation with no scan (direct hand-off from\",\n      \"  another agent) → **1 session**.\",\n      \"- Re-assess impact when a regulation page was refreshed → **1\",\n      \"  session**.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Configurable Paths\",\n      \"\",\n      \"The pipeline uses these placeholders. Consuming projects override the\",\n      \"defaults by passing paths in the skill invocations or by extending\",\n      \"this rule in their own `agentConfig.rules`.\",\n      \"\",\n      \"| Placeholder | Meaning | Default |\",\n      \"|-------------|---------|---------|\",\n      `| \\`<REGULATORY_ROOT>\\` | Root folder for all regulatory-research documents | \\`${paths.docsRoot}/regulatory-research/\\` |`,\n      \"| `<REGULATION_DIR>` | Per-scope directory containing regulation pages | `<REGULATORY_ROOT>/<SCOPE_SLUG>/` |\",\n      \"| `<REGULATION_PAGE>` | One-regulation research page | `<REGULATION_DIR>/<REGULATION_SLUG>.md` |\",\n      \"| `<SCOPE_INDEX_PAGE>` | Scope-level index page | `<REGULATION_DIR>/index.md` |\",\n      \"| `<SCAN_DIR>` | Scan reports written during Phase 1 | `<researchRoot>/regulatory/` |\",\n      \"| `<SCOPE_SLUG>` | Short kebab-case slug identifying the industry, jurisdiction, or platform scope | derived from the scan issue |\",\n      \"| `<REGULATION_SLUG>` | Short kebab-case slug identifying one regulation | derived from the research issue |\",\n      \"\",\n      `If \\`${paths.docsRoot}/project-context.md\\` specifies a different`,\n      \"regulatory-research tree, prefer that. Otherwise fall back to the\",\n      \"defaults above.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Agent Loop\",\n      \"\",\n      \"Run this loop exactly once per session. Never start a second issue.\",\n      \"\",\n      \"1. Claim one open `type:regulatory-research` issue using phase\",\n      \"   priority: `regulatory:scan` > `regulatory:research` >\",\n      \"   `regulatory:impact`. Within a phase, prefer the oldest ready\",\n      \"   issue (FIFO).\",\n      \"2. Transition `status:ready` → `status:in-progress` and create the\",\n      \"   branch per your project's branch-naming convention.\",\n      \"3. Execute the phase handler that matches the issue's `regulatory:*`\",\n      \"   label.\",\n      \"4. Commit, push, open a PR (if applicable), and close the issue per\",\n      `   your project's PR workflow — see the **${ISSUE_CLOSE_SECTION_TITLE}**`,\n      \"   section below before you close anything yourself.\",\n      \"   Stamp every PR you open with the `origin:agent` label — see the\",\n      \"   **Origin label** section below.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...renderClaimVerificationSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderOriginStampSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderIssueClosePolicySection(),\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 1: Scan (`regulatory:scan`)\",\n      \"\",\n      \"**Goal:** Enumerate regulations applicable to a given scope —\",\n      \"typically an industry, a jurisdiction, or the consuming project's\",\n      \"platform itself — and produce a prioritized list with downstream\",\n      \"research issues.\",\n      \"\",\n      \"**Budget:** 4–8 targeted web searches. Writing one scan report and\",\n      \"creating `regulatory:research` issues for each prioritized\",\n      \"regulation.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the scan issue body.** Extract:\",\n      \"   - The scope type: industry, jurisdiction, or platform\",\n      \"   - The `<SCOPE_SLUG>` (industry slug, country / region code, or\",\n      \"     `platform`)\",\n      \"   - Authorized input paths — prior industry, customer, or standards\",\n      \"     research that reference the scope\",\n      \"   - Optional: known regulations to include, regulations to exclude,\",\n      \"     and a priority hint\",\n      \"\",\n      \"2. **Read related project context.** Check\",\n      `   \\`${paths.docsRoot}/project-context.md\\` for declared`,\n      \"   jurisdictional scope, industry categories, and any regulations\",\n      \"   already flagged by other agents. Check industry-research,\",\n      \"   customer-research, and standards-research trees for prior\",\n      \"   references to regulations in this scope.\",\n      \"\",\n      \"3. **Read existing regulatory-research pages** under\",\n      \"   `<REGULATION_DIR>`. A scan may land on top of a partially\",\n      \"   populated tree — stub regulation pages, a prior scan report, or\",\n      \"   impact analyses from earlier work. Treat these as inputs, not\",\n      \"   work to redo.\",\n      \"\",\n      \"4. **Execute 4–8 targeted web searches** to enumerate the\",\n      \"   regulatory landscape:\",\n      \"   - Regulations governing the scope at each jurisdiction level\",\n      \"     (local, state / provincial, federal / national, international)\",\n      \"   - Regulator and enforcement-agency identities\",\n      \"   - Recent rulemaking activity or pending regulations\",\n      \"   - Cross-border or supply-chain regulatory overlaps\",\n      \"\",\n      \"   If a search returns low-quality results, try one reformulated\",\n      \"   query before moving on. Never exceed the 8-search cap.\",\n      \"\",\n      \"5. **Write the scan report** to\",\n      \"   `<SCAN_DIR>/regulatory-<SCOPE_SLUG>-<YYYY-MM-DD>.md`:\",\n      \"\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"Regulatory Scan: <Scope>\"',\n      \"   date: YYYY-MM-DD\",\n      \"   parent_issue: <N>\",\n      \"   status: active\",\n      \"   scope: <SCOPE_SLUG>\",\n      \"   ---\",\n      \"\",\n      \"   ## Scope Context\",\n      \"   - **Scope type:** <industry / jurisdiction / platform>\",\n      \"   - **Scope identifier:** <SCOPE_SLUG>\",\n      \"   - **Geographic reach:** <where regulations apply>\",\n      \"\",\n      \"   ## Platform Regulations\",\n      \"   Regulations that apply to the consuming project's software\",\n      \"   platform itself (not a specific industry vertical).\",\n      \"\",\n      \"   | Regulation | Jurisdiction | Why It Applies | Priority |\",\n      \"   |------------|--------------|----------------|----------|\",\n      \"\",\n      \"   ## Regulations by Jurisdiction Level\",\n      \"\",\n      \"   ### International / Cross-Border\",\n      \"   | Regulation | Region | Scope | Priority |\",\n      \"   |------------|--------|-------|----------|\",\n      \"\",\n      \"   ### Federal / National\",\n      \"   | Regulation | Country | Scope | Priority |\",\n      \"   |------------|---------|-------|----------|\",\n      \"\",\n      \"   ### State / Provincial\",\n      \"   | Regulation | State / Province | Scope | Priority |\",\n      \"   |------------|------------------|-------|----------|\",\n      \"\",\n      \"   ### Local / Municipal\",\n      \"   | Regulation | Locality | Scope | Priority |\",\n      \"   |------------|----------|-------|----------|\",\n      \"\",\n      \"   ## Existing Coverage\",\n      \"   - <regulation>: <already researched / issue open / not started>\",\n      \"\",\n      \"   ## Recommendations\",\n      \"   - <regulation> → create research issue (priority: <level>)\",\n      \"   - <regulation> → already covered, no action\",\n      \"   - <regulation> → defer until <condition>\",\n      \"\",\n      \"   ## Sources\",\n      \"   1. [<Title>](<URL>) — <description>\",\n      \"   ```\",\n      \"\",\n      \"6. **Create one `regulatory:research` issue per recommended\",\n      \"   regulation.** Each issue cites the scan report, names the\",\n      \"   regulation, and identifies the jurisdiction. Apply the scan\",\n      \"   issue's priority as the default; escalate if the scope flags a\",\n      \"   higher-priority regulation.\",\n      \"\",\n      \"7. **Create or update the scope index page** at\",\n      \"   `<SCOPE_INDEX_PAGE>` so downstream regulations link back to a\",\n      \"   coherent landing page for the scope. Follow the\",\n      \"   section-index-page contract in the `shared-editing-safety` rule:\",\n      \"   the body must carry a 1–2\",\n      \"   paragraph contextual summary plus a grouped, linked listing of\",\n      \"   every regulation in the scope (e.g. by jurisdiction). No body\",\n      \"   `# Heading` — the frontmatter `title:` already renders as the\",\n      \"   page H1.\",\n      \"\",\n      \"8. **Commit and push** the scan report and the scope index page.\",\n      `   Close the scan issue ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 2: Research (`regulatory:research`)\",\n      \"\",\n      \"**Goal:** Research one regulation in depth and populate the\",\n      \"regulation page with scope, triggers, key requirements, jurisdiction\",\n      \"variations, enforcement, and penalties.\",\n      \"\",\n      \"**Budget:** 6–12 targeted web searches (6–8 for core requirements,\",\n      \"plus 0–4 for jurisdiction variations). Writes one regulation page,\",\n      \"creates the blocked impact issue, and may create\",\n      \"`company:research` issues for enforcement bodies not yet profiled.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the scan report** for context on this regulation's\",\n      \"   priority and scope.\",\n      \"\",\n      \"2. **Read the regulation-page template** at\",\n      \"   `.claude/skills/research-regulation/_references/templates/_template-regulation.md`.\",\n      \"   The template is authoritative — copy its structure verbatim into\",\n      \"   the regulation page, then populate each section from your\",\n      \"   research.\",\n      \"\",\n      \"3. **Read existing regulation pages** in the same `<REGULATION_DIR>`\",\n      \"   to follow consistent structure and avoid duplication.\",\n      \"\",\n      \"4. **Execute 6–8 core web searches** for the regulation's\",\n      \"   requirements:\",\n      \"   - Official regulation text on an authoritative publisher\",\n      \"   - Regulator guidance documents\",\n      \"   - Compliance summaries from reputable legal sources\",\n      \"   - Enforcement history and notable actions\",\n      \"   - Recent amendments or proposed changes\",\n      \"   - Implementation timelines\",\n      \"   - Relationship to other regulations\",\n      \"\",\n      \"   If a search returns low-quality results, try one reformulated\",\n      \"   query before moving on.\",\n      \"\",\n      \"5. **Execute up to 4 jurisdiction searches** if the regulation has\",\n      \"   meaningful jurisdiction variations (state / provincial,\",\n      \"   international equivalents, local variations). Skip this step if\",\n      \"   the regulation applies uniformly across its scope.\",\n      \"\",\n      \"6. **Populate the regulation page** at `<REGULATION_PAGE>` by\",\n      \"   copying the template verbatim and filling each section. Every\",\n      \"   requirement in the `Key Requirements` table must cite a specific\",\n      \"   section, article, or paragraph number. Every jurisdiction\",\n      \"   variation must cite the local law reference.\",\n      \"\",\n      \"7. **Create the `regulatory:impact` issue** blocked on this\",\n      \"   research issue (`Depends on: #<this-issue>`). Its body references\",\n      \"   the regulation page and lists the capability gaps the impact\",\n      \"   phase must assess.\",\n      \"\",\n      \"8. **Create `company:research` issues** for enforcement bodies or\",\n      \"   regulator agencies that do not already have a canonical profile\",\n      \"   or an open `company:research` issue. The `company-profile`\",\n      \"   bundle owns the downstream profile; this agent only hands off.\",\n      \"   Each issue must carry:\",\n      \"\",\n      \"   - `type:company-profile`\",\n      \"   - `company:research`\",\n      `   - \\`priority:${labelsForPhase(issueDefaults, \"company:research\").priority}\\``,\n      `   - \\`status:${labelsForPhase(issueDefaults, \"company:research\").status}\\``,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"9. **Verify all handoffs were created** before committing.\",\n      \"\",\n      \"10. **Commit and push** the regulation page. Close the research\",\n      `    issue ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 3: Impact (`regulatory:impact`)\",\n      \"\",\n      \"**Goal:** Assess how the regulation affects the consuming project —\",\n      \"which capabilities are affected, which customer or industry segments\",\n      \"are in scope, and which obligations must be translated into\",\n      \"requirements. Hand off each actionable obligation as a `req:scan`\",\n      \"seed that becomes an SEC requirement in the writer pipeline.\",\n      \"\",\n      \"**Budget:** No web searches. Pure synthesis from the regulation\",\n      \"page plus project context, with issue creation for downstream\",\n      \"handoffs.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the regulation page** with full requirements and\",\n      \"   jurisdiction variations.\",\n      \"\",\n      `2. **Read project context** (\\`${paths.docsRoot}/project-context.md\\`)`,\n      \"   to identify which capability areas the consuming project maps to.\",\n      \"   Read capability-model and business-model trees if present for\",\n      \"   reverse mappings.\",\n      \"\",\n      \"3. **Edit the regulation page** to append an `## Impact` section:\",\n      \"\",\n      \"   ```markdown\",\n      \"   ## Impact\",\n      \"\",\n      \"   ### Platform Compliance\",\n      \"   | Requirement Area | Product Component Affected | Compliance Approach |\",\n      \"   |------------------|---------------------------|---------------------|\",\n      \"   | <area from Key Requirements> | <component or capability> | <how the product should comply> |\",\n      \"\",\n      \"   ### Customer Compliance Support\",\n      \"   | Requirement Area | What Customers Need | What the Product Should Provide |\",\n      \"   |------------------|---------------------|---------------------------------|\",\n      \"   | <area> | <customer obligation> | <feature or capability> |\",\n      \"\",\n      \"   ### Capability Gaps\",\n      \"   Capabilities the consuming project needs but does not yet have\",\n      \"   to support compliance:\",\n      \"\",\n      \"   | Gap | Regulation Citation | Priority | Affected Components |\",\n      \"   |-----|---------------------|----------|---------------------|\",\n      \"   | <gap description> | <citation> | <high / medium / low> | <component list> |\",\n      \"\",\n      \"   ### Affected Segments\",\n      \"   | Segment | How Affected |\",\n      \"   |---------|--------------|\",\n      \"   | <segment name> | <how the regulation affects this segment> |\",\n      \"\",\n      \"   ## Traceability\",\n      \"   - **Source regulation:** <citation>\",\n      \"   - **Affected segments:** <relative links>\",\n      \"   - **Standards implementing:** <relative links> (if applicable)\",\n      \"\",\n      \"   **Requirements created** (one per line, ascending issue-number\",\n      \"   order — append your own entries only):\",\n      \"\",\n      \"   - #<N> — <PREFIX> req:scan\",\n      \"   ```\",\n      \"\",\n      \"   The **Requirements created** block is an **append-only,\",\n      \"   one-issue-per-line, deterministically sorted** list — it is a\",\n      \"   merge-conflict hotspot because sibling `regulatory:impact`\",\n      \"   sessions land requirement entries into the same regulation page\",\n      \"   concurrently. Maintain it under the following discipline (the\",\n      \"   same discipline the `shared-editing-safety` rule prescribes for\",\n      \"   shared registries, applied here to this one list section — the\",\n      \"   surrounding regulation page is a hand-authored document, not a\",\n      \"   registry, so only this section is governed):\",\n      \"\",\n      \"   - **One entry per line.** Write each requirement you created as\",\n      \"     its own new `- #<N> — <PREFIX> req:scan` bullet. Never collapse\",\n      \"     entries into a single comma-separated\",\n      \"     `**Requirements created:** #N, #M` line — that single mutable\",\n      \"     line is the original conflict cause and always conflicts when\",\n      \"     two sessions touch it.\",\n      \"   - **Ascending issue-number order.** Insert your bullet in the\",\n      \"     position that keeps the list sorted by issue number. A\",\n      \"     single-line bullet insert into a sorted list rarely truly\",\n      \"     conflicts, so git auto-merges concurrent sibling inserts.\",\n      \"   - **Append-only.** Never rewrite, reorder, or merge existing\",\n      \"     bullets. If a legacy comma line\",\n      \"     (`**Requirements created:** #N, #M`) already exists on the\",\n      \"     page, leave it untouched and add your entries as per-line\",\n      \"     bullets below it — do **not** rewrite the legacy line, because\",\n      \"     rewriting it is itself a conflict.\",\n      \"   - **Defer the commit of this section to the final pre-push\",\n      \"     step.** Pull the latest default branch before inserting, insert\",\n      \"     only your own entry, and if a concurrent sibling already landed\",\n      \"     a bullet, rebase and re-insert. Commit this shared list section\",\n      \"     on its own at the end, then push immediately.\",\n      \"\",\n      \"4. **Create `req:scan` issues** for each capability gap identified.\",\n      \"   Each issue hands off to the `requirements-analyst` bundle so its\",\n      \"   scan phase can deduplicate and open `req:write` issues in the\",\n      \"   SEC category. Each issue must carry:\",\n      \"\",\n      \"   - `type:requirement`\",\n      \"   - `req:scan`\",\n      `   - \\`priority:${labelsForPhase(issueDefaults, \"req:scan\").priority}\\``,\n      `   - \\`status:${labelsForPhase(issueDefaults, \"req:scan\").status}\\``,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"   The body must also:\",\n      \"   - Identify the target category as **SEC** (security & compliance)\",\n      \"     in the body so the downstream writer phase picks up the right\",\n      \"     template\",\n      \"   - Link back to the regulation page and cite the triggering\",\n      \"     requirement\",\n      \"   - Escalate the priority above the bundle default when the\",\n      \"     regulation is already in force and the gap is unmitigated\",\n      \"\",\n      \"5. **Create `company:research` issues** for any enforcement body\",\n      \"   mentioned on the regulation page that does not already have a\",\n      \"   canonical profile or an open `company:research` issue. Each\",\n      \"   issue must carry:\",\n      \"\",\n      \"   - `type:company-profile`\",\n      \"   - `company:research`\",\n      `   - \\`priority:${labelsForPhase(issueDefaults, \"company:research\").priority}\\``,\n      `   - \\`status:${labelsForPhase(issueDefaults, \"company:research\").status}\\``,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"6. **Create `people:research` issues** for notable regulatory\",\n      \"   leaders (commissioners, agency directors, lead policy authors)\",\n      \"   mentioned on the regulation page. Keep this list small — at most\",\n      \"   three individuals per impact session — and skip anyone already\",\n      \"   profiled or queued. Each issue must carry:\",\n      \"\",\n      \"   - `type:people-profile`\",\n      \"   - `people:research`\",\n      `   - \\`priority:${labelsForPhase(issueDefaults, \"people:research\").priority}\\``,\n      `   - \\`status:${labelsForPhase(issueDefaults, \"people:research\").status}\\``,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"7. **Commit and push** the updated regulation page. Close the\",\n      `   impact issue ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Coordination with Other Agents\",\n      \"\",\n      \"### Upstream: research-pipeline, industry-discovery, standards-research\",\n      \"\",\n      \"Industry, research-pipeline, and standards-research deliverables may\",\n      \"reference regulations without scoping them. A human opens a\",\n      \"`regulatory:scan` issue for the relevant scope to start the\",\n      \"pipeline. This agent never auto-creates `regulatory:scan` issues —\",\n      \"scan is a human-authored starting point.\",\n      \"\",\n      \"### Downstream: requirements-analyst bundle\",\n      \"\",\n      \"Phase 3 (Impact) hands off actionable obligations to the\",\n      \"`requirements-analyst` bundle via `req:scan` issues. The body of\",\n      \"each handoff issue identifies the target category as **SEC**\",\n      \"(security & compliance) so the downstream `requirements-writer`\",\n      \"phase picks up the right template. This agent never writes\",\n      \"requirement documents itself.\",\n      \"\",\n      \"### Downstream: company-profile bundle\",\n      \"\",\n      \"This agent creates `company:research` issues for enforcement bodies\",\n      \"and regulator agencies surfaced during research (Phase 2) or impact\",\n      \"(Phase 3). The `company-profile` bundle's Phase 1 (research)\",\n      \"consumes those issues and produces the canonical profile. This\",\n      \"agent never writes canonical company profiles itself.\",\n      \"\",\n      \"### Downstream: people-profile bundle\",\n      \"\",\n      \"This agent creates `people:research` issues for notable regulatory\",\n      \"leaders surfaced during impact analysis. The `people-profile`\",\n      \"bundle's Phase 1 (research) consumes those issues and produces the\",\n      \"canonical profile. This agent never writes canonical people\",\n      \"profiles itself.\",\n      \"\",\n      \"### File Boundaries\",\n      \"\",\n      \"- **Reads:**\",\n      \"  - `<REGULATORY_ROOT>/` — prior scan reports, regulation pages, and\",\n      \"    impact analyses\",\n      \"  - `<SCAN_DIR>/` — scan reports\",\n      \"  - `<docsRoot>/` — project context, industry-research,\",\n      \"    customer-research, and standards-research trees for framing\",\n      \"    context\",\n      \"- **Writes:**\",\n      \"  - `<SCAN_DIR>/regulatory-<SCOPE_SLUG>-<YYYY-MM-DD>.md` (Phase 1)\",\n      \"  - `<SCOPE_INDEX_PAGE>` (Phase 1)\",\n      \"  - `<REGULATION_PAGE>` (Phases 2 and 3 — Phase 3 appends `## Impact`)\",\n      \"- **Never writes to:**\",\n      \"  - Any canonical company-profile or people-profile path (the\",\n      \"    `company-profile` and `people-profile` bundles own those)\",\n      \"  - `<BCM_DOC_ROOT>/` (the `bcm-writer` bundle owns this)\",\n      \"  - `<REQUIREMENTS_ROOT>/` (the `requirements-writer` bundle owns\",\n      \"    this)\",\n      \"  - `<BUSINESS_MODELS_ROOT>/` (the `business-models` bundle owns\",\n      \"    this)\",\n      \"  - `<STANDARDS_ROOT>/` (the `standards-research` bundle owns this)\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Blocked Issues\",\n      \"\",\n      \"Follow your project's shared Blocked Issues procedure. Additional\",\n      \"block reasons specific to regulatory research:\",\n      \"\",\n      \"- **Regulation text behind a paywall or login.** The agent cannot\",\n      \"  access the authoritative content.\",\n      \"- **Conflicting regulator guidance.** Two or more authoritative\",\n      \"  sources disagree on a material requirement; human legal review is\",\n      \"  needed.\",\n      \"- **Pending or proposed regulation.** Rapidly changing draft content\",\n      \"  that would be out-of-date before the PR merges.\",\n      \"- **Ambiguous applicability.** The agent cannot determine whether a\",\n      \"  regulation applies to the consuming project or its customers\",\n      \"  without a human decision.\",\n      \"- **Impact issue arrived before research completed.** Phase 3 blocks\",\n      \"  on the Phase 2 research issue closing.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Rules\",\n      \"\",\n      \"- **One phase per session.** Never run two phases back-to-back in a\",\n      \"  single session.\",\n      \"- **One regulation per research session.** Phase 2 is scoped to\",\n      \"  exactly one regulation — never research multiple regulations at\",\n      \"  once.\",\n      \"- **Persist before closing.** Every phase must write its output file\",\n      \"  before closing its issue.\",\n      \"- **Search budgets are caps, not targets.** Do not exceed 8\",\n      \"  searches in scan, 12 in research, or 0 in impact.\",\n      \"- **Cite specific sections.** Every regulatory requirement must cite\",\n      \"  the specific section, article, clause, or paragraph number.\",\n      \"- **No legal interpretation.** Document what the regulation says,\",\n      \"  not what it means. When interpretation is ambiguous, flag the\",\n      \"  ambiguity as an open question and block.\",\n      \"- **Tier 1 required for citations.** Every requirement in the Key\",\n      \"  Requirements table needs at least one Tier 1 source.\",\n      \"- **No fabrication.** Every claim in a scan report, regulation\",\n      \"  page, or impact analysis must trace to a cited source. Do not\",\n      \"  populate from general knowledge alone.\",\n      \"- **Relative links only.** Cross-references between docs use\",\n      \"  relative markdown paths, never absolute `https://github.com/...`\",\n      \"  URLs.\",\n      \"- **Never cross agent boundaries.** Do not write canonical company\",\n      \"  or people profiles, requirement documents, capability models,\",\n      \"  business-model canvases, or standards-research pages. Hand off\",\n      \"  surfaced work via `company:research`, `people:research`, or\",\n      \"  `req:scan` issues.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off the scan phase of a regulatory-research campaign. */\nfunction buildScanRegulatoryLandscapeSkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"scan-regulatory-landscape\",\n    description:\n      \"Kick off the scan phase of a regulatory-research campaign. Creates a regulatory:scan issue for the supplied scope (industry, jurisdiction, or platform) and dispatches Phase 1 of the regulatory-research-analyst, which writes a scan report and creates downstream regulatory:research issues.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"regulatory-research-analyst\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Scan Regulatory Landscape\",\n      \"\",\n      \"Kick off a regulatory-research campaign for a given scope — an\",\n      \"industry, a jurisdiction, or the consuming project's platform\",\n      \"itself. Creates a `regulatory:scan` issue carrying the scope\",\n      \"identifier and dispatches Phase 1 (Scan) in the\",\n      \"regulatory-research-analyst agent.\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/scan-regulatory-landscape <scope-slug>\",\n      \"\",\n      \"Optional extensions in the issue body:\",\n      \"- `scope_type: <industry | jurisdiction | platform>` — defaults to\",\n      \"  `industry`\",\n      \"- `scope_name: <human-readable name>` — defaults to the slug\",\n      \"  prettified\",\n      \"- `jurisdictions: <list>` — specific jurisdiction levels to enumerate\",\n      \"- `include_regulations: <list>` — regulations that must be covered\",\n      \"- `exclude_regulations: <list>` — regulations to skip\",\n      \"- `sources: <list>` — additional authorized input paths (prior\",\n      \"  industry, customer, or standards research that references the\",\n      \"  scope)\",\n      \"\",\n      \"## Default Paths\",\n      \"\",\n      \"If the project has no override in\",\n      `\\`${paths.docsRoot}/project-context.md\\` or \\`agentConfig.rules\\`,`,\n      \"outputs land under:\",\n      \"\",\n      `- Scan report: \\`${paths.researchRoot}/regulatory/regulatory-<scope-slug>-<YYYY-MM-DD>.md\\``,\n      `- Scope index page: \\`${paths.docsRoot}/regulatory-research/<scope-slug>/index.md\\``,\n      `- Regulation pages (Phase 2): \\`${paths.docsRoot}/regulatory-research/<scope-slug>/<regulation-slug>.md\\``,\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `regulatory:scan` issue with `type:regulatory-research`,\",\n      `   \\`priority:${labelsForPhase(issueDefaults, \"regulatory:scan\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"regulatory:scan\").status}\\`. The body must include the`,\n      \"   scope slug, the scope type, and any known regulations to include\",\n      \"   or exclude.\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 1 (Scan) of the regulatory-research-analyst agent.\",\n      \"3. Phase 1 writes the scan report and creates one\",\n      \"   `regulatory:research` issue per prioritized regulation.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- A scan report under the project's research directory, listing\",\n      \"  applicable regulations by jurisdiction level and recommended\",\n      \"  research priorities.\",\n      \"- One `regulatory:research` issue per prioritized regulation.\",\n      \"- A scope index page under the regulatory-research tree.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off the research phase for one regulation. */\nfunction buildResearchRegulationSkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"research-regulation\",\n    description:\n      \"Kick off the research phase for one regulation. Creates a regulatory:research issue for the supplied scope and regulation and dispatches Phase 2 of the regulatory-research-analyst, which populates the regulation page with scope, triggers, key requirements, jurisdiction variations, enforcement, and penalties using the ship-with regulation-page template.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"regulatory-research-analyst\",\n    platforms: { cursor: { exclude: true } },\n    referenceFiles: REGULATORY_RESEARCH_REFERENCE_FILES,\n    instructions: [\n      \"# Research Regulation\",\n      \"\",\n      \"Author a regulation page for one regulation. Creates a\",\n      \"`regulatory:research` issue and dispatches Phase 2 (Research) in\",\n      \"the regulatory-research-analyst agent.\",\n      \"\",\n      \"Most campaigns do not invoke this skill directly — Phase 1 (Scan)\",\n      \"creates research issues automatically. Use this skill when:\",\n      \"\",\n      \"- A single regulation needs refreshed research without a full scan\",\n      \"- A new regulation was published after the last scan and needs to\",\n      \"  be folded into the tree\",\n      \"- The scan phase deferred a regulation and the blocker is now\",\n      \"  resolved\",\n      \"- Another agent (e.g. `standards-research`) flagged a mandated\",\n      \"  regulation that needs its own page\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/research-regulation <scope-slug>:<regulation-slug>\",\n      \"\",\n      \"Optional extensions in the issue body:\",\n      \"- `scan_report: <path>` — prior scan-phase report (optional when\",\n      \"  invoked manually)\",\n      \"- `jurisdiction: <federal | state | international | local>` —\",\n      \"  primary jurisdiction for the regulation\",\n      \"- `sources: <list>` — additional authorized input paths\",\n      \"\",\n      \"## Regulation-Page Template\",\n      \"\",\n      \"This skill ships a verbatim regulation-page template at\",\n      \"`.claude/skills/research-regulation/_references/templates/_template-regulation.md`.\",\n      \"The Phase 2 handler reads that file as its authoritative structure —\",\n      \"every regulation page copies the template and fills scope, triggers,\",\n      \"key requirements, jurisdiction variations, enforcement, penalties,\",\n      \"and traceability sections.\",\n      \"\",\n      \"## Default Paths\",\n      \"\",\n      \"If the project has no override in\",\n      `\\`${paths.docsRoot}/project-context.md\\` or \\`agentConfig.rules\\`,`,\n      \"the regulation page lands at:\",\n      \"\",\n      `\\`${paths.docsRoot}/regulatory-research/<scope-slug>/<regulation-slug>.md\\``,\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `regulatory:research` issue with\",\n      `   \\`type:regulatory-research\\`, \\`priority:${labelsForPhase(issueDefaults, \"regulatory:research\").priority}\\`, and`,\n      `   \\`status:${labelsForPhase(issueDefaults, \"regulatory:research\").status}\\`. The body must include the scope slug and the`,\n      \"   regulation slug.\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 2 (Research) of the regulatory-research-analyst\",\n      \"   agent. The agent runs 6–12 targeted web searches and populates\",\n      \"   the regulation page.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- A populated regulation page with scope, triggers, key\",\n      \"  requirements (with specific section citations), jurisdiction\",\n      \"  variations, enforcement, penalties, related regulations, and a\",\n      \"  cited sources section.\",\n      \"- One blocked `regulatory:impact` issue for the downstream Phase 3.\",\n      \"- `company:research` issues for enforcement bodies that do not yet\",\n      \"  have a canonical profile.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off the impact phase for one regulation. */\nfunction buildImpactRegulationSkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"impact-regulation\",\n    description:\n      \"Kick off the impact phase for one regulation. Creates a regulatory:impact issue for the supplied regulation and dispatches Phase 3 of the regulatory-research-analyst, which assesses product impact, documents capability gaps, and hands off each actionable obligation as a req:scan seed in the SEC (security & compliance) category for the requirements-analyst bundle to consume.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"regulatory-research-analyst\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Assess Regulation Impact\",\n      \"\",\n      \"Assess the impact of one regulation on the consuming project and\",\n      \"hand off each actionable obligation to the requirements pipeline\",\n      \"as a SEC (security & compliance) `req:scan` seed. Creates a\",\n      \"`regulatory:impact` issue and dispatches Phase 3 (Impact) in the\",\n      \"regulatory-research-analyst agent.\",\n      \"\",\n      \"Most campaigns do not invoke this skill directly — Phase 2\",\n      \"(Research) creates the impact issue automatically, blocked on the\",\n      \"research issue that spawned it. Use this skill when:\",\n      \"\",\n      \"- A regulation page was refreshed and the impact analysis needs a\",\n      \"  re-run\",\n      \"- A human authored the regulation page and needs the impact\",\n      \"  synthesized separately\",\n      \"- The impact phase was deferred and the research is now landed\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/impact-regulation <scope-slug>:<regulation-slug>\",\n      \"\",\n      \"Required extensions in the issue body:\",\n      \"- `regulation_page: <path>` — link to the research page being\",\n      \"  assessed\",\n      \"\",\n      \"## Default Paths\",\n      \"\",\n      \"If the project has no override in\",\n      `\\`${paths.docsRoot}/project-context.md\\` or \\`agentConfig.rules\\`,`,\n      \"the impact section is appended to the regulation page at:\",\n      \"\",\n      `\\`${paths.docsRoot}/regulatory-research/<scope-slug>/<regulation-slug>.md\\``,\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `regulatory:impact` issue with\",\n      `   \\`type:regulatory-research\\`, \\`priority:${labelsForPhase(issueDefaults, \"regulatory:impact\").priority}\\`, and`,\n      `   \\`status:${labelsForPhase(issueDefaults, \"regulatory:impact\").status}\\` (or \\`status:blocked\\` when still dependent on a`,\n      \"   Phase 2 research issue). Body must include the regulation page\",\n      \"   path.\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 3 (Impact) of the regulatory-research-analyst\",\n      \"   agent. No web searches — pure synthesis from the regulation\",\n      \"   page and project context.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- An `## Impact` section appended to the regulation page covering\",\n      \"  platform compliance, customer compliance support, capability\",\n      \"  gaps, and affected segments.\",\n      \"- One `req:scan` issue (consumed by the `requirements-analyst`\",\n      \"  bundle) per capability gap identified. Each handoff carries the\",\n      \"  SEC category in the body so the downstream `requirements-writer`\",\n      \"  phase picks up the `security/` template.\",\n      \"- Optional `company:research` and `people:research` issues for\",\n      \"  enforcement bodies and regulatory leaders not yet profiled.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/**\n * Regulatory-research bundle — enabled by default.\n *\n * Consuming projects can disable it with\n * `excludeBundles: [\"regulatory-research\"]`. `appliesWhen` always\n * returns `true` per the workflow-bundle peer-present assumption.\n *\n * Ships a sub-agent (`regulatory-research-analyst`), three\n * user-invocable skills (`/scan-regulatory-landscape`,\n * `/research-regulation`, `/impact-regulation`), a regulation-page\n * template (emitted alongside the research skill), and\n * `type:regulatory-research` plus `regulatory:*` phase labels.\n *\n * The bundle sits downstream of `research-pipeline`,\n * `industry-discovery`, and `standards-research` (which surface the\n * need for regulatory research) and hands off actionable obligations\n * to the `requirements-analyst` bundle via `req:scan` issues that\n * become SEC (security & compliance) requirements in the writer\n * pipeline, and canonical profiles to `company-profile` and\n * `people-profile` for enforcement bodies and regulatory leaders.\n */\nexport function buildRegulatoryResearchBundle(\n  paths: ResolvedAgentPaths = DEFAULT_AGENT_PATHS,\n  issueDefaults: ResolvedIssueDefaults = DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n): AgentRuleBundle {\n  return {\n    name: \"regulatory-research\",\n    description:\n      \"Regulatory compliance research pipeline: scan, research, impact. 3 phases with regulatory:* phase labels. Enumerates jurisdictional regulations by industry and activity, researches each in depth with specific section citations, and hands off actionable obligations to the requirements-analyst bundle as req:scan seeds that become SEC (security & compliance) requirements. Enabled by default; domain-neutral; documents obligations without interpreting them; filesystem-durable between phases.\",\n    appliesWhen: () => true,\n    rules: [\n      {\n        name: \"regulatory-research-workflow\",\n        description:\n          \"Describes the 3-phase regulatory-research pipeline, the regulatory:* label taxonomy, and the handoff boundaries with requirements-analyst (SEC req:scan seeds), company-profile, and people-profile.\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Regulatory Research Workflow\",\n          \"\",\n          \"Use `/scan-regulatory-landscape <scope-slug>` to kick off a\",\n          \"regulatory-research campaign. The pipeline runs in 3 phases —\",\n          \"scan, research, impact — each tracked by its own GitHub issue\",\n          \"labeled `regulatory:scan`, `regulatory:research`, or\",\n          \"`regulatory:impact`. All issues carry\",\n          \"`type:regulatory-research`.\",\n          \"\",\n          \"Two additional user-invocable skills drive the downstream\",\n          \"phases directly when the default pipeline needs to be entered\",\n          \"mid-stream:\",\n          \"\",\n          \"- `/research-regulation <scope>:<regulation>` — author one\",\n          \"  regulation page (normally created by the scan phase\",\n          \"  automatically).\",\n          \"- `/impact-regulation <scope>:<regulation>` — synthesize\",\n          \"  product impact and hand off SEC `req:scan` seeds to the\",\n          \"  `requirements-analyst` bundle (normally created by the\",\n          \"  research phase automatically).\",\n          \"\",\n          \"The bundle produces **scan reports, regulation pages, and\",\n          \"impact analyses**. It never writes requirement documents,\",\n          \"capability models, canonical profiles, business-model canvases,\",\n          \"or standards-research pages — surfaced work is delegated to the\",\n          \"`requirements-analyst`, `company-profile`, and `people-profile`\",\n          \"bundles via `req:scan`, `company:research`, and\",\n          \"`people:research` issues respectively. Each `req:scan` handoff\",\n          \"targets the **SEC (security & compliance)** category so the\",\n          \"downstream `requirements-writer` phase picks up the right\",\n          \"template.\",\n          \"\",\n          \"Consumer-specific regulatory landscapes (which industries,\",\n          \"jurisdictions, and regulations to cover) are supplied per-\",\n          `project via \\`${paths.docsRoot}/project-context.md\\` or the`,\n          \"invoking issue body. The bundle is domain-neutral — no\",\n          \"regulations, regulators, or jurisdictions are hardcoded.\",\n          \"\",\n          \"The bundle **documents** regulatory obligations; it does\",\n          \"**not** interpret them. Legal interpretation, compliance\",\n          \"strategy, and risk assessment are human responsibilities. When\",\n          \"regulation text is ambiguous or regulator guidance conflicts,\",\n          \"the agent flags the ambiguity as an open question and blocks —\",\n          \"it never guesses at the interpretation.\",\n          \"\",\n          \"See the `regulatory-research-analyst` agent definition for\",\n          \"full workflow details, default paths, configurable\",\n          \"placeholders, and phase-by-phase instructions.\",\n        ].join(\"\\n\"),\n        platforms: {\n          cursor: { exclude: true },\n        },\n        tags: [\"workflow\"],\n      },\n    ],\n    skills: [\n      buildScanRegulatoryLandscapeSkill(paths, issueDefaults),\n      buildResearchRegulationSkill(paths, issueDefaults),\n      buildImpactRegulationSkill(paths, issueDefaults),\n    ],\n    subAgents: [buildRegulatoryResearchAnalystSubAgent(paths, issueDefaults)],\n    labels: [\n      {\n        name: \"type:regulatory-research\",\n        color: \"5319E7\",\n        description:\n          \"Researches a regulatory obligation: jurisdictional scan, deep-dive, or impact analysis\",\n      },\n      {\n        name: \"regulatory:scan\",\n        color: \"C5DEF5\",\n        description:\n          \"Phase 1: enumerate regulations for an industry/jurisdiction/scope; create research issues\",\n      },\n      {\n        name: \"regulatory:research\",\n        color: \"BFDADC\",\n        description:\n          \"Phase 2: research one regulation in depth (scope, triggers, requirements, enforcement)\",\n      },\n      {\n        name: \"regulatory:impact\",\n        color: \"D4C5F9\",\n        description:\n          \"Phase 3: assess product impact and hand off SEC req:scan seeds to requirements-analyst\",\n      },\n    ],\n  };\n}\n\n/**\n * Default-paths instance of the regulatory-research bundle, preserved\n * for backward compatibility with consumers that import the const\n * directly. The factory above is the canonical entry point when a\n * consumer supplies `AgentConfigOptions.paths`.\n */\nexport const regulatoryResearchBundle: AgentRuleBundle =\n  buildRegulatoryResearchBundle();\n","/**\n * Shared prompt snippets describing the requirements taxonomy.\n *\n * The 11-category taxonomy (BR / FR / NFR / TR / ADR / SEC / DR / INT /\n * OPS / UX / MT), the four-tier architectural classification (Platform,\n * Industry, Customer Workflow, Consumer Application), and the\n * category-disambiguation rules (SEC vs NFR, TR vs ADR, FR vs INT, DR\n * vs SEC, NFR vs OPS) are consumed by multiple agent bundles. To keep\n * the writer, reviewer, and analyst bundles from drifting apart, all\n * three import these constants instead of restating the tables and\n * rules in their own prompt strings.\n *\n * Each export is a `ReadonlyArray<string>` so it can be spread directly\n * into a sub-agent `prompt` array. The snippets intentionally do **not**\n * include leading or trailing section dividers (`---`) — the consuming\n * bundle decides where these sections fit into its own prompt outline.\n *\n * See issue #408 for the consolidation rationale.\n */\n\n/**\n * The 11-category taxonomy table. Introduces the category grid used by\n * every requirement document and states that directory names are\n * defaults while category prefixes are universal.\n *\n * Consumers: `requirements-writer` and `requirements-reviewer` embed\n * this verbatim. The analyst references the table indirectly through\n * its \"respect the taxonomy\" note.\n */\nexport const REQUIREMENTS_TAXONOMY_TABLE_SECTION: ReadonlyArray<string> = [\n  \"## The 11-Category Taxonomy\",\n  \"\",\n  \"All requirements follow the BIZBOK-aligned 11-category taxonomy\",\n  \"below. Getting requirements into the right category matters because\",\n  \"it determines which template applies, which standards inform it, and\",\n  \"how it traces to other requirements.\",\n  \"\",\n  \"| Category | Prefix | Directory (default) | Question it answers |\",\n  \"|----------|--------|---------------------|---------------------|\",\n  \"| Business Requirements | BR | `business/` | **Why** are we building this? What business value does it deliver? |\",\n  \"| Functional Requirements | FR | `functional/` | **What** does the system do? What is the user-visible behavior? |\",\n  \"| Non-Functional Requirements | NFR | `non-functional/` | **How well** must the system perform? What quality bar must it meet? |\",\n  \"| Technical Requirements | TR | `technical/` | **What technology** are we using, and why that one? |\",\n  \"| Architectural Decisions | ADR | `architectural-decisions/` | **What structural decision** are we making, and what are the trade-offs? |\",\n  \"| Security & Compliance | SEC | `security/` | **What must we protect**, and what rules govern that protection? |\",\n  \"| Data Requirements | DR | `data/` | **What data** do we store, how long, and how do we recover it? |\",\n  \"| Integration Requirements | INT | `integration/` | **What external systems** do we connect to, and how? |\",\n  \"| Operational Requirements | OPS | `operational/` | **How do we deploy, monitor, and respond** to incidents? |\",\n  \"| UX Requirements | UX | `ux/` | **How must the interface look, feel, and behave** for users? |\",\n  \"| Multi-Tenancy & Licensing | MT | `multi-tenancy/` | **How do we isolate tenants, gate features, and meter usage?** |\",\n  \"\",\n  \"All requirement documents live under `<REQUIREMENTS_ROOT>` in the\",\n  \"category directory shown above. Directory names are defaults —\",\n  \"consuming projects may rename them, but the prefixes are universal.\",\n];\n\n/**\n * The full disambiguation rule bullets. Used when deciding which\n * category a requirement belongs to. Both the writer and the reviewer\n * (in its Categorization Accuracy check) apply the same rules to avoid\n * drift.\n *\n * The constant intentionally ships the bullets **without** a heading —\n * the writer wraps them in an `### Disambiguation Rules` section under\n * the 11-category taxonomy, while the reviewer threads them directly\n * into its Check 2 (Categorization Accuracy) prose. Keeping the heading\n * out of the shared snippet lets each consumer choose the right\n * heading level for its surrounding outline.\n */\nexport const REQUIREMENTS_TAXONOMY_DISAMBIGUATION_SECTION: ReadonlyArray<string> =\n  [\n    \"- **SEC vs NFR:** Protecting data, enforcing access control, or\",\n    \"  meeting a regulation → SEC. System performance, uptime, or\",\n    '  scalability → NFR. \"99.9% uptime\" is NFR; \"audit logs for all',\n    '  admin actions\" is SEC.',\n    '- **TR vs ADR:** A TR pins down a specific technology choice (\"use',\n    '  PostgreSQL 16+\"). An ADR records a structural decision with',\n    '  context, trade-offs, and alternatives (\"why row-level isolation',\n    '  over schema-per-tenant\"). TRs often follow from ADRs.',\n    \"- **FR vs INT:** What the user experiences → FR. How two systems\",\n    '  communicate → INT. \"User can pay with a credit card\" is FR;',\n    '  \"Stripe Checkout API integration for payment processing\" is INT.',\n    \"- **DR vs SEC:** What data exists, how long we keep it, and how we\",\n    \"  recover it → DR. Who can access it and how it's protected → SEC.\",\n    \"  These often cross-reference each other.\",\n    \"- **NFR vs OPS:** A measurable target the system must meet → NFR.\",\n    '  The tooling and processes to run the system → OPS. \"p99 latency',\n    '  < 200ms\" is NFR; \"Datadog APM for latency monitoring\" is OPS.',\n  ];\n\n/**\n * The four architectural tiers. Orthogonal to category — category\n * answers \"what kind\" while tier answers \"where in the architecture.\"\n *\n * Only the tier **table** lives here. The writer bundle owns the\n * prose that explains tier metadata fields (Customer, Implementor),\n * cross-tier traceability, and the `tier:*` issue labels — those are\n * writer-specific concerns that do not belong in the shared reference.\n */\nexport const REQUIREMENTS_TIER_TABLE_SECTION: ReadonlyArray<string> = [\n  \"| Tier | Slug | When to use |\",\n  \"|------|------|-------------|\",\n  \"| **Platform** | `platform` | Core platform services — APIs, tenant isolation, auth, event bus, shared infrastructure |\",\n  \"| **Industry** | `industry` | Vertical-specific capabilities not every tenant needs |\",\n  \"| **Customer Workflow** | `customer-workflow` | Business logic tenants configure within the platform — approval chains, notification rules, intake processes |\",\n  \"| **Consumer Application** | `consumer-app` | UI/UX and integrations in external front-ends/systems consuming the platform's APIs |\",\n];\n\n/**\n * The `req:write` issue body schema. Every bundle that opens a\n * `req:write` issue (the analyst's trace phase, the reviewer's review\n * and deprecation phases) **and** the writer bundle's intake step\n * embed this section verbatim so the three producers and the single\n * consumer never drift apart. The schema documents the three required\n * fields the writer parses, the one strongly-recommended\n * `Inputs / Read` field, and the `Missing:` escape hatch that upstream\n * producers use when a required field cannot be derived.\n *\n * Consumers embed the section under their own heading — the heading\n * is intentionally omitted here so each bundle can choose the right\n * outline level for its surrounding context.\n *\n * See issue #411 for the consolidation rationale.\n */\nexport const REQ_WRITE_ISSUE_SCHEMA_SECTION: ReadonlyArray<string> = [\n  \"The body of every `req:write` issue **must** declare the three\",\n  \"fields below. The downstream `requirements-writer` agent parses\",\n  \"them on intake and will refuse to write a document (and flag the\",\n  \"issue `status:needs-attention`) if any required field is missing\",\n  \"or contradictory.\",\n  \"\",\n  \"### Required Fields\",\n  \"\",\n  \"- **Category:** one of `BR` / `FR` / `NFR` / `TR` / `ADR` / `SEC` /\",\n  \"  `DR` / `INT` / `OPS` / `UX` / `MT`. Must match the category\",\n  \"  prefix in the requirement's title and file name.\",\n  \"- **Tier:** one of `platform` / `industry` / `customer-workflow` /\",\n  \"  `consumer-app`. Must match the `tier:*` label applied to the\",\n  \"  issue.\",\n  \"- **Output Path:** absolute-from-repo-root path ending in\",\n  \"  `<PREFIX>-<NNN>-<slug>.md` under the target category directory\",\n  \"  (for example,\",\n  \"  `docs/src/content/docs/requirements/functional/FR-012-checkout-flow.md`).\",\n  \"\",\n  \"### Strongly Recommended\",\n  \"\",\n  \"- **Requirement ID:** the reserved requirement ID (e.g.\",\n  \"  `FR-1240`), a HINT allocated at issue-creation. Optional —\",\n  \"  legacy issues may omit it. The writer re-validates and finalizes\",\n  \"  the ID at write-start (via `next-requirement-id.sh`) before\",\n  \"  authoring, so this field is advisory: if a concurrent claim took\",\n  \"  the reserved number, the writer authors under the freshly\",\n  \"  finalized ID instead and updates this field to match.\",\n  \"- **Inputs / Read:** bullet list of source files the writer should\",\n  \"  consult — the upstream proposal file (when one exists), the\",\n  \"  BCM/source document(s) the proposal cites, and any related\",\n  \"  requirements the new document should trace to. Omit only for\",\n  \"  ad-hoc requirements where no upstream proposal exists; the\",\n  \"  writer will then treat the issue body itself as the input.\",\n  \"\",\n  \"### Missing Fields\",\n  \"\",\n  \"When an upstream producer cannot derive one of the required\",\n  \"fields, it **must not** guess a value. Instead it opens the\",\n  \"`req:write` issue with `status:needs-attention` (not\",\n  \"`status:ready`) and includes a `Missing:` line listing the\",\n  \"field(s) that could not be determined. For example:\",\n  \"\",\n  \"```\",\n  \"Missing: Tier — source document has no tier metadata and the\",\n  \"referencing requirement is cross-tier.\",\n  \"```\",\n  \"\",\n  \"A human triages the issue, fills in the missing field, and flips\",\n  \"the label to `status:ready` before the writer picks it up.\",\n];\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { renderClaimVerificationSection } from \"./claim-verification\";\nimport {\n  DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n  ResolvedIssueDefaults,\n  labelsForPhase,\n} from \"./issue-defaults\";\nimport { renderIssueTypeAssignmentStep } from \"./issue-type\";\nimport { renderOriginStampSection } from \"./origin-label\";\nimport { DEFAULT_AGENT_PATHS, ResolvedAgentPaths } from \"./paths\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n  REQ_WRITE_ISSUE_SCHEMA_SECTION,\n  REQUIREMENTS_TAXONOMY_DISAMBIGUATION_SECTION,\n  REQUIREMENTS_TAXONOMY_TABLE_SECTION,\n  REQUIREMENTS_TIER_TABLE_SECTION,\n} from \"./requirements-taxonomy\";\nimport {\n  AGENT_MODEL,\n  AGENT_RULE_SCOPE,\n  AgentProcedure,\n  AgentSkill,\n  AgentSubAgent,\n} from \"../types\";\n\n/**\n * Verbatim BR (Business Requirement) template shipped to the consuming\n * project under the requirements-writer skill's reference directory.\n */\nconst templateBr = (paths: ResolvedAgentPaths): string => `---\ntitle: \"BR-NNN: [Business Requirement Title]\"\n---\n\n## Metadata\n\n| Field | Value |\n|---|---|\n| **ID** | BR-NNN |\n| **Status** | Draft |\n| **Tier** | [Platform · Industry · Customer Workflow · Consumer Application] |\n| **Implementor** | [Consortium Member · Customer · TBD — required for Customer Workflow and Consumer Application tiers. When Consortium Member, link to org profile] |\n| **Customer** | [Link to customer org profile if this requirement originated from or applies to a specific customer. Optional for Platform/Industry tiers, expected for Customer Workflow/Consumer Application tiers] |\n| **Priority** | [Critical / High / Medium / Low] |\n| **Owner** | [Name or role responsible for this requirement] |\n| **Created** | YYYY-MM-DD |\n| **Last Updated** | YYYY-MM-DD |\n\n## Business Need\n\nA clear statement of the business problem or opportunity this requirement addresses. Focus on the \"why\" — what pain point exists, what opportunity we're capturing, or what strategic goal this supports.\n\n## Stakeholders\n\n| Stakeholder | Role | Interest |\n|---|---|---|\n| [Name/Group] | [Their role] | [What they care about regarding this requirement] |\n\n## Success Metrics\n\nDefine how we'll know this requirement has been successfully met. Metrics should be specific and measurable.\n\n| Metric | Target | Measurement Method |\n|---|---|---|\n| [e.g., Onboarding completion rate] | [e.g., > 80% within 7 days] | [e.g., Analytics funnel tracking] |\n\n## Scope\n\n### In Scope\n\nWhat is explicitly included in this business requirement.\n\n### Out of Scope\n\nWhat is explicitly excluded — important for preventing scope creep and setting expectations.\n\n## Assumptions\n\nList assumptions that underpin this requirement. Flag any that carry risk if they turn out to be wrong.\n\n- [Assumption 1]\n- [Assumption 2]\n\n## Constraints\n\nBusiness-level constraints that bound this requirement (budget, timeline, regulatory, organizational).\n\n- [Constraint 1]\n- [Constraint 2]\n\n## Dependencies\n\nOther business requirements, external factors, or organizational decisions this requirement depends on.\n\n- [Dependency 1]\n- [Dependency 2]\n\n## Traceability\n\n- **Decomposes into:** [FR-NNN](../${paths.requirementCategoryDirs.functional}/FR-NNN-slug.md), [FR-NNN](../${paths.requirementCategoryDirs.functional}/FR-NNN-slug.md)\n- **Constrained by:** [NFR-NNN](../${paths.requirementCategoryDirs.nonFunctional}/NFR-NNN-slug.md)\n- **Related:** [SEC-NNN](../${paths.requirementCategoryDirs.security}/SEC-NNN-slug.md)\n- **Depends on (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [platform/industry requirement this depends on]\n- **Enables (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [customer-workflow/consumer-app requirement this enables]\n\n## Open Items\n\n### Identified Gaps\n\n[Document any missing functionality, unhandled edge cases, or incomplete aspects. Number each item and assign a priority (P0/P1/P2/P3). Call out interdependencies with other open items. If none, write \"None identified.\"]\n\n1. **[Gap title]** \\`[P0-P3]\\`\n   [Description of what's missing and why it matters.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Follow-up Questions\n\n[Document anything ambiguous or where the motivation/reasoning cannot be confidently inferred. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Question title]** \\`[P0-P3]\\`\n   [The question, with context on why the answer matters.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Contradictions & Inconsistencies\n\n[Document any conflicts with other requirements, code behavior, or documentation. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Contradiction title]** \\`[P0-P3]\\`\n   [Description of the conflict and what needs to be resolved.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n## Revision History\n\n| Date | Author | Change |\n|---|---|---|\n| YYYY-MM-DD | [Name] | Initial draft |\n`;\n\n/** Verbatim FR (Functional Requirement) template. */\nconst templateFr = (paths: ResolvedAgentPaths): string => `---\ntitle: \"FR-NNN: [Functional Requirement Title]\"\n---\n\n## Metadata\n\n| Field | Value |\n|---|---|\n| **ID** | FR-NNN |\n| **Status** | Draft |\n| **Tier** | [Platform · Industry · Customer Workflow · Consumer Application] |\n| **Implementor** | [Consortium Member · Customer · TBD — required for Customer Workflow and Consumer Application tiers. When Consortium Member, link to org profile] |\n| **Customer** | [Link to customer org profile if this requirement originated from or applies to a specific customer. Optional for Platform/Industry tiers, expected for Customer Workflow/Consumer Application tiers] |\n| **Priority** | [Must Have / Should Have / Could Have / Won't Have] |\n| **Owner** | [Name or role] |\n| **Created** | YYYY-MM-DD |\n| **Last Updated** | YYYY-MM-DD |\n\n## User Story\n\n**As a** [actor/role],\n**I want to** [action/capability],\n**So that** [business value/outcome].\n\n## Description\n\nA narrative description of this feature or behavior. Include enough context that someone unfamiliar with the project can understand what the system does and why it matters.\n\n## Actors\n\n| Actor | Description |\n|---|---|\n| [e.g., Registered User] | [Who they are and what access level they have] |\n\n## Preconditions\n\nConditions that must be true before this functionality can be used.\n\n- [Precondition 1]\n- [Precondition 2]\n\n## Main Flow\n\nThe primary happy-path sequence of interactions.\n\n1. [Step 1]\n2. [Step 2]\n3. [Step 3]\n\n## Alternative Flows\n\n### AF-1: [Alternative Flow Name]\n\n**Trigger:** [What causes this alternative path]\n\n1. [Step 1]\n2. [Step 2]\n\n### AF-2: [Alternative Flow Name]\n\n**Trigger:** [What causes this alternative path]\n\n1. [Step 1]\n2. [Step 2]\n\n## Exception Flows\n\n### EF-1: [Exception Flow Name]\n\n**Trigger:** [What error condition causes this]\n\n1. [Step 1 — how the system responds]\n2. [Step 2]\n\n## Acceptance Criteria\n\nSpecific, testable conditions that must be met for this requirement to be considered complete.\n\n- [ ] [Criterion 1 — stated as a concrete, verifiable condition]\n- [ ] [Criterion 2]\n- [ ] [Criterion 3]\n\n## Business Rules\n\nRules that govern the behavior described in this requirement.\n\n| Rule ID | Description |\n|---|---|\n| BIZ-01 | [e.g., Email addresses must be unique across the system] |\n| BIZ-02 | [e.g., Passwords must be at least 12 characters] |\n\n## UI/UX Considerations\n\nNotes on how this feature should present to the user. Reference UX requirements where applicable.\n\n## Data Requirements\n\nWhat data is created, read, updated, or deleted by this feature. Reference DR documents where applicable.\n\n## Traceability\n\n- **Implements:** [BR-NNN](../${paths.requirementCategoryDirs.business}/BR-NNN-slug.md)\n- **Constrained by:** [NFR-NNN](../${paths.requirementCategoryDirs.nonFunctional}/NFR-NNN-slug.md)\n- **Related:** [INT-NNN](../${paths.requirementCategoryDirs.integration}/INT-NNN-slug.md)\n- **Depends on (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [platform/industry requirement this depends on]\n- **Enables (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [customer-workflow/consumer-app requirement this enables]\n\n## Open Items\n\n### Identified Gaps\n\n[Document any missing functionality, unhandled edge cases, or incomplete aspects. Number each item and assign a priority (P0/P1/P2/P3). Call out interdependencies with other open items. If none, write \"None identified.\"]\n\n1. **[Gap title]** \\`[P0-P3]\\`\n   [Description of what's missing and why it matters.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Follow-up Questions\n\n[Document anything ambiguous or where the motivation/reasoning cannot be confidently inferred. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Question title]** \\`[P0-P3]\\`\n   [The question, with context on why the answer matters.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Contradictions & Inconsistencies\n\n[Document any conflicts with other requirements, code behavior, or documentation. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Contradiction title]** \\`[P0-P3]\\`\n   [Description of the conflict and what needs to be resolved.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n## Revision History\n\n| Date | Author | Change |\n|---|---|---|\n| YYYY-MM-DD | [Name] | Initial draft |\n`;\n\n/** Verbatim NFR (Non-Functional Requirement) template. */\nconst templateNfr = (paths: ResolvedAgentPaths): string => `---\ntitle: \"NFR-NNN: [Non-Functional Requirement Title]\"\n---\n\n## Metadata\n\n| Field | Value |\n|---|---|\n| **ID** | NFR-NNN |\n| **Status** | Draft |\n| **Tier** | [Platform · Industry · Customer Workflow · Consumer Application] |\n| **Implementor** | [Consortium Member · Customer · TBD — required for Customer Workflow and Consumer Application tiers. When Consortium Member, link to org profile] |\n| **Customer** | [Link to customer org profile if this requirement originated from or applies to a specific customer. Optional for Platform/Industry tiers, expected for Customer Workflow/Consumer Application tiers] |\n| **Quality Attribute** | [Performance / Reliability / Scalability / Maintainability / Portability / Availability] |\n| **Priority** | [Critical / High / Medium / Low] |\n| **Owner** | [Name or role] |\n| **Created** | YYYY-MM-DD |\n| **Last Updated** | YYYY-MM-DD |\n\n## Description\n\nWhat quality attribute this requirement addresses and why it matters for the system.\n\n## Measurable Targets\n\nNon-functional requirements must have numeric, measurable targets — vague statements like \"the system should be fast\" are not acceptable.\n\n| Metric | Target | Measurement Method | Measurement Frequency |\n|---|---|---|---|\n| [e.g., API response time (p99)] | [e.g., < 200ms] | [e.g., Datadog APM percentile tracking] | [e.g., Continuous] |\n| [e.g., System availability] | [e.g., 99.9% monthly] | [e.g., Uptime monitoring (Pingdom/UptimeRobot)] | [e.g., Monthly] |\n\n## Current Baseline\n\nIf this is being applied to an existing system, document the current measured values so improvement can be tracked.\n\n| Metric | Current Value | Date Measured |\n|---|---|---|\n| [Metric] | [Current value or \"Not yet measured\"] | [Date] |\n\n## Rationale\n\nWhy this target was chosen. What business need or user expectation drives this number? What are the consequences of not meeting it?\n\n## Applicable Scope\n\nWhich parts of the system does this requirement apply to? Be specific — \"all API endpoints\" or \"the checkout flow\" rather than \"the system.\"\n\n## Approach\n\nHigh-level approach for meeting this target. Reference ADRs and TRs for implementation details.\n\n## Monitoring & Alerting\n\nHow compliance with this requirement will be monitored in production. Reference OPS requirements where applicable.\n\n| Alert Condition | Threshold | Action |\n|---|---|---|\n| [e.g., p99 latency exceeds target] | [e.g., > 200ms for 5 minutes] | [e.g., Page on-call engineer] |\n\n## Traceability\n\n- **Supports:** [BR-NNN](../${paths.requirementCategoryDirs.business}/BR-NNN-slug.md)\n- **Constrains:** [FR-NNN](../${paths.requirementCategoryDirs.functional}/FR-NNN-slug.md)\n- **Monitored by:** [OPS-NNN](../${paths.requirementCategoryDirs.operational}/OPS-NNN-slug.md)\n- **Depends on (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [platform/industry requirement this depends on]\n- **Enables (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [customer-workflow/consumer-app requirement this enables]\n\n## Open Items\n\n### Identified Gaps\n\n[Document any missing functionality, unhandled edge cases, or incomplete aspects. Number each item and assign a priority (P0/P1/P2/P3). Call out interdependencies with other open items. If none, write \"None identified.\"]\n\n1. **[Gap title]** \\`[P0-P3]\\`\n   [Description of what's missing and why it matters.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Follow-up Questions\n\n[Document anything ambiguous or where the motivation/reasoning cannot be confidently inferred. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Question title]** \\`[P0-P3]\\`\n   [The question, with context on why the answer matters.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Contradictions & Inconsistencies\n\n[Document any conflicts with other requirements, code behavior, or documentation. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Contradiction title]** \\`[P0-P3]\\`\n   [Description of the conflict and what needs to be resolved.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n## Revision History\n\n| Date | Author | Change |\n|---|---|---|\n| YYYY-MM-DD | [Name] | Initial draft |\n`;\n\n/** Verbatim TR (Technical Requirement) template. */\nconst templateTr = (paths: ResolvedAgentPaths): string => `---\ntitle: \"TR-NNN: [Technical Requirement Title]\"\n---\n\n## Metadata\n\n| Field | Value |\n|---|---|\n| **ID** | TR-NNN |\n| **Status** | Draft |\n| **Tier** | [Platform · Industry · Customer Workflow · Consumer Application] |\n| **Implementor** | [Consortium Member · Customer · TBD — required for Customer Workflow and Consumer Application tiers. When Consortium Member, link to org profile] |\n| **Customer** | [Link to customer org profile if this requirement originated from or applies to a specific customer. Optional for Platform/Industry tiers, expected for Customer Workflow/Consumer Application tiers] |\n| **Category** | [Language / Framework / Database / Infrastructure / Library / Tool] |\n| **Owner** | [Name or role] |\n| **Created** | YYYY-MM-DD |\n| **Last Updated** | YYYY-MM-DD |\n\n## Technology Choice\n\nWhen **Accepted**: Fill in the selected technology.\n\nWhen **Proposed**: Write \"Pending human review. See Recommendation below.\" and leave Version/License/Vendor as TBD.\n\n| Field | Value |\n|---|---|\n| **Technology** | [e.g., PostgreSQL] |\n| **Version** | [e.g., 16+ (observed: 16-alpine at time of documentation). Version will naturally drift upward through routine maintenance.] |\n| **License** | [e.g., PostgreSQL License (permissive, OSI-approved)] |\n| **Vendor/Maintainer** | [e.g., PostgreSQL Global Development Group] |\n\n## Alternatives Considered\n\nList every viable technology option, including the recommended one. Each alternative gets the same level of analysis.\n\n### Option 1: [Technology Name]\n\n**Description:** [What this technology is and how it would be used]\n\n**Pros:**\n- [Pro 1]\n- [Pro 2]\n\n**Cons:**\n- [Con 1]\n- [Con 2]\n\n**License:** [License type]\n**Maturity:** [Established / Growing / Emerging]\n\n### Option 2: [Technology Name]\n\n**Description:** [What this technology is and how it would be used]\n\n**Pros:**\n- [Pro 1]\n\n**Cons:**\n- [Con 1]\n\n**License:** [License type]\n**Maturity:** [Established / Growing / Emerging]\n\n## Recommendation\n\n**Recommended option:** [Name of the recommended technology]\n\n**Why this option:** [A well-reasoned explanation of why this technology best fits the context, constraints, and goals. Address the key trade-offs honestly — explain why the cons are acceptable and why other options were not preferred.]\n\n**Key trade-offs accepted:** [What you're giving up by choosing this option over others]\n\nWhen the status is \\`Proposed\\`, this section frames the decision for the human reviewer. When \\`Accepted\\`, this section documents the reasoning behind the choice.\n\n## Rationale\n\nWhen **Accepted**: Summarize why this technology was selected. Reference the ADR that records the decision process if one exists.\n\nWhen **Proposed**: Write \"See Recommendation above. Awaiting human decision.\"\n\n## Usage Context\n\nHow and where this technology is used in the system. Be specific about which components or layers depend on it.\n\n## Version Constraints\n\nAny version pinning, upgrade policies, or compatibility requirements. Assume versions will drift upward over time through routine maintenance unless there is a specific reason to pin.\n\n- **Minimum version:** [version — the floor below which compatibility is not guaranteed]\n- **Observed version:** [version at time of documentation]\n- **Maximum version:** [version or \"latest stable\" — only specify if there's a known ceiling]\n- **Upgrade policy:** [e.g., \"Track latest minor releases within 30 days; major version upgrades require ADR\"]\n- **Version-sensitive notes:** [Any specific features or APIs used that depend on this version floor — helps future developers understand what might break if they don't meet the minimum]\n\n## Configuration Standards\n\nKey configuration decisions, defaults, or standards that apply to this technology across the project.\n\n## Dependencies & Compatibility\n\nOther technologies this choice interacts with, and any known compatibility constraints.\n\n| Dependency | Relationship | Constraint |\n|---|---|---|\n| [e.g., Node.js runtime] | [Required by] | [e.g., v18 LTS or later] |\n\n## Risks & Mitigations\n\n| Risk | Likelihood | Impact | Mitigation |\n|---|---|---|---|\n| [e.g., Vendor discontinues support] | [Low/Medium/High] | [Low/Medium/High] | [e.g., Open-source, community-maintained] |\n\n## Traceability\n\n- **Justified by:** [ADR-NNN](../${paths.requirementCategoryDirs.architecturalDecisions}/ADR-NNN-slug.md)\n- **Supports:** [FR-NNN](../${paths.requirementCategoryDirs.functional}/FR-NNN-slug.md)\n- **Constrained by:** [NFR-NNN](../${paths.requirementCategoryDirs.nonFunctional}/NFR-NNN-slug.md)\n- **Depends on (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [platform/industry requirement this depends on]\n- **Enables (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [customer-workflow/consumer-app requirement this enables]\n\n## Open Items\n\n### Identified Gaps\n\n[Document any missing functionality, unhandled edge cases, or incomplete aspects. Number each item and assign a priority (P0/P1/P2/P3). Call out interdependencies with other open items. If none, write \"None identified.\"]\n\n1. **[Gap title]** \\`[P0-P3]\\`\n   [Description of what's missing and why it matters.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Follow-up Questions\n\n[Document anything ambiguous or where the motivation/reasoning cannot be confidently inferred. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Question title]** \\`[P0-P3]\\`\n   [The question, with context on why the answer matters.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Contradictions & Inconsistencies\n\n[Document any conflicts with other requirements, code behavior, or documentation. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Contradiction title]** \\`[P0-P3]\\`\n   [Description of the conflict and what needs to be resolved.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n## Revision History\n\n| Date | Author | Change |\n|---|---|---|\n| YYYY-MM-DD | [Name] | Initial draft |\n`;\n\n/** Verbatim ADR (Architectural Decision Record) template. */\nconst templateAdr = (paths: ResolvedAgentPaths): string => `---\ntitle: \"ADR-NNN: [Decision Title]\"\n---\n\n## Metadata\n\n| Field | Value |\n|---|---|\n| **ID** | ADR-NNN |\n| **Status** | Draft |\n| **Tier** | [Platform · Industry · Customer Workflow · Consumer Application] |\n| **Implementor** | [Consortium Member · Customer · TBD — required for Customer Workflow and Consumer Application tiers. When Consortium Member, link to org profile] |\n| **Customer** | [Link to customer org profile if this requirement originated from or applies to a specific customer. Optional for Platform/Industry tiers, expected for Customer Workflow/Consumer Application tiers] |\n| **Decision Date** | YYYY-MM-DD |\n| **Decision Makers** | [Names or roles involved in the decision] |\n| **Created** | YYYY-MM-DD |\n| **Last Updated** | YYYY-MM-DD |\n\n## Context\n\nWhat is the issue that we're seeing that motivates this decision or change? What forces are at play — technical constraints, business pressures, team capabilities, timeline?\n\n## Decision\n\nWhen **Accepted**: State the architectural decision clearly and concisely. Start with \"We will...\" or \"We have decided to...\"\n\nWhen **Proposed**: Write \"Pending human review. See Recommendation below.\" Do not make the decision — present the analysis so a human can decide.\n\n## Alternatives Considered\n\nList every viable option, including the recommended one. Each alternative gets the same level of analysis — do not shortchange options you don't prefer.\n\n### Alternative 1: [Name]\n\n**Description:** [What this alternative entails — enough detail to evaluate it]\n\n**Pros:**\n- [Pro 1]\n- [Pro 2]\n\n**Cons:**\n- [Con 1]\n- [Con 2]\n\n### Alternative 2: [Name]\n\n**Description:** [What this alternative entails]\n\n**Pros:**\n- [Pro 1]\n\n**Cons:**\n- [Con 1]\n\n## Recommendation\n\n**Recommended option:** [Name of the recommended alternative]\n\n**Why this option:** [A well-reasoned explanation of why this alternative best fits the context, constraints, and goals. Address the key trade-offs honestly — explain why the cons of the recommended option are acceptable and why the pros of rejected alternatives don't outweigh their cons in this context.]\n\n**Key trade-offs accepted:** [What you're giving up by choosing this option over others]\n\nWhen the status is \\`Proposed\\`, this section frames the decision for the human reviewer. When \\`Accepted\\`, this section documents the reasoning behind the choice.\n\n## Consequences\n\n### Positive\n\n- [Positive consequence 1]\n- [Positive consequence 2]\n\n### Negative\n\n- [Negative consequence 1 — every decision has trade-offs; document them honestly]\n- [Negative consequence 2]\n\n### Neutral\n\n- [Neutral observation about what changes as a result of this decision]\n\n## Compliance & Constraints\n\nAny regulatory, security, or organizational constraints that influenced this decision.\n\n## Implementation Notes\n\nHigh-level guidance for implementing this decision. Detailed implementation goes in TR and FR documents.\n\n## Traceability\n\n- **Supports:** [BR-NNN](../${paths.requirementCategoryDirs.business}/BR-NNN-slug.md)\n- **Implemented by:** [TR-NNN](../${paths.requirementCategoryDirs.technical}/TR-NNN-slug.md)\n- **Related:** [ADR-NNN](ADR-NNN-slug.md)\n- **Depends on (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [platform/industry requirement this depends on]\n- **Enables (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [customer-workflow/consumer-app requirement this enables]\n\n## Open Items\n\n### Identified Gaps\n\n[Document any missing functionality, unhandled edge cases, or incomplete aspects. Number each item and assign a priority (P0/P1/P2/P3). Call out interdependencies with other open items. If none, write \"None identified.\"]\n\n1. **[Gap title]** \\`[P0-P3]\\`\n   [Description of what's missing and why it matters.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Follow-up Questions\n\n[Document anything ambiguous or where the motivation/reasoning cannot be confidently inferred. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Question title]** \\`[P0-P3]\\`\n   [The question, with context on why the answer matters.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Contradictions & Inconsistencies\n\n[Document any conflicts with other requirements, code behavior, or documentation. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Contradiction title]** \\`[P0-P3]\\`\n   [Description of the conflict and what needs to be resolved.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n## Revision History\n\n| Date | Author | Change |\n|---|---|---|\n| YYYY-MM-DD | [Name] | Initial draft |\n`;\n\n/** Verbatim SEC (Security & Compliance) template. */\nconst templateSec = (paths: ResolvedAgentPaths): string => `---\ntitle: \"SEC-NNN: [Security Requirement Title]\"\n---\n\n## Metadata\n\n| Field | Value |\n|---|---|\n| **ID** | SEC-NNN |\n| **Status** | Draft |\n| **Tier** | [Platform · Industry · Customer Workflow · Consumer Application] |\n| **Implementor** | [Consortium Member · Customer · TBD — required for Customer Workflow and Consumer Application tiers. When Consortium Member, link to org profile] |\n| **Customer** | [Link to customer org profile if this requirement originated from or applies to a specific customer. Optional for Platform/Industry tiers, expected for Customer Workflow/Consumer Application tiers] |\n| **Security Domain** | [Authentication / Authorization / Data Protection / Audit / Compliance / Network / Input Validation] |\n| **Priority** | [Critical / High / Medium / Low] |\n| **Owner** | [Name or role] |\n| **Created** | YYYY-MM-DD |\n| **Last Updated** | YYYY-MM-DD |\n\n## Description\n\nWhat security concern this requirement addresses and why it matters.\n\n## Threat Model Reference\n\nWhat threats does this requirement mitigate? Reference any formal threat modeling artifacts if they exist.\n\n| Threat | STRIDE Category | Severity | This Requirement Mitigates |\n|---|---|---|---|\n| [e.g., Unauthorized access to tenant data] | [e.g., Elevation of Privilege] | [Critical/High/Medium/Low] | [How] |\n\n## Requirements\n\n### Controls\n\nSpecific security controls that must be implemented.\n\n| Control ID | Description | OWASP ASVS Ref | NIST 800-53 Ref |\n|---|---|---|---|\n| [e.g., SEC-001-C1] | [e.g., All passwords hashed with bcrypt, cost factor ≥ 12] | [e.g., V2.4.1] | [e.g., IA-5(1)] |\n\n### Policies\n\nOrganizational or procedural security policies this requirement enforces.\n\n- [Policy 1]\n- [Policy 2]\n\n## Applicable Regulations\n\n| Regulation | Requirement | How We Comply |\n|---|---|---|\n| [e.g., SOC 2 Type II] | [e.g., Access controls and audit logging] | [e.g., RBAC + immutable audit log] |\n| [e.g., GDPR] | [e.g., Data encryption at rest] | [e.g., AES-256 via AWS KMS] |\n\n## Validation Approach\n\nHow compliance with this security requirement will be verified.\n\n| Method | Frequency | Responsible Party |\n|---|---|---|\n| [e.g., Automated security scan] | [e.g., Every CI build] | [e.g., DevOps] |\n| [e.g., Penetration test] | [e.g., Annually] | [e.g., External vendor] |\n\n## Acceptance Criteria\n\n- [ ] [Specific, verifiable security condition]\n- [ ] [e.g., No passwords stored in plaintext anywhere in the system]\n- [ ] [e.g., All API endpoints require authentication except explicitly whitelisted public routes]\n\n## Traceability\n\n- **Protects:** [FR-NNN](../${paths.requirementCategoryDirs.functional}/FR-NNN-slug.md)\n- **Constrained by:** [NFR-NNN](../${paths.requirementCategoryDirs.nonFunctional}/NFR-NNN-slug.md)\n- **Implements:** [BR-NNN](../${paths.requirementCategoryDirs.business}/BR-NNN-slug.md)\n- **Related data:** [DR-NNN](../${paths.requirementCategoryDirs.data}/DR-NNN-slug.md)\n- **Depends on (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [platform/industry requirement this depends on]\n- **Enables (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [customer-workflow/consumer-app requirement this enables]\n\n## Open Items\n\n### Identified Gaps\n\n[Document any missing functionality, unhandled edge cases, or incomplete aspects. Number each item and assign a priority (P0/P1/P2/P3). Call out interdependencies with other open items. If none, write \"None identified.\"]\n\n1. **[Gap title]** \\`[P0-P3]\\`\n   [Description of what's missing and why it matters.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Follow-up Questions\n\n[Document anything ambiguous or where the motivation/reasoning cannot be confidently inferred. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Question title]** \\`[P0-P3]\\`\n   [The question, with context on why the answer matters.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Contradictions & Inconsistencies\n\n[Document any conflicts with other requirements, code behavior, or documentation. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Contradiction title]** \\`[P0-P3]\\`\n   [Description of the conflict and what needs to be resolved.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n## Revision History\n\n| Date | Author | Change |\n|---|---|---|\n| YYYY-MM-DD | [Name] | Initial draft |\n`;\n\n/** Verbatim DR (Data Requirement) template. */\nconst templateDr = (paths: ResolvedAgentPaths): string => `---\ntitle: \"DR-NNN: [Data Requirement Title]\"\n---\n\n## Metadata\n\n| Field | Value |\n|---|---|\n| **ID** | DR-NNN |\n| **Status** | Draft |\n| **Tier** | [Platform · Industry · Customer Workflow · Consumer Application] |\n| **Implementor** | [Consortium Member · Customer · TBD — required for Customer Workflow and Consumer Application tiers. When Consortium Member, link to org profile] |\n| **Customer** | [Link to customer org profile if this requirement originated from or applies to a specific customer. Optional for Platform/Industry tiers, expected for Customer Workflow/Consumer Application tiers] |\n| **Data Domain** | [e.g., User Data / Transaction Data / Configuration / Audit Logs / Media Assets] |\n| **Classification** | [Public / Internal / Confidential / Restricted] |\n| **Owner** | [Name or role] |\n| **Created** | YYYY-MM-DD |\n| **Last Updated** | YYYY-MM-DD |\n\n## Description\n\nWhat data this requirement governs, why it exists, and its significance to the system.\n\n## Data Model\n\nDescribe the key entities, their attributes, and relationships. Include an entity-relationship summary or reference a diagram.\n\n| Entity | Key Attributes | Relationships |\n|---|---|---|\n| [e.g., User] | [e.g., id, email, name, created_at] | [e.g., Has many Organizations (via membership)] |\n\n## Data Lifecycle\n\n| Phase | Description | Duration |\n|---|---|---|\n| Creation | [How and when this data is created] | — |\n| Active Use | [How this data is used during normal operations] | [e.g., Indefinite while account active] |\n| Archival | [If/how data is archived after active use] | [e.g., After 12 months of inactivity] |\n| Deletion | [When and how data is permanently removed] | [e.g., 90 days after account closure] |\n\n## Retention Policy\n\n| Data Type | Retention Period | Legal Basis | Deletion Method |\n|---|---|---|---|\n| [e.g., User profile data] | [e.g., Account lifetime + 90 days] | [e.g., Contractual obligation] | [e.g., Soft delete → hard delete after retention] |\n| [e.g., Audit logs] | [e.g., 7 years] | [e.g., SOC 2 compliance] | [e.g., Automated purge] |\n\n## Backup & Recovery\n\n| Parameter | Value |\n|---|---|\n| **RPO (Recovery Point Objective)** | [e.g., < 1 hour — maximum acceptable data loss] |\n| **RTO (Recovery Time Objective)** | [e.g., < 4 hours — maximum acceptable downtime] |\n| **Backup Frequency** | [e.g., Continuous WAL archiving + daily snapshots] |\n| **Backup Location** | [e.g., Cross-region S3 with encryption] |\n| **Recovery Testing** | [e.g., Quarterly restore test] |\n\n## Data Quality Rules\n\n| Rule | Description | Enforcement |\n|---|---|---|\n| [e.g., Email uniqueness] | [e.g., No two active users may share an email] | [e.g., Database unique constraint] |\n\n## Privacy & Classification\n\nHow this data is classified and what handling rules apply based on that classification.\n\n| Classification Level | Handling Rules |\n|---|---|\n| Public | No restrictions |\n| Internal | Access controlled, not shared externally |\n| Confidential | Encrypted at rest, access logged, need-to-know basis |\n| Restricted | All of Confidential + additional controls per regulation |\n\n## Traceability\n\n- **Supports:** [FR-NNN](../${paths.requirementCategoryDirs.functional}/FR-NNN-slug.md)\n- **Protected by:** [SEC-NNN](../${paths.requirementCategoryDirs.security}/SEC-NNN-slug.md)\n- **Stored per:** [TR-NNN](../${paths.requirementCategoryDirs.technical}/TR-NNN-slug.md)\n- **Depends on (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [platform/industry requirement this depends on]\n- **Enables (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [customer-workflow/consumer-app requirement this enables]\n\n## Open Items\n\n### Identified Gaps\n\n[Document any missing functionality, unhandled edge cases, or incomplete aspects. Number each item and assign a priority (P0/P1/P2/P3). Call out interdependencies with other open items. If none, write \"None identified.\"]\n\n1. **[Gap title]** \\`[P0-P3]\\`\n   [Description of what's missing and why it matters.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Follow-up Questions\n\n[Document anything ambiguous or where the motivation/reasoning cannot be confidently inferred. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Question title]** \\`[P0-P3]\\`\n   [The question, with context on why the answer matters.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Contradictions & Inconsistencies\n\n[Document any conflicts with other requirements, code behavior, or documentation. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Contradiction title]** \\`[P0-P3]\\`\n   [Description of the conflict and what needs to be resolved.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n## Revision History\n\n| Date | Author | Change |\n|---|---|---|\n| YYYY-MM-DD | [Name] | Initial draft |\n`;\n\n/** Verbatim INT (Integration Requirement) template. */\nconst templateInt = (paths: ResolvedAgentPaths): string => `---\ntitle: \"INT-NNN: [Integration Requirement Title]\"\n---\n\n## Metadata\n\n| Field | Value |\n|---|---|\n| **ID** | INT-NNN |\n| **Status** | Draft |\n| **Tier** | [Platform · Industry · Customer Workflow · Consumer Application] |\n| **Implementor** | [Consortium Member · Customer · TBD — required for Customer Workflow and Consumer Application tiers. When Consortium Member, link to org profile] |\n| **Customer** | [Link to customer org profile if this requirement originated from or applies to a specific customer. Optional for Platform/Industry tiers, expected for Customer Workflow/Consumer Application tiers] |\n| **Integration Type** | [REST API / GraphQL / Webhook / Message Queue / File Transfer / SDK] |\n| **Direction** | [Inbound / Outbound / Bidirectional] |\n| **External System** | [Name of the third-party or internal system] |\n| **Owner** | [Name or role] |\n| **Created** | YYYY-MM-DD |\n| **Last Updated** | YYYY-MM-DD |\n\n## Description\n\nWhat this integration does, why it's needed, and what business capability it enables.\n\n## External System Overview\n\n| Field | Value |\n|---|---|\n| **System** | [e.g., Stripe] |\n| **Purpose** | [e.g., Payment processing and subscription management] |\n| **API Documentation** | [URL to official docs] |\n| **API Version** | [e.g., 2023-10-16] |\n| **Authentication** | [e.g., API key (secret key in header)] |\n\n## Integration Points\n\n### [Endpoint/Event 1]: [Name]\n\n| Field | Value |\n|---|---|\n| **Direction** | [Inbound/Outbound] |\n| **Protocol** | [e.g., HTTPS REST] |\n| **Endpoint** | [e.g., POST /v1/customers] |\n| **Authentication** | [e.g., Bearer token] |\n| **Rate Limit** | [e.g., 100 requests/second] |\n\n**Request/Payload:**\n\\`\\`\\`\n[Brief description or schema reference]\n\\`\\`\\`\n\n**Response/Output:**\n\\`\\`\\`\n[Brief description or schema reference]\n\\`\\`\\`\n\n## Error Handling\n\n| Error Scenario | Strategy | Retry Policy |\n|---|---|---|\n| [e.g., 429 Rate Limited] | [e.g., Exponential backoff] | [e.g., 3 retries, max 30s] |\n| [e.g., 500 Server Error] | [e.g., Retry with circuit breaker] | [e.g., 3 retries, then circuit open for 60s] |\n| [e.g., Timeout] | [e.g., Retry once, then dead letter queue] | [e.g., 30s timeout, 1 retry] |\n\n## Data Mapping\n\nHow data maps between our system and the external system.\n\n| Our Field | External Field | Transformation |\n|---|---|---|\n| [e.g., user.email] | [e.g., customer.email] | [e.g., Direct mapping] |\n\n## SLA & Availability\n\n| Parameter | Our Expectation | External System's Published SLA |\n|---|---|---|\n| Availability | [e.g., 99.9%] | [e.g., 99.99%] |\n| Response Time | [e.g., < 500ms p99] | [e.g., < 200ms typical] |\n\n## Fallback Behavior\n\nWhat happens when this integration is unavailable. How does the system degrade gracefully?\n\n## Testing Strategy\n\n| Environment | Approach |\n|---|---|\n| Development | [e.g., Mock server / sandbox environment] |\n| Staging | [e.g., Sandbox API with test credentials] |\n| Production | [e.g., Live API with monitoring] |\n\n## Traceability\n\n- **Enables:** [FR-NNN](../${paths.requirementCategoryDirs.functional}/FR-NNN-slug.md)\n- **Constrained by:** [NFR-NNN](../${paths.requirementCategoryDirs.nonFunctional}/NFR-NNN-slug.md)\n- **Secured by:** [SEC-NNN](../${paths.requirementCategoryDirs.security}/SEC-NNN-slug.md)\n- **Depends on (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [platform/industry requirement this depends on]\n- **Enables (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [customer-workflow/consumer-app requirement this enables]\n\n## Open Items\n\n### Identified Gaps\n\n[Document any missing functionality, unhandled edge cases, or incomplete aspects. Number each item and assign a priority (P0/P1/P2/P3). Call out interdependencies with other open items. If none, write \"None identified.\"]\n\n1. **[Gap title]** \\`[P0-P3]\\`\n   [Description of what's missing and why it matters.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Follow-up Questions\n\n[Document anything ambiguous or where the motivation/reasoning cannot be confidently inferred. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Question title]** \\`[P0-P3]\\`\n   [The question, with context on why the answer matters.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Contradictions & Inconsistencies\n\n[Document any conflicts with other requirements, code behavior, or documentation. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Contradiction title]** \\`[P0-P3]\\`\n   [Description of the conflict and what needs to be resolved.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n## Revision History\n\n| Date | Author | Change |\n|---|---|---|\n| YYYY-MM-DD | [Name] | Initial draft |\n`;\n\n/** Verbatim OPS (Operational Requirement) template. */\nconst templateOps = (paths: ResolvedAgentPaths): string => `---\ntitle: \"OPS-NNN: [Operational Requirement Title]\"\n---\n\n## Metadata\n\n| Field | Value |\n|---|---|\n| **ID** | OPS-NNN |\n| **Status** | Draft |\n| **Tier** | [Platform · Industry · Customer Workflow · Consumer Application] |\n| **Implementor** | [Consortium Member · Customer · TBD — required for Customer Workflow and Consumer Application tiers. When Consortium Member, link to org profile] |\n| **Customer** | [Link to customer org profile if this requirement originated from or applies to a specific customer. Optional for Platform/Industry tiers, expected for Customer Workflow/Consumer Application tiers] |\n| **Operations Domain** | [Deployment / Monitoring / Alerting / Logging / Incident Response / Backup] |\n| **Owner** | [Name or role] |\n| **Created** | YYYY-MM-DD |\n| **Last Updated** | YYYY-MM-DD |\n\n## Description\n\nWhat operational concern this requirement addresses and why it matters for system reliability.\n\n## Current State\n\nIf this applies to an existing system, document the current operational posture.\n\n## Requirements\n\n### Deployment\n\n| Parameter | Requirement |\n|---|---|\n| **Strategy** | [e.g., Blue-green / Rolling / Canary] |\n| **Frequency** | [e.g., On-demand, multiple times per day] |\n| **Rollback** | [e.g., Automated rollback on health check failure within 5 minutes] |\n| **Downtime** | [e.g., Zero-downtime required] |\n\n### Monitoring & Observability\n\n| Signal Type | What to Monitor | Tool | Retention |\n|---|---|---|---|\n| **Metrics** | [e.g., Request rate, error rate, latency p50/p95/p99] | [e.g., Datadog] | [e.g., 15 months] |\n| **Logs** | [e.g., Application logs, access logs, audit logs] | [e.g., CloudWatch → S3] | [e.g., 90 days hot, 1 year cold] |\n| **Traces** | [e.g., Distributed request traces] | [e.g., Datadog APM] | [e.g., 30 days] |\n\n### Alerting\n\n| Alert | Condition | Severity | Notification Channel | Escalation |\n|---|---|---|---|---|\n| [e.g., High error rate] | [e.g., 5xx rate > 1% for 5 min] | [e.g., P1 / Critical] | [e.g., PagerDuty → on-call] | [e.g., If unack'd in 15 min → engineering lead] |\n\n### Incident Response\n\n| Severity | Response Time | Resolution Target | Communication |\n|---|---|---|---|\n| P1 (Critical) | [e.g., 15 minutes] | [e.g., 1 hour] | [e.g., Status page + stakeholder notification] |\n| P2 (Major) | [e.g., 30 minutes] | [e.g., 4 hours] | [e.g., Status page if customer-facing] |\n| P3 (Minor) | [e.g., Next business day] | [e.g., 5 business days] | [e.g., Internal tracking only] |\n\n## Runbook References\n\n| Scenario | Runbook Location |\n|---|---|\n| [e.g., Database failover] | [Link or path] |\n| [e.g., High memory usage] | [Link or path] |\n\n## Environments\n\n| Environment | Purpose | Infrastructure | Access |\n|---|---|---|---|\n| Development | [Local development] | [e.g., Docker Compose] | [e.g., All developers] |\n| Staging | [Pre-production testing] | [e.g., AWS, scaled down] | [e.g., Engineering team] |\n| Production | [Live system] | [e.g., AWS, full scale] | [e.g., Restricted, via bastion] |\n\n## Traceability\n\n- **Monitors:** [NFR-NNN](../${paths.requirementCategoryDirs.nonFunctional}/NFR-NNN-slug.md)\n- **Supports:** [BR-NNN](../${paths.requirementCategoryDirs.business}/BR-NNN-slug.md)\n- **Uses:** [TR-NNN](../${paths.requirementCategoryDirs.technical}/TR-NNN-slug.md)\n- **Depends on (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [platform/industry requirement this depends on]\n- **Enables (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [customer-workflow/consumer-app requirement this enables]\n\n## Open Items\n\n### Identified Gaps\n\n[Document any missing functionality, unhandled edge cases, or incomplete aspects. Number each item and assign a priority (P0/P1/P2/P3). Call out interdependencies with other open items. If none, write \"None identified.\"]\n\n1. **[Gap title]** \\`[P0-P3]\\`\n   [Description of what's missing and why it matters.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Follow-up Questions\n\n[Document anything ambiguous or where the motivation/reasoning cannot be confidently inferred. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Question title]** \\`[P0-P3]\\`\n   [The question, with context on why the answer matters.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Contradictions & Inconsistencies\n\n[Document any conflicts with other requirements, code behavior, or documentation. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Contradiction title]** \\`[P0-P3]\\`\n   [Description of the conflict and what needs to be resolved.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n## Revision History\n\n| Date | Author | Change |\n|---|---|---|\n| YYYY-MM-DD | [Name] | Initial draft |\n`;\n\n/** Verbatim UX (UX Requirement) template. */\nconst templateUx = (paths: ResolvedAgentPaths): string => `---\ntitle: \"UX-NNN: [UX Requirement Title]\"\n---\n\n## Metadata\n\n| Field | Value |\n|---|---|\n| **ID** | UX-NNN |\n| **Status** | Draft |\n| **Tier** | [Platform · Industry · Customer Workflow · Consumer Application] |\n| **Implementor** | [Consortium Member · Customer · TBD — required for Customer Workflow and Consumer Application tiers. When Consortium Member, link to org profile] |\n| **Customer** | [Link to customer org profile if this requirement originated from or applies to a specific customer. Optional for Platform/Industry tiers, expected for Customer Workflow/Consumer Application tiers] |\n| **UX Domain** | [Accessibility / Responsiveness / Internationalization / Interaction Design / Information Architecture] |\n| **Priority** | [Critical / High / Medium / Low] |\n| **Owner** | [Name or role] |\n| **Created** | YYYY-MM-DD |\n| **Last Updated** | YYYY-MM-DD |\n\n## Description\n\nWhat user experience concern this requirement addresses and why it matters.\n\n## Target Users\n\n| User Segment | Characteristics | Key Needs |\n|---|---|---|\n| [e.g., Power users] | [e.g., Daily usage, keyboard-heavy workflow] | [e.g., Keyboard shortcuts, bulk actions] |\n\n## Accessibility\n\n| Parameter | Requirement |\n|---|---|\n| **WCAG Level** | [e.g., 2.1 Level AA] |\n| **Screen Reader Support** | [e.g., ARIA labels on all interactive elements] |\n| **Keyboard Navigation** | [e.g., All functionality accessible via keyboard] |\n| **Color Contrast** | [e.g., Minimum 4.5:1 for normal text, 3:1 for large text] |\n| **Motion** | [e.g., Respect prefers-reduced-motion; no auto-playing animations] |\n\n## Responsive Design\n\n| Breakpoint | Target Devices | Layout Behavior |\n|---|---|---|\n| [e.g., < 375px] | [e.g., Small phones] | [e.g., Single column, stacked navigation] |\n| [e.g., 375–768px] | [e.g., Phones, small tablets] | [e.g., Single column, hamburger menu] |\n| [e.g., 768–1024px] | [e.g., Tablets] | [e.g., Two-column where appropriate] |\n| [e.g., > 1024px] | [e.g., Desktop] | [e.g., Full layout with sidebar navigation] |\n\n## Internationalization (i18n)\n\n| Parameter | Requirement |\n|---|---|\n| **Supported Languages** | [e.g., English (launch), Spanish, French (Phase 2)] |\n| **Text Direction** | [e.g., LTR only at launch; RTL support in backlog] |\n| **Date/Time Formats** | [e.g., Locale-aware formatting] |\n| **Currency** | [e.g., Display in user's locale, store in USD] |\n\n## Interaction Patterns\n\nKey interaction patterns and principles that apply to this requirement.\n\n| Pattern | Standard | Notes |\n|---|---|---|\n| [e.g., Form validation] | [e.g., Inline validation on blur, summary on submit] | [e.g., Error messages adjacent to field] |\n| [e.g., Loading states] | [e.g., Skeleton screens for content, spinners for actions] | [e.g., No blank screens during loads] |\n\n## Design System Reference\n\nReference to the project's design system, component library, or style guide if one exists.\n\n## Acceptance Criteria\n\n- [ ] [Specific, verifiable UX condition]\n- [ ] [e.g., All pages score ≥ 90 on Lighthouse accessibility audit]\n- [ ] [e.g., All interactive elements have visible focus indicators]\n\n## Traceability\n\n- **Enhances:** [FR-NNN](../${paths.requirementCategoryDirs.functional}/FR-NNN-slug.md)\n- **Constrained by:** [NFR-NNN](../${paths.requirementCategoryDirs.nonFunctional}/NFR-NNN-slug.md)\n- **Supports:** [BR-NNN](../${paths.requirementCategoryDirs.business}/BR-NNN-slug.md)\n- **Depends on (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [platform/industry requirement this depends on]\n- **Enables (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [customer-workflow/consumer-app requirement this enables]\n\n## Open Items\n\n### Identified Gaps\n\n[Document any missing functionality, unhandled edge cases, or incomplete aspects. Number each item and assign a priority (P0/P1/P2/P3). Call out interdependencies with other open items. If none, write \"None identified.\"]\n\n1. **[Gap title]** \\`[P0-P3]\\`\n   [Description of what's missing and why it matters.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Follow-up Questions\n\n[Document anything ambiguous or where the motivation/reasoning cannot be confidently inferred. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Question title]** \\`[P0-P3]\\`\n   [The question, with context on why the answer matters.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Contradictions & Inconsistencies\n\n[Document any conflicts with other requirements, code behavior, or documentation. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Contradiction title]** \\`[P0-P3]\\`\n   [Description of the conflict and what needs to be resolved.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n## Revision History\n\n| Date | Author | Change |\n|---|---|---|\n| YYYY-MM-DD | [Name] | Initial draft |\n`;\n\n/** Verbatim MT (Multi-Tenancy & Licensing) template. */\nconst templateMt = (paths: ResolvedAgentPaths): string => `---\ntitle: \"MT-NNN: [Multi-Tenancy Requirement Title]\"\n---\n\n## Metadata\n\n| Field | Value |\n|---|---|\n| **ID** | MT-NNN |\n| **Status** | Draft |\n| **Tier** | [Platform · Industry · Customer Workflow · Consumer Application] |\n| **Implementor** | [Consortium Member · Customer · TBD — required for Customer Workflow and Consumer Application tiers. When Consortium Member, link to org profile] |\n| **Customer** | [Link to customer org profile if this requirement originated from or applies to a specific customer. Optional for Platform/Industry tiers, expected for Customer Workflow/Consumer Application tiers] |\n| **MT Domain** | [Tenant Isolation / Feature Gating / Usage Metering / Billing / Provisioning / Licensing] |\n| **Priority** | [Critical / High / Medium / Low] |\n| **Owner** | [Name or role] |\n| **Created** | YYYY-MM-DD |\n| **Last Updated** | YYYY-MM-DD |\n\n## Description\n\nWhat multi-tenancy concern this requirement addresses and why it matters for the SaaS product.\n\n## Tenant Isolation Model\n\n| Layer | Isolation Strategy | Details |\n|---|---|---|\n| **Database** | [e.g., Row-level / Schema-per-tenant / Database-per-tenant] | [e.g., tenant_id column on all tenant-scoped tables, enforced by RLS] |\n| **Application** | [e.g., Shared application, tenant context from auth token] | [e.g., Middleware extracts tenant from JWT, injects into query context] |\n| **Infrastructure** | [e.g., Shared infrastructure / Dedicated compute per tenant] | [e.g., Shared at launch, dedicated option for enterprise tier] |\n| **Storage** | [e.g., Shared bucket with tenant prefix / Separate buckets] | [e.g., S3 bucket with tenant-id/ prefix, IAM policies per tenant] |\n\n## Feature Gating\n\n| Feature | Free Tier | Pro Tier | Enterprise Tier |\n|---|---|---|---|\n| [e.g., Number of users] | [e.g., Up to 5] | [e.g., Up to 50] | [e.g., Unlimited] |\n| [e.g., API access] | [e.g., No] | [e.g., Yes, 1000 calls/day] | [e.g., Yes, unlimited] |\n\n### Gating Mechanism\n\nHow feature gates are implemented and managed (e.g., feature flag service, plan-based checks, entitlement system).\n\n## Usage Metering\n\n| Dimension | Unit | Collection Method | Billing Cycle |\n|---|---|---|---|\n| [e.g., API calls] | [e.g., Per request] | [e.g., API gateway counter] | [e.g., Monthly] |\n| [e.g., Storage] | [e.g., GB-month] | [e.g., Nightly calculation] | [e.g., Monthly] |\n\n## Tenant Provisioning\n\n| Step | Action | Duration | Automated? |\n|---|---|---|---|\n| 1 | [e.g., Create tenant record] | [e.g., < 1s] | [e.g., Yes] |\n| 2 | [e.g., Provision database schema/rows] | [e.g., < 5s] | [e.g., Yes] |\n| 3 | [e.g., Configure DNS/subdomain] | [e.g., < 1 min] | [e.g., Yes] |\n\n## Tenant Offboarding\n\nWhat happens when a tenant leaves — data retention, export, cleanup procedures.\n\n## Noisy Neighbor Prevention\n\nHow the system prevents one tenant from degrading the experience of others.\n\n| Strategy | Implementation |\n|---|---|\n| [e.g., Rate limiting] | [e.g., Per-tenant rate limits at API gateway] |\n| [e.g., Resource quotas] | [e.g., Max storage per tenant per tier] |\n\n## Acceptance Criteria\n\n- [ ] [e.g., Tenant A cannot access Tenant B's data under any circumstances]\n- [ ] [e.g., Feature gate changes take effect within 60 seconds]\n- [ ] [e.g., New tenant provisioning completes in under 30 seconds]\n\n## Traceability\n\n- **Implements:** [BR-NNN](../${paths.requirementCategoryDirs.business}/BR-NNN-slug.md)\n- **Secured by:** [SEC-NNN](../${paths.requirementCategoryDirs.security}/SEC-NNN-slug.md)\n- **Constrained by:** [NFR-NNN](../${paths.requirementCategoryDirs.nonFunctional}/NFR-NNN-slug.md)\n- **Depends on (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [platform/industry requirement this depends on]\n- **Enables (cross-tier):** [XX-NNN](../category/XX-NNN-slug.md) — [customer-workflow/consumer-app requirement this enables]\n\n## Open Items\n\n### Identified Gaps\n\n[Document any missing functionality, unhandled edge cases, or incomplete aspects. Number each item and assign a priority (P0/P1/P2/P3). Call out interdependencies with other open items. If none, write \"None identified.\"]\n\n1. **[Gap title]** \\`[P0-P3]\\`\n   [Description of what's missing and why it matters.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Follow-up Questions\n\n[Document anything ambiguous or where the motivation/reasoning cannot be confidently inferred. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Question title]** \\`[P0-P3]\\`\n   [The question, with context on why the answer matters.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n### Contradictions & Inconsistencies\n\n[Document any conflicts with other requirements, code behavior, or documentation. Number each item and assign a priority. If none, write \"None identified.\"]\n\n1. **[Contradiction title]** \\`[P0-P3]\\`\n   [Description of the conflict and what needs to be resolved.]\n   → [Depends on / Blocks]: [XX-NNN Open Item #N](../category/XX-NNN-slug.md#open-items) (if applicable)\n\n## Revision History\n\n| Date | Author | Change |\n|---|---|---|\n| YYYY-MM-DD | [Name] | Initial draft |\n`;\n\n/** Verbatim category-README template (one per requirement directory). */\nconst TEMPLATE_CATEGORY_README = `# [Category Name] Requirements\n\n## Purpose\n\n[One-paragraph description of what belongs in this category and the question it answers.]\n\n## What Belongs Here\n\n- [Type of requirement 1]\n- [Type of requirement 2]\n- [Type of requirement 3]\n\n## What Does NOT Belong Here\n\n| If your requirement looks like... | It probably belongs in... | Why |\n|---|---|---|\n| [e.g., \"The system must respond in < 200ms\"] | [e.g., NFR (Non-Functional)] | [e.g., That's a quality/performance target, not a feature description] |\n\n## Template\n\nUse [\\`_template-{PREFIX}.md\\`](../templates/_template-{PREFIX}.md) for all new documents in this category.\n\n## Current Documents\n\n| ID | Title | Status | Last Updated |\n|---|---|---|---|\n| [{PREFIX}-001](/{PREFIX}-001-slug.md) | [Title] | [Status] | [Date] |\n\n## Conventions\n\n- File naming: \\`{PREFIX}-NNN-descriptive-slug.md\\`\n- Number sequentially — check the table above for the next available number. Do not embed per-requirement descriptions, a running change-log, or a mutable \"next available: X (…)\" counter in this Conventions section; the table above is the sole registry, and each document's ID is finalized at write-start.\n- Every document must include YAML frontmatter with a \\`title\\` field\n- Every document must include a \\`## Traceability\\` section\n`;\n\n/** Verbatim top-level requirements README template. */\nconst templateRequirementsReadme = (paths: ResolvedAgentPaths): string => `---\ntitle: \"[Project Name] — Requirements Documentation\"\n---\n\nThis directory contains the structured requirements taxonomy for [Project Name]. It covers the full lifecycle from business intent through operational concerns, providing traceability between strategic goals and implementation work.\n\n## Taxonomy Overview\n\n| Category | Prefix | Directory | Purpose |\n|---|---|---|---|\n| Business Requirements | BR | [\\`${paths.requirementCategoryDirs.business}/\\`](${paths.requirementCategoryDirs.business}/README.md) | Strategic intent, stakeholders, success metrics |\n| Functional Requirements | FR | [\\`${paths.requirementCategoryDirs.functional}/\\`](${paths.requirementCategoryDirs.functional}/README.md) | User stories, flows, acceptance criteria |\n| Non-Functional Requirements | NFR | [\\`${paths.requirementCategoryDirs.nonFunctional}/\\`](${paths.requirementCategoryDirs.nonFunctional}/README.md) | Performance, scalability, availability targets |\n| Technical Requirements | TR | [\\`${paths.requirementCategoryDirs.technical}/\\`](${paths.requirementCategoryDirs.technical}/README.md) | Technology choices, framework decisions |\n| Architectural Decisions | ADR | [\\`${paths.requirementCategoryDirs.architecturalDecisions}/\\`](${paths.requirementCategoryDirs.architecturalDecisions}/README.md) | Context, decision, consequences (standard ADR format) |\n| Security & Compliance | SEC | [\\`${paths.requirementCategoryDirs.security}/\\`](${paths.requirementCategoryDirs.security}/README.md) | Auth, encryption, audit, regulatory |\n| Data Requirements | DR | [\\`${paths.requirementCategoryDirs.data}/\\`](${paths.requirementCategoryDirs.data}/README.md) | Data models, retention, classification, RPO/RTO |\n| Integration Requirements | INT | [\\`${paths.requirementCategoryDirs.integration}/\\`](${paths.requirementCategoryDirs.integration}/README.md) | APIs, third-party systems, protocols |\n| Operational Requirements | OPS | [\\`${paths.requirementCategoryDirs.operational}/\\`](${paths.requirementCategoryDirs.operational}/README.md) | Deployment, monitoring, alerting, logging |\n| UX Requirements | UX | [\\`${paths.requirementCategoryDirs.ux}/\\`](${paths.requirementCategoryDirs.ux}/README.md) | Accessibility, responsiveness, i18n |\n| Multi-Tenancy & Licensing | MT | [\\`${paths.requirementCategoryDirs.multiTenancy}/\\`](${paths.requirementCategoryDirs.multiTenancy}/README.md) | Tenant isolation, feature gating, billing |\n\nEach directory contains a \\`README.md\\` with detailed guidance on what belongs in that category (and what doesn't), common disambiguation tips, and project-specific context. When unsure where a requirement belongs, start with the category README.\n\n## Which Category Do I Use?\n\nWhen capturing or decomposing a requirement, use the question it answers to determine the correct category:\n\n| Question | Category | Example |\n|---|---|---|\n| **Why** do we need this? What business value does it deliver? | BR | \"We need self-service registration to reduce sales-assisted onboarding costs\" |\n| **What** does the system do? What is the user-visible behavior? | FR | \"A user can register with email and password and receive a verification link\" |\n| **How well** must the system perform? What quality bar must it meet? | NFR | \"Registration API must respond within 200ms at p99\" |\n| **What technology** are we choosing, and why that one? | TR | \"PostgreSQL 16+ for the primary datastore\" |\n| **What structural decision** are we making, and what are the trade-offs? | ADR | \"Use row-level tenant isolation rather than schema-per-tenant\" |\n| **What must we protect**, and what rules govern that protection? | SEC | \"All PII must be encrypted at rest; SOC 2 Type II compliance required\" |\n| **What data** do we store, for how long, and how do we recover it? | DR | \"Tenant data retained for 90 days after account closure, RPO < 1 hour\" |\n| **What external systems** do we connect to, and how? | INT | \"Stripe Billing API for subscription management via REST\" |\n| **How do we deploy, monitor, and respond** to incidents? | OPS | \"Blue-green deployments with PagerDuty alerting on error rate > 1%\" |\n| **How must the interface look, feel, and behave** for users? | UX | \"WCAG 2.1 AA compliance; responsive down to 375px width\" |\n| **How do we isolate tenants, gate features, and meter usage?** | MT | \"Logical tenant isolation at row level; API call metering per plan tier\" |\n\n### Common Disambiguation\n\n- **SEC vs NFR:** If it's about protecting data, enforcing access control, or meeting a regulation → SEC. If it's about system performance, uptime, or scalability → NFR. A requirement like \"99.9% uptime\" is an NFR; \"audit logs for all admin actions\" is SEC.\n- **TR vs ADR:** A TR specifies a concrete technology choice (\"use PostgreSQL\"). An ADR records a structural decision with context, trade-offs, and alternatives considered (\"why row-level isolation over schema-per-tenant\"). TRs often follow from ADRs.\n- **FR vs INT:** If it describes what the user experiences → FR. If it describes how two systems communicate → INT. \"User can pay with a credit card\" is FR; \"Stripe Checkout API integration for payment processing\" is INT.\n- **DR vs SEC:** If it's about what data exists, how long we keep it, and how we recover it → DR. If it's about who can access it and how it's protected → SEC. These often cross-reference each other.\n- **NFR vs OPS:** If it's a measurable target the system must meet → NFR. If it's about the tooling and processes to run the system → OPS. \"p99 latency < 200ms\" is NFR; \"Datadog APM for latency monitoring\" is OPS.\n\n## File Naming Convention\n\n\\`\\`\\`\n{PREFIX}-{NNN}-{slug}.md\n\\`\\`\\`\n\n- **PREFIX** — category abbreviation from the table above\n- **NNN** — three-digit sequential number (e.g., \\`001\\`, \\`012\\`)\n- **slug** — lowercase kebab-case descriptive name\n\nExamples:\n- \\`FR-001-user-registration.md\\`\n- \\`SEC-001-multi-tenant-auth.md\\`\n- \\`ADR-001-database-selection.md\\`\n\n## Status Definitions\n\nAll requirements use a universal status lifecycle:\n\n| Status | Meaning |\n|---|---|\n| \\`Draft\\` | Initial capture, under discussion |\n| \\`Proposed\\` | Formally proposed, awaiting review |\n| \\`Accepted\\` | Approved and active |\n| \\`Implemented\\` | Fully delivered |\n| \\`Deprecated\\` | No longer applicable |\n| \\`Superseded\\` | Replaced by another requirement (link to successor) |\n\n## Cross-Referencing Guide\n\nEvery requirement document should include a \\`## Traceability\\` section. Use relative markdown links with the requirement ID as link text.\n\nExample:\n\\`\\`\\`markdown\n## Traceability\n\n- **Implements:** [FR-001](../${paths.requirementCategoryDirs.functional}/FR-001-user-registration.md)\n- **Constrained by:** [NFR-001](../${paths.requirementCategoryDirs.nonFunctional}/NFR-001-uptime-sla.md)\n- **Related:** [SEC-001](../${paths.requirementCategoryDirs.security}/SEC-001-multi-tenant-auth.md)\n\\`\\`\\`\n\n### Link Types\n\n| Link Type | Meaning |\n|---|---|\n| **Implements** | This requirement realizes a higher-level requirement |\n| **Constrained by** | This requirement is bounded by another requirement |\n| **Supports** | This requirement contributes to but does not fully realize another |\n| **Supersedes** | This requirement replaces a deprecated one |\n| **Related** | Informational relationship |\n\n## Connecting Requirements to Code\n\n- **GitHub issues:** Use the Requirements Traceability section of the issue template to reference requirement IDs\n- **PR descriptions:** Include a Requirements section with links to relevant requirement documents\n- **Commit footers:** Optionally add \\`Implements BR-001\\` or \\`Supports NFR-003\\` lines\n\n## Dependency Flow\n\nRequirements relate to each other in a layered hierarchy:\n\n\\`\\`\\`\nBusiness Requirements (BR)\n    → justify epics and initiatives\n\nFunctional (FR), Integration (INT), Multi-Tenancy (MT)\n    → decompose into feature issues\n\nNFRs, Security (SEC), UX\n    → appear as acceptance criteria AND as standalone issues\n\nArchitectural Decisions (ADR)\n    → spawn implementation issues and serve as context\n\nTechnical (TR), Data (DR), Operational (OPS)\n    → drive infrastructure and platform issues\n\\`\\`\\`\n`;\n\n/** Verbatim Standards & Frameworks reference shipped with the skill. */\nconst STANDARDS_AND_FRAMEWORKS = `# Standards & Frameworks Reference\n\nThis reference provides detailed guidance on the standards and frameworks that inform each requirement category. Consult this when you're uncertain about how to structure a requirement, what level of detail is appropriate, or how to handle an edge case within a specific category.\n\n## Table of Contents\n\n1. [BR — BABOK Guide v3](#br--babok-guide-v3)\n2. [FR — BABOK v3 + IEEE 830](#fr--babok-v3--ieee-830)\n3. [NFR — ISO/IEC 25010:2023](#nfr--isoiec-250102023)\n4. [ADR — Nygard ADR + MADR](#adr--nygard-adr--madr)\n5. [TR — BABOK v3 Transition Requirements](#tr--babok-v3-transition-requirements)\n6. [SEC — OWASP ASVS + NIST SP 800-53](#sec--owasp-asvs--nist-sp-800-53)\n7. [DR — DAMA-DMBOK](#dr--dama-dmbok)\n8. [INT — Enterprise Integration Patterns + OpenAPI](#int--enterprise-integration-patterns--openapi)\n9. [OPS — Google SRE Book + ITIL 4](#ops--google-sre-book--itil-4)\n10. [UX — WCAG 2.1 + Nielsen Norman Heuristics](#ux--wcag-21--nielsen-norman-heuristics)\n11. [MT — Azure Well-Architected Framework](#mt--azure-well-architected-framework)\n12. [Cross-Cutting References](#cross-cutting-references)\n\n---\n\n## BR — BABOK Guide v3\n\n**Standard:** [BABOK Guide v3 — Requirements Classification Schema](https://www.iiba.org/business-analysis-certifications/iiba-certifications/ecba-certification/babok-guide-v3/)\n\n**What it is:** The International Institute of Business Analysis (IIBA) defines business requirements as the highest level of the requirements hierarchy — statements of goals, objectives, and outcomes that describe why a change is being undertaken.\n\n**How it informs BR documents:**\n- Business requirements sit at the top of the requirements hierarchy. Every other requirement should eventually trace back to one.\n- Stakeholder identification follows BABOK's guidance: identify who cares about this requirement, what their role is, and what their interest is.\n- Success metrics should be specific and measurable — BABOK emphasizes that business requirements without measurable success criteria are aspirational statements, not requirements.\n- Traceability: BABOK's model flows from Business Requirements → Stakeholder Requirements → Solution Requirements (functional + non-functional) → Transition Requirements. Our taxonomy maps to this: BR → FR/NFR → TR.\n\n**When to consult this:** When you're struggling to articulate *why* something is being built (especially when reverse-engineering from code), when defining stakeholders, or when writing success metrics.\n\n---\n\n## FR — BABOK v3 + IEEE 830\n\n**Standards:**\n- [BABOK Guide v3 — Solution Requirements](https://www.iiba.org/business-analysis-certifications/iiba-certifications/ecba-certification/babok-guide-v3/)\n- [IEEE 830 (SRS) — Recommended Practice for Software Requirements Specifications](https://standards.ieee.org/ieee/830/1222/)\n\n**What they are:** BABOK defines functional requirements as \"solution requirements\" that describe user-visible behavior. IEEE 830 provides the classic structure for Software Requirements Specifications, including the concept of structured flows.\n\n**How they inform FR documents:**\n- The user story format (\"As a... I want... so that...\") captures the actor, action, and business value in a single sentence. This comes from agile practice but aligns with BABOK's emphasis on stakeholder-centric requirements.\n- Structured flows (main flow, alternative flows, exception flows) come from IEEE 830's recommended practices. The main flow is the happy path. Alternative flows are valid variations. Exception flows handle errors.\n- MoSCoW prioritization (Must Have / Should Have / Could Have / Won't Have) comes from the DSDM Agile Project Framework and is used for the Priority field in FR documents.\n- Acceptance criteria should be specific, testable, and binary (pass/fail). Each criterion describes one verifiable condition.\n\n**When to consult this:** When structuring a complex feature into flows, when deciding how to decompose a large feature into multiple FRs, when writing acceptance criteria, or when prioritizing requirements.\n\n---\n\n## NFR — ISO/IEC 25010:2023\n\n**Standard:** [ISO/IEC 25010:2023 — Systems and Software Quality Requirements and Evaluation](https://www.iso.org/standard/35733.html)\n\n**What it is:** ISO 25010 defines a product quality model with characteristics and sub-characteristics. It's the international standard for thinking about software quality attributes.\n\n**Quality characteristics defined by ISO 25010:**\n- **Functional suitability** — Does it do what it's supposed to? (correctness, completeness, appropriateness)\n- **Performance efficiency** — Time behavior, resource utilization, capacity\n- **Compatibility** — Co-existence, interoperability\n- **Usability** — Recognizability, learnability, operability, error protection, aesthetics, accessibility\n- **Reliability** — Maturity, availability, fault tolerance, recoverability\n- **Security** — Confidentiality, integrity, non-repudiation, accountability, authenticity (note: in our taxonomy, security gets its own SEC category)\n- **Maintainability** — Modularity, reusability, analysability, modifiability, testability\n- **Portability** — Adaptability, installability, replaceability\n\n**How it informs NFR documents:**\n- Every NFR must have a numeric, measurable target. \"The system should be fast\" is not an NFR. \"API response time must be < 200ms at p99\" is.\n- The Quality Attribute field in the NFR template maps to ISO 25010's characteristics. Use this to categorize what kind of quality the NFR addresses.\n- Measurement methods must be specified — how will you know if the target is being met?\n\n**When to consult this:** When you're not sure if something is an NFR (use the quality characteristics as a checklist), when a stated quality target is vague and needs to be made measurable, or when you need to categorize what type of quality attribute an NFR addresses.\n\n---\n\n## ADR — Nygard ADR + MADR\n\n**Standards:**\n- [Nygard ADR Format](https://cognitect.com/blog/2011/11/15/documenting-architecture-decisions) — The original lightweight ADR format\n- [MADR — Markdown Architectural Decision Records](https://adr.github.io/madr/) — Extended format with structured alternatives\n\n**What they are:** Michael Nygard's original ADR format (Context → Decision → Consequences) established the standard for documenting architecture decisions as lightweight, immutable records. MADR extends this with explicit alternatives and structured consequences.\n\n**How they inform ADR documents:**\n- **Context:** What forces are at play? Technical constraints, business pressures, team capabilities, timeline. This is the \"why now\" of the decision.\n- **Decision:** State it clearly: \"We will use X.\" Not \"We are considering X.\"\n- **Alternatives considered:** For each alternative, document what it is, its pros and cons, and why it was rejected. This is crucial — future readers need to know not just what was decided, but what was considered and why other options lost.\n- **Consequences:** Every decision has positive, negative, and neutral consequences. Documenting negative consequences honestly is essential — it prevents future developers from relitigating decisions without understanding the trade-offs.\n- **Immutability:** ADRs are not edited once accepted — they are superseded by new ADRs. This preserves the decision history.\n\n**When to consult this:** When deciding whether something is an ADR vs. a TR (ADR = structural decision with trade-offs; TR = specific technology choice), when structuring the alternatives section, or when documenting consequences honestly (resist the temptation to only list positives).\n\n---\n\n## TR — BABOK v3 Transition Requirements\n\n**Standard:** [BABOK Guide v3 — Transition Requirements](https://www.iiba.org/business-analysis-certifications/iiba-certifications/ecba-certification/babok-guide-v3/)\n\n**What it is:** BABOK defines transition requirements as capabilities the solution must have to facilitate the transition from the current state to the desired state. In our taxonomy, TRs pin down specific technology, framework, and version choices.\n\n**How it informs TR documents:**\n- TRs are concrete and specific: \"PostgreSQL 16+\", \"Express 4.x\", \"Redis 7\". Not \"a relational database\" (that's an ADR-level decision).\n- Every TR should be traceable to an ADR that justifies the choice. If no ADR exists, the rationale should be included in the TR itself.\n- Version constraints, licensing, and vendor/maintainer information help with long-term planning and risk assessment.\n- Remember the version drift principle: cite observed versions but treat them as floors, not pins.\n\n**When to consult this:** When deciding the granularity of a TR (one per technology, not one per library), when linking TRs to their justifying ADRs, or when documenting version constraints.\n\n---\n\n## SEC — OWASP ASVS + NIST SP 800-53\n\n**Standards:**\n- [OWASP Application Security Verification Standard (ASVS)](https://owasp.org/www-project-application-security-verification-standard/) — A framework of security requirements organized by domain\n- [NIST SP 800-53 Rev 5](https://csrc.nist.gov/publications/detail/sp/800-53/rev-5/final) — Security and Privacy Controls for Information Systems\n\n**What they are:** OWASP ASVS provides a practical, developer-friendly framework for security requirements organized into chapters: authentication, session management, access control, validation, cryptography, error handling, data protection, communications, malicious code, business logic, files, and API security. NIST 800-53 provides a comprehensive control catalog used for compliance frameworks like FedRAMP and SOC 2.\n\n**How they inform SEC documents:**\n- OWASP ASVS chapter references help categorize security requirements. For example:\n  - V2: Authentication (password policies, multi-factor, credential storage)\n  - V3: Session Management (token generation, timeout, revocation)\n  - V4: Access Control (RBAC, least privilege, path traversal)\n  - V5: Validation, Sanitization, and Encoding\n  - V6: Stored Cryptography\n  - V7: Error Handling and Logging\n  - V8: Data Protection\n  - V13: API and Web Service Security\n- NIST 800-53 control families map to compliance requirements (e.g., AC = Access Control, AU = Audit and Accountability, IA = Identification and Authentication)\n- STRIDE threat categories (Spoofing, Tampering, Repudiation, Information Disclosure, Denial of Service, Elevation of Privilege) help structure threat model references\n- Validation approaches should include both automated (CI security scans, SAST, DAST) and manual (penetration testing, code review) methods\n\n**When to consult this:** When categorizing a security requirement, when linking to specific OWASP ASVS or NIST 800-53 controls, when writing threat model references, when distinguishing between SEC and NFR (security protects; NFR measures quality), or when specifying validation approaches.\n\n---\n\n## DR — DAMA-DMBOK\n\n**Standard:** [DAMA-DMBOK — Data Management Body of Knowledge](https://www.dama.org/cpages/body-of-knowledge)\n\n**What it is:** DAMA-DMBOK covers data governance, data quality, data lifecycle management, data architecture, and related disciplines. It provides frameworks for thinking about data classification, retention, and recovery.\n\n**How it informs DR documents:**\n- **Data classification levels:** Public → Internal → Confidential → Restricted. Each level has corresponding handling rules (encryption, access logging, need-to-know).\n- **Retention policies:** Every data type needs a retention period, legal basis for retention, and deletion method. DAMA emphasizes that retention is not just \"how long\" but also \"why that long\" and \"what triggers deletion.\"\n- **RPO/RTO framework:**\n  - RPO (Recovery Point Objective): Maximum acceptable data loss measured in time. RPO < 1 hour means you can't lose more than 1 hour of data.\n  - RTO (Recovery Time Objective): Maximum acceptable downtime. RTO < 4 hours means the system must be back up within 4 hours.\n- **Data lifecycle:** Creation → Active Use → Archival → Deletion. Each phase has different storage, access, and protection requirements.\n\n**When to consult this:** When classifying data sensitivity, when defining retention policies (especially the legal basis), when setting RPO/RTO targets, or when documenting the data lifecycle for a new entity.\n\n---\n\n## INT — Enterprise Integration Patterns + OpenAPI\n\n**Standards:**\n- [Enterprise Integration Patterns (Hohpe & Woolf)](https://www.enterpriseintegrationpatterns.com/) — Canonical patterns for system integration\n- [OpenAPI Specification](https://www.openapis.org/) — Standard for describing REST APIs\n\n**What they are:** Hohpe & Woolf's Enterprise Integration Patterns define the vocabulary for how systems communicate: messaging, routing, transformation, endpoints. OpenAPI provides the standard for documenting REST API contracts.\n\n**How they inform INT documents:**\n- **Direction labels:** Inbound (external system calls us), Outbound (we call external system), Bidirectional\n- **Error handling strategies from EIP:**\n  - Retry with exponential backoff — for transient failures\n  - Circuit breaker — stop calling a failing service to prevent cascade failures\n  - Dead letter queue (DLQ) — capture messages that can't be processed for later investigation\n  - Idempotency — ensure repeated calls don't cause duplicate effects\n- **SLA expectations:** Document both what we expect from the external system and what they expect from us. Include availability, response time, and rate limits.\n- **API contracts:** Follow OpenAPI conventions for documenting endpoints, request/response schemas, authentication methods, and error codes.\n\n**When to consult this:** When documenting error handling for an integration (use the EIP vocabulary), when specifying fallback behavior, when distinguishing between FR (what the user experiences) and INT (how systems communicate), or when documenting API contracts.\n\n---\n\n## OPS — Google SRE Book + ITIL 4\n\n**Standards:**\n- [Google SRE Book — Site Reliability Engineering](https://sre.google/sre-book/table-of-contents/) — Engineering approach to operations\n- [ITIL 4](https://www.axelos.com/certifications/itil-service-management) — IT service management framework\n\n**What they are:** The Google SRE book defines principles for running reliable production systems: SLIs, SLOs, error budgets, toil reduction, incident response. ITIL 4 provides the broader service management framework for change management, incident management, and service operations.\n\n**How they inform OPS documents:**\n- **SLIs (Service Level Indicators):** The metrics that measure service health. Examples: request latency, error rate, throughput, availability.\n- **SLOs (Service Level Objectives):** Targets for SLIs. Example: \"99.9% of requests complete within 200ms.\" SLOs belong in NFR documents, but OPS documents describe how they're monitored.\n- **Observability:** The three pillars — metrics, logs, traces. OPS documents should specify all three: what metrics are collected, what's logged, and whether distributed tracing is in place.\n- **Incident response:** Severity levels, response times, escalation paths, communication plans. The SRE book emphasizes blameless postmortems and clear runbooks.\n- **Deployment strategies:** Blue-green, canary, rolling, feature flags. Each has different rollback characteristics and risk profiles.\n\n**When to consult this:** When defining monitoring and alerting rules, when structuring incident response procedures, when choosing deployment strategies, or when distinguishing between NFR (the target) and OPS (the machinery that monitors and maintains the target).\n\n---\n\n## UX — WCAG 2.1 + Nielsen Norman Heuristics\n\n**Standards:**\n- [WCAG 2.1 — Web Content Accessibility Guidelines](https://www.w3.org/WAI/standards-guidelines/wcag/) — W3C accessibility standard\n- [Nielsen Norman Group — 10 Usability Heuristics](https://www.nngroup.com/articles/ten-usability-heuristics/) — Foundational usability principles\n\n**What they are:** WCAG 2.1 defines three levels of accessibility conformance (A, AA, AAA) across four principles: Perceivable, Operable, Understandable, Robust (POUR). Nielsen's heuristics provide a framework for evaluating usability beyond accessibility.\n\n**How they inform UX documents:**\n- **WCAG conformance levels:**\n  - Level A: Minimum accessibility. Removes the most serious barriers.\n  - Level AA: The accepted standard for most applications. Addresses the majority of barriers.\n  - Level AAA: The highest level. Often impractical for entire sites but useful for specific features.\n- **POUR principles:**\n  - Perceivable: Can users perceive the content? (text alternatives, captions, contrast)\n  - Operable: Can users operate the interface? (keyboard navigation, timing, seizure prevention)\n  - Understandable: Can users understand the content and interface? (readability, predictability, error prevention)\n  - Robust: Can the content be interpreted by assistive technologies? (valid markup, ARIA)\n- **Nielsen's 10 heuristics:**\n  1. Visibility of system status\n  2. Match between system and the real world\n  3. User control and freedom\n  4. Consistency and standards\n  5. Error prevention\n  6. Recognition rather than recall\n  7. Flexibility and efficiency of use\n  8. Aesthetic and minimalist design\n  9. Help users recognize, diagnose, and recover from errors\n  10. Help and documentation\n- **Responsive design:** Document specific breakpoints and layout behavior changes, not just \"it should be responsive.\"\n\n**When to consult this:** When specifying accessibility requirements (use WCAG success criteria references like \"WCAG 2.1 SC 1.4.3 — Contrast Minimum\"), when evaluating an interface against usability heuristics, or when defining responsive breakpoints.\n\n---\n\n## MT — Azure Well-Architected Framework\n\n**Standard:** [Azure Well-Architected Framework — Multi-Tenancy](https://learn.microsoft.com/en-us/azure/architecture/guide/multitenant/overview)\n\n**What it is:** Microsoft's comprehensive guidance on building multi-tenant SaaS applications, covering tenant isolation models, feature gating, metering, billing, and provisioning. While it's Azure-branded, the architectural patterns are cloud-agnostic.\n\n**How it informs MT documents:**\n- **Isolation models:**\n  - Row-level isolation: Single database, tenant_id column, enforced by RLS policies. Cheapest, hardest to guarantee isolation.\n  - Schema-per-tenant: Single database, separate schema per tenant. Middle ground.\n  - Database-per-tenant: Full isolation. Most expensive, easiest to guarantee.\n  - The framework helps evaluate trade-offs between cost, isolation guarantees, and operational complexity.\n- **Feature gating:** Mechanisms for enabling/disabling features per tenant or plan tier. Consider: feature flags, entitlement systems, plan-based checks.\n- **Metering dimensions:** What to meter (API calls, storage, users, compute), how to collect (real-time counters, batch aggregation), and how to bill (per-unit, tiered, flat-rate).\n- **Provisioning:** Tenant onboarding workflow — creating the tenant record, provisioning resources, configuring DNS/routing. Speed matters for self-service.\n- **Noisy neighbor prevention:** Rate limiting, resource quotas, fair scheduling — how to prevent one tenant from degrading the experience of others.\n\n**When to consult this:** When choosing a tenant isolation model, when designing feature gating, when defining metering and billing dimensions, when planning tenant provisioning flows, or when addressing noisy-neighbor concerns.\n\n---\n\n## Tier-Specific Standards Guidance\n\nThe four architectural tiers (Platform, Industry, Customer Workflow, Consumer Application) influence which standards are most relevant when writing requirements. The tier names below are the bundle defaults — consuming projects may rename or reduce the tier set in their own \\`docs/src/content/docs/project-context.md\\`.\n\n### Platform Tier\nAll category-specific standards apply at their full depth. Platform requirements define the core infrastructure that all other tiers depend on. Pay particular attention to:\n- **INT** — Enterprise Integration Patterns and OpenAPI for the headless API surface\n- **MT** — Azure Well-Architected Framework for tenant isolation (this is inherently platform-tier)\n- **SEC** — OWASP ASVS for the authentication/authorization framework\n- **NFR** — ISO 25010 quality targets for the shared infrastructure\n\n### Industry Tier\nRegulatory and compliance standards dominate. Industry requirements translate external mandates into platform capabilities:\n- **SEC** — NIST SP 800-53 controls mapped to industry-specific regulations\n- **INT** — Industry-specific interoperability standards\n- **DR** — DAMA-DMBOK data classification applied to industry-specific data sensitivity levels\n\n### Customer Workflow Tier\nFocus on configurability and business rules. Standards inform what the platform's workflow engine must support:\n- **FR** — BABOK/IEEE 830 for capturing the configurable business logic — emphasis on parameterization (what can the tenant change?) vs. fixed behavior\n- **BR** — BABOK stakeholder analysis, noting that the stakeholder is the tenant administrator who configures the workflow, not the end user\n\n### Consumer Application Tier\nFront-end and UX standards become primary. These requirements describe what consortium members or customers build on top of the platform:\n- **UX** — WCAG 2.1 accessibility requirements, Nielsen Norman heuristics for front-end usability\n- **FR** — IEEE 830 structured flows for user-facing interactions in the consuming application\n- **INT** — OpenAPI specifications for the API contracts the consumer application consumes (trace back to Platform INT requirements)\n\nNote: Consumer Application requirements follow the same rigor as Platform requirements. The tier distinction is architectural, not qualitative.\n\n---\n\n## Cross-Cutting References\n\nThese resources inform the overall taxonomy structure, traceability approach, and cross-referencing conventions across all categories:\n\n### BABOK Guide v3\n[IIBA BABOK Guide v3](https://www.iiba.org/business-analysis-certifications/iiba-certifications/ecba-certification/babok-guide-v3/)\n\nThe requirements classification schema (Business → Stakeholder → Solution → Transition) is the backbone of the taxonomy hierarchy. BABOK's traceability guidance directly informs the cross-referencing conventions used throughout.\n\n### IEEE 29148:2018\n[IEEE 29148:2018 — Systems and Software Engineering — Life Cycle Processes — Requirements Engineering](https://standards.ieee.org/ieee/29148/6937/)\n\nThe international standard for requirements engineering processes, covering elicitation, analysis, specification, and validation. Useful when thinking about the overall requirements process, not just individual document structure.\n\n### arc42\n[arc42 — Software Architecture Documentation](https://arc42.org/overview)\n\nA practical template for software architecture documentation. Influenced the separation between architectural decisions (ADR) and technical specifications (TR) and operational concerns (OPS) in this taxonomy.\n\n### C4 Model\n[C4 Model — Software Architecture Visualization](https://c4model.com/)\n\nSimon Brown's approach to visualizing software architecture at four levels of abstraction: Context, Container, Component, Code. Useful context for understanding how ADRs and TRs relate to system design at different levels.\n`;\n\n/**\n * Name of the user-invocable slash command that ships this bundle's\n * reference files. Projen synthesizes skill reference files under\n * `.claude/skills/<SKILL_NAME>/_references/`, so every path the\n * reviewer bundle reads derives from this single string.\n */\nconst WRITE_REQUIREMENT_SKILL_NAME = \"write-requirement\";\n\n/**\n * Root directory (relative to the project root) where the\n * `write-requirement` skill synthesizes its reference files.\n */\nconst WRITE_REQUIREMENT_REFERENCES_ROOT = `.claude/skills/${WRITE_REQUIREMENT_SKILL_NAME}/_references`;\n\n/**\n * Canonical paths to the reference files shipped by the\n * `requirements-writer` bundle. Consumed by the `requirements-reviewer`\n * bundle via `import { REQUIREMENTS_WRITER_PATHS }` so the reviewer's\n * prompt strings cannot drift from the actual synthesized locations.\n *\n * Values are derived from `WRITE_REQUIREMENT_SKILL_NAME` rather than\n * hard-coded: if the skill is ever renamed, both the skill definition\n * and every consumer that reads these constants move together.\n */\nexport const REQUIREMENTS_WRITER_PATHS = {\n  /** Directory containing the 13 category templates (trailing slash). */\n  templatesRoot: `${WRITE_REQUIREMENT_REFERENCES_ROOT}/templates/`,\n  /** The standards-and-frameworks reference document. */\n  standardsRef: `${WRITE_REQUIREMENT_REFERENCES_ROOT}/standards-and-frameworks.md`,\n} as const;\n\n/**\n * Regression eval suite shipped alongside the `write-requirement`\n * skill at `.claude/skills/write-requirement/evals/evals.json`. Each\n * entry exercises one branch of the decision-authority rules: pure\n * direct-write (BR/FR), partial-deferral with a Proposed ADR, and a\n * mixed prompt that must route an NFR and an OPS document correctly\n * while deferring tooling selection.\n *\n * Suites follow the skill-evals schema — see the `skill-evals` rule\n * content rendered by `./skill-evals.ts#renderSkillEvalsRuleContent`.\n */\nconst WRITE_REQUIREMENT_EVALS_JSON = JSON.stringify(\n  {\n    skill_name: \"write-requirement\",\n    evals: [\n      {\n        id: 1,\n        prompt:\n          \"We had a kickoff meeting where the team decided we need self-service event registration for B2B conferences. The main pain point is that current solutions take months to configure — operators send spreadsheets and wait weeks for changes. We want organizers to set up registration themselves. Target market is small to mid-size B2B conferences with 500-5000 registrants. Write the BR and FR requirements for this.\",\n        expected_output:\n          \"A BR document in the configured business-requirements directory capturing the business need (self-service registration, reduced configuration time, target market) with stakeholders, success metrics, and scope. One or more FR documents in the functional-requirements directory describing the self-service configuration workflow with user stories, main/alternative/exception flows, and acceptance criteria. All documents follow the category template exactly, carry YAML frontmatter, ship as status Draft, and include traceability links between the BR and FRs. No technology choices are made — any tech implications are deferred to Proposed ADR or TR documents.\",\n        files: [],\n        product_context_refs: [\n          \"Mission\",\n          \"In-Scope Capabilities\",\n          \"Out of Scope\",\n        ],\n      },\n      {\n        id: 2,\n        prompt:\n          \"We need to add payment processing to our platform. Registrants should be able to pay with credit cards and we need to support multiple registration tiers with different prices. Write the requirements for this.\",\n        expected_output:\n          \"FR documents covering payment processing (user-visible behavior: selecting a tier, entering payment, receiving confirmation) and registration tiers (configuring tiers, pricing, capacity). The FR documents do NOT select a specific payment provider — instead, a Proposed ADR is created listing payment provider options (e.g., Stripe, Braintree, Adyen) with pros/cons and a recommendation, with the Decision section set to 'Pending human review'. An INT document describes the integration shape (direction, error handling, SLA expectations) but defers provider selection to the ADR. Open items cross-reference the pending decision.\",\n        files: [],\n        product_context_refs: [\"Domain Vocabulary\"],\n      },\n      {\n        id: 3,\n        prompt:\n          \"Here are notes from our meeting: 'We discussed monitoring. The team agreed we need 99.9% uptime SLA, p99 latency under 200ms for registration API calls, and real-time alerting when error rates spike above 1%. Alice suggested Datadog, Bob preferred CloudWatch since we're already on AWS. No decision was made on tooling.' Write the requirements.\",\n        expected_output:\n          \"An NFR document with measurable targets (99.9% uptime, p99 < 200ms, error rate alerting threshold at 1%) — written directly as Draft. An OPS document describing monitoring and alerting requirements (what needs monitoring, alerting rules, incident response) — written directly for the requirements portion. A Proposed ADR or TR for the monitoring tooling decision, listing Datadog and CloudWatch as options with pros/cons, noting each team member's preference, and recommending one with rationale. The ADR/TR has status Proposed with an open item flagging human decision required. The OPS document references the pending tooling decision in its open items.\",\n        files: [],\n        product_context_refs: [\"Domain Vocabulary\"],\n      },\n    ],\n  },\n  null,\n  2,\n);\n\n/**\n * Reference files emitted alongside the SKILL.md. Keep this list synchronized\n * with the templates exported above; the bundle test asserts the count.\n */\nfunction buildRequirementsWriterReferenceFiles(\n  paths: ResolvedAgentPaths,\n): ReadonlyArray<{\n  readonly path: string;\n  readonly content: string;\n}> {\n  return [\n    {\n      path: \"_references/templates/_template-BR.md\",\n      content: templateBr(paths),\n    },\n    {\n      path: \"_references/templates/_template-FR.md\",\n      content: templateFr(paths),\n    },\n    {\n      path: \"_references/templates/_template-NFR.md\",\n      content: templateNfr(paths),\n    },\n    {\n      path: \"_references/templates/_template-TR.md\",\n      content: templateTr(paths),\n    },\n    {\n      path: \"_references/templates/_template-ADR.md\",\n      content: templateAdr(paths),\n    },\n    {\n      path: \"_references/templates/_template-SEC.md\",\n      content: templateSec(paths),\n    },\n    {\n      path: \"_references/templates/_template-DR.md\",\n      content: templateDr(paths),\n    },\n    {\n      path: \"_references/templates/_template-INT.md\",\n      content: templateInt(paths),\n    },\n    {\n      path: \"_references/templates/_template-OPS.md\",\n      content: templateOps(paths),\n    },\n    {\n      path: \"_references/templates/_template-UX.md\",\n      content: templateUx(paths),\n    },\n    {\n      path: \"_references/templates/_template-MT.md\",\n      content: templateMt(paths),\n    },\n    {\n      path: \"_references/templates/_template-category-README.md\",\n      content: TEMPLATE_CATEGORY_README,\n    },\n    {\n      path: \"_references/templates/_template-requirements-README.md\",\n      content: templateRequirementsReadme(paths),\n    },\n    {\n      path: \"_references/standards-and-frameworks.md\",\n      content: STANDARDS_AND_FRAMEWORKS,\n    },\n    {\n      path: \"evals/evals.json\",\n      content: WRITE_REQUIREMENT_EVALS_JSON,\n    },\n  ];\n}\n\n/**\n * Sub-agent that authors formal requirement documents using the\n * 11-category taxonomy (BR, FR, NFR, TR, ADR, SEC, DR, INT, OPS, UX, MT)\n * and the decision-authority rules (direct-write vs. propose-only ADR/TR).\n *\n * Picks up `req:write` issues created by the upstream `requirements-analyst`\n * bundle's trace phase, reads the matching template from the skill's\n * reference directory, and writes a single requirement document per\n * session under the configured `<REQUIREMENTS_ROOT>`.\n *\n * This agent writes **requirement documents only** — capability models\n * are the responsibility of the `bcm-writer` agent and gap discovery is\n * the responsibility of the `requirements-analyst` agent.\n */\nfunction buildRequirementsWriterSubAgent(\n  paths: ResolvedAgentPaths,\n): AgentSubAgent {\n  return {\n    name: \"requirements-writer\",\n    description:\n      \"Writes formal requirement documents (BR, FR, NFR, TR, ADR, SEC, DR, INT, OPS, UX, MT) from upstream proposals using the 11-category taxonomy, the four-tier classification, and the decision-authority rules (direct-write vs. propose-only ADR/TR). Handles one req:write issue per session. Produces requirement documents — not capability models or gap reports.\",\n    model: AGENT_MODEL.POWERFUL,\n    maxTurns: 80,\n    platforms: { cursor: { exclude: true } },\n    prompt: [\n      \"# Requirements Writer Agent\",\n      \"\",\n      \"You author formal requirement documents using the 11-category\",\n      \"taxonomy (BR, FR, NFR, TR, ADR, SEC, DR, INT, OPS, UX, MT) and the\",\n      \"four-tier architectural classification (Platform, Industry, Customer\",\n      \"Workflow, Consumer Application). Each session handles exactly **one**\",\n      \"`req:write` issue and writes exactly **one** requirement document.\",\n      \"\",\n      \"This agent produces **requirement documents only** — capability\",\n      \"models are written by the `bcm-writer` agent and requirement-gap\",\n      \"discovery is the responsibility of the `requirements-analyst` agent.\",\n      \"Keep this boundary clean: never open `req:scan`,\",\n      \"`req:draft-trace`, or `bcm:*` issues from this pipeline.\",\n      \"\",\n      \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n      \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...PROJECT_CONTEXT_READER_SECTION,\n      \"## Design Principles\",\n      \"\",\n      \"1. **One requirement per session.** Each `req:write` issue maps to a\",\n      \"   single requirement document. Never write two documents in one\",\n      \"   session and never start a second issue.\",\n      \"2. **Templates are authoritative.** Every category has a template\",\n      \"   under `<TEMPLATES_ROOT>`. Use it verbatim — do not invent new\",\n      \"   sections or reorder existing ones. A section that does not apply\",\n      \"   gets `Not applicable — <reason>` rather than being omitted.\",\n      \"3. **Decision authority is non-negotiable.** Direct-write categories\",\n      \"   ship as `Status: Draft`. ADR and TR documents ship as\",\n      \"   `Status: Proposed` with a Recommendation that frames a human\",\n      \"   decision — never decide for the human.\",\n      \"4. **Trace upstream.** Every requirement links back to the proposal\",\n      \"   that produced it, the source document(s) cited in that proposal,\",\n      \"   and the upstream BCM capability or business need it serves.\",\n      \"5. **Cite, don't invent.** When the proposal does not supply a\",\n      \"   stakeholder, metric, threat model entry, or technology option,\",\n      \"   write `TODO:` and flag the issue with `status:needs-attention`\",\n      \"   rather than fabricating content.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Configurable Paths\",\n      \"\",\n      \"The pipeline uses these placeholders. Consuming projects override the\",\n      \"defaults by passing paths in the `/write-requirement` skill\",\n      `invocation, by recording overrides in \\`${paths.docsRoot}/project-context.md\\`, or`,\n      \"by extending this rule in their own `agentConfig.rules`.\",\n      \"\",\n      \"| Placeholder | Meaning | Default |\",\n      \"|-------------|---------|---------|\",\n      `| \\`<REQUIREMENTS_ROOT>\\` | Root folder for final requirement documents | \\`${paths.requirementsRoot}/\\` |`,\n      `| \\`<RESEARCH_REQUIREMENTS_ROOT>\\` | Where the upstream \\`requirements-analyst\\` writes proposals | \\`${paths.researchRequirementsRoot}/\\` |`,\n      `| \\`<TEMPLATES_ROOT>\\` | Where the category templates ship (set automatically by this bundle) | \\`${REQUIREMENTS_WRITER_PATHS.templatesRoot}\\` |`,\n      `| \\`<STANDARDS_REF>\\` | Standards & frameworks reference document | \\`${REQUIREMENTS_WRITER_PATHS.standardsRef}\\` |`,\n      `| \\`<PREFIX>\\` | Project-specific requirement ID prefix | none — requirement IDs use the category prefix (\\`BR\\`, \\`FR\\`, …) unless \\`${paths.docsRoot}/project-context.md\\` defines a project prefix |`,\n      \"\",\n      `If \\`${paths.docsRoot}/project-context.md\\` specifies a different requirements tree,`,\n      \"prefer that. Otherwise fall back to the defaults above.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...REQUIREMENTS_TAXONOMY_TABLE_SECTION,\n      \"\",\n      \"### Disambiguation Rules\",\n      \"\",\n      \"Apply these rules when deciding where a requirement belongs:\",\n      \"\",\n      ...REQUIREMENTS_TAXONOMY_DISAMBIGUATION_SECTION,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Architectural Tiers\",\n      \"\",\n      \"Every requirement also belongs to one of four architectural tiers.\",\n      'Tier is **orthogonal** to category — category answers \"what kind\"',\n      'while tier answers \"where in the architecture.\" The tier names below',\n      \"are the bundle defaults; consuming projects may rename or reduce the\",\n      `tier set in their own \\`${paths.docsRoot}/project-context.md\\`.`,\n      \"\",\n      ...REQUIREMENTS_TIER_TABLE_SECTION,\n      \"\",\n      \"Tier is a **required metadata field**. Set it in the Metadata table\",\n      \"of every requirement document and apply the matching `tier:*` issue\",\n      \"label (`tier:platform`, `tier:industry`, `tier:customer-workflow`,\",\n      \"or `tier:consumer-app`).\",\n      \"\",\n      \"**Customer field (optional).** When the proposal originated from or\",\n      \"applies to a specific customer, set the `Customer` field in the\",\n      \"Metadata table. Optional for Platform/Industry tiers, expected for\",\n      \"Customer Workflow / Consumer Application tiers when the project\",\n      \"tracks customer profiles.\",\n      \"\",\n      \"**Implementor field (tier-specific).** For Customer Workflow and\",\n      \"Consumer Application tiers, set the `Implementor` field (Consortium\",\n      \"Member / Customer / TBD) when the project tracks that distinction.\",\n      \"Skip the field entirely if it does not apply to your project.\",\n      \"\",\n      \"**Cross-tier traceability.** Higher-tier requirements must link to\",\n      \"lower-tier requirements they depend on using `Depends on (cross-tier)`\",\n      \"links in the Traceability section. For example, a Consumer\",\n      \"Application FR for an intake portal must trace to the Platform INT\",\n      \"for the API it consumes.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Decision Authority Rules\",\n      \"\",\n      \"**This is the most important section.** Not all categories are\",\n      \"treated equally. The core principle is: **requirements that describe\",\n      \"*what* and *why* get written directly; decisions about *how* and\",\n      \"*with what* are deferred to humans.**\",\n      \"\",\n      \"### Write Directly (status: `Draft`)\",\n      \"\",\n      \"These categories describe business needs, user behavior, quality\",\n      \"targets, security posture, and user experience. The writer has full\",\n      \"authority to produce these documents:\",\n      \"\",\n      \"- **BR** — Business Requirements\",\n      \"- **FR** — Functional Requirements\",\n      \"- **NFR** — Non-Functional Requirements\",\n      \"- **SEC** — Security & Compliance\",\n      \"- **UX** — UX Requirements\",\n      \"\",\n      \"### Write with Partial Deferral\",\n      \"\",\n      \"These categories contain a mix of *what* (write directly) and *how*\",\n      \"(defer). Write the requirement portions directly but defer\",\n      \"technology/tooling selections:\",\n      \"\",\n      \"- **DR** — Write data models, retention policies, and classification\",\n      \"  directly. When backup strategy or storage technology must be\",\n      \"  specified, create a `Proposed` ADR or TR instead of choosing.\",\n      \"- **MT** — Write tenant isolation requirements and metering\",\n      \"  dimensions directly. When the isolation *model* must be chosen\",\n      \"  (row-level vs schema-per-tenant vs database-per-tenant), create a\",\n      \"  `Proposed` ADR instead of choosing.\",\n      \"- **INT** — Write the integration shape, direction, error handling\",\n      \"  strategy, and SLA expectations directly. When the specific\",\n      \"  provider must be selected, create a `Proposed` TR/ADR instead.\",\n      \"- **OPS** — Write operational requirements (monitoring needs,\",\n      \"  incident response, deployment strategy) directly. When specific\",\n      \"  tooling must be selected, create a `Proposed` TR/ADR instead.\",\n      \"\",\n      \"### Propose Only (status: `Proposed`, pending human decision)\",\n      \"\",\n      \"These categories represent technology and architecture decisions\",\n      \"that humans must make. Produce complete documents with all the\",\n      \"information needed for the decision, but **do not make the decision\",\n      \"itself**.\",\n      \"\",\n      \"- **ADR** — Write the full document following the ADR template:\",\n      \"  1. **Context** — forces at play, constraints, what prompted the\",\n      \"     decision\",\n      '  2. **Decision** — set to: *\"Pending human review. See',\n      '     Recommendation below.\"*',\n      \"  3. **Alternatives Considered** — every viable option with\",\n      \"     equal-depth analysis. Each gets a description, pros, and cons.\",\n      \"     Do not shortchange options you don't prefer.\",\n      \"  4. **Recommendation** — state which option you recommend, *why*\",\n      \"     it's the best fit for the context, and what trade-offs are\",\n      \"     accepted. The reasoning must be specific to this project's\",\n      \"     situation — not generic.\",\n      \"  5. **Consequences** — positive, negative, and neutral consequences\",\n      \"     of the recommended option\",\n      \"  6. Set status to `Proposed`. Add an open item flagging that a\",\n      \"     human decision is required before dependent requirements can\",\n      \"     proceed.\",\n      \"\",\n      \"- **TR** — Write the full document following the TR template:\",\n      '  1. **Technology Choice** — set to: *\"Pending human review. See',\n      '     Recommendation below.\"*',\n      \"  2. **Alternatives Considered** — every viable technology option\",\n      \"     with description, pros, cons, license, and maturity assessment\",\n      \"     for each\",\n      \"  3. **Recommendation** — state which technology you recommend,\",\n      \"     *why*, and what trade-offs are accepted\",\n      '  4. **Rationale** — set to: *\"See Recommendation above. Awaiting',\n      '     human decision.\"*',\n      \"  5. Set status to `Proposed`. Add an open item flagging that a\",\n      \"     human decision is required.\",\n      \"\",\n      \"### How Deferral Works in Practice\",\n      \"\",\n      \"When writing a requirement that implies a technology choice:\",\n      \"\",\n      \"1. Write the requirement itself (FR, DR, INT, OPS, etc.) with full\",\n      \"   detail.\",\n      \"2. Where the requirement needs a technology decision, add a note:\",\n      `   *\"Technology selection pending — see [ADR-NNN](../${paths.requirementCategoryDirs.architecturalDecisions}/ADR-NNN-slug.md)\"*.`,\n      \"3. Create the corresponding ADR or TR as `Proposed` with options,\",\n      \"   pros/cons, and recommendation.\",\n      '4. In the ADR/TR open items, add: *\"Human decision required.',\n      '   Dependent requirements: [list]\"*.',\n      \"5. In the original requirement's open items, add a cross-reference:\",\n      `   *\"Blocked by [ADR-NNN](../${paths.requirementCategoryDirs.architecturalDecisions}/ADR-NNN-slug.md) —`,\n      '   technology selection pending human review.\"*',\n      \"\",\n      \"This creates a clear chain: the requirement is understood, the\",\n      \"decision is framed with all necessary information, and the\",\n      \"dependency is tracked in both directions.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## File Naming Convention\",\n      \"\",\n      \"Every requirement file follows this pattern:\",\n      \"\",\n      \"```\",\n      \"{PREFIX}-{NNN}-{slug}.md\",\n      \"```\",\n      \"\",\n      \"- **PREFIX** — category abbreviation (`BR`, `FR`, `NFR`, `TR`,\",\n      \"  `ADR`, `SEC`, `DR`, `INT`, `OPS`, `UX`, `MT`). If the project\",\n      `  declares a project-wide prefix in \\`${paths.docsRoot}/project-context.md\\`, use`,\n      \"  it instead.\",\n      \"- **NNN** — sequential number, zero-padded to at least three\",\n      \"  digits (001, 002, 012; grows past 999 naturally, e.g. 1240). The\",\n      \"  ID is **finalized at write-start** via\",\n      \"  `.claude/procedures/next-requirement-id.sh`, which allocates from\",\n      \"  live state (existing docs plus open `req:write` issues). Scanning\",\n      \"  the target category directory under `<REQUIREMENTS_ROOT>` for the\",\n      \"  next available number is the **fallback** used only when that\",\n      \"  procedure is unavailable.\",\n      \"- **slug** — lowercase kebab-case descriptive name.\",\n      \"\",\n      \"Examples: `FR-001-user-registration.md`,\",\n      \"`ADR-003-database-selection.md`,\",\n      \"`SEC-001-authentication-framework.md`.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Frontmatter\",\n      \"\",\n      \"Every `.md` requirement file must begin with a YAML frontmatter\",\n      \"block. The minimum required fields are `title` and `description`:\",\n      \"\",\n      \"```markdown\",\n      \"---\",\n      'title: \"FR-001: User Registration\"',\n      'description: \"Functional requirement for the user registration workflow.\"',\n      \"tier: platform\",\n      \"---\",\n      \"\",\n      \"...\",\n      \"```\",\n      \"\",\n      \"Titles containing colons must be wrapped in double quotes. The\",\n      \"`tier` field must be one of `platform`, `industry`,\",\n      \"`customer-workflow`, or `consumer-app` (use whatever tier slugs the\",\n      \"project declares).\",\n      \"\",\n      \"### Optional traceability extensions\",\n      \"\",\n      \"Projects that publish requirements through Starlight, Astro, or a\",\n      \"similar static-site generator may add structured traceability fields\",\n      \"to frontmatter. One example: a `referencedIn.meetings[]` block that\",\n      \"links the requirement back to a meeting transcript that informed it.\",\n      \"These conventions are **optional** — adopt them only if your project\",\n      \"already maintains the matching reverse-link structures.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Status Lifecycle\",\n      \"\",\n      \"Every requirement has a status that tracks where it is in its\",\n      \"lifecycle:\",\n      \"\",\n      \"| Status | Meaning |\",\n      \"|---|---|\",\n      \"| `Draft` | Initial capture, under discussion |\",\n      \"| `Proposed` | Formally proposed, awaiting review — **used for ADR and TR documents pending human decision** |\",\n      \"| `Accepted` | Approved and active |\",\n      \"| `Implemented` | Fully delivered |\",\n      \"| `Deprecated` | No longer applicable |\",\n      \"| `Superseded` | Replaced by another requirement (link to successor) |\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Traceability\",\n      \"\",\n      \"Every requirement document must include a `## Traceability` section.\",\n      \"Use relative markdown links with the requirement ID as link text.\",\n      \"\",\n      \"```markdown\",\n      \"## Traceability\",\n      \"\",\n      `- **Implements:** [BR-001](../${paths.requirementCategoryDirs.business}/BR-001-self-service-onboarding.md)`,\n      `- **Constrained by:** [NFR-001](../${paths.requirementCategoryDirs.nonFunctional}/NFR-001-api-response-times.md)`,\n      `- **Related:** [SEC-001](../${paths.requirementCategoryDirs.security}/SEC-001-authentication-framework.md)`,\n      \"```\",\n      \"\",\n      \"### Link Types\",\n      \"\",\n      \"| Link Type | Meaning |\",\n      \"|---|---|\",\n      \"| **Implements** | This requirement realizes a higher-level requirement |\",\n      \"| **Constrained by** | This requirement is bounded by another requirement |\",\n      \"| **Supports** | This requirement contributes to but does not fully realize another |\",\n      \"| **Supersedes** | This requirement replaces a deprecated one |\",\n      \"| **Related** | Informational relationship |\",\n      \"\",\n      \"### Dependency Flow\",\n      \"\",\n      \"```\",\n      \"Business Requirements (BR)\",\n      \"    -> justify epics and initiatives\",\n      \"\",\n      \"Functional (FR), Integration (INT), Multi-Tenancy (MT)\",\n      \"    -> decompose into feature work\",\n      \"\",\n      \"NFRs, Security (SEC), UX\",\n      \"    -> appear as acceptance criteria AND as standalone requirements\",\n      \"\",\n      \"Architectural Decisions (ADR)\",\n      \"    -> spawn implementation tasks and serve as context for TRs\",\n      \"\",\n      \"Technical (TR), Data (DR), Operational (OPS)\",\n      \"    -> drive infrastructure and platform work\",\n      \"```\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Open Items\",\n      \"\",\n      \"Every requirement document must end with a `## Open Items` section\",\n      \"(placed just above `## Revision History`). This section surfaces\",\n      \"things that need human attention.\",\n      \"\",\n      \"### Priority Levels\",\n      \"\",\n      \"| Priority | Meaning |\",\n      \"|---|---|\",\n      \"| **P0 — Blocker** | Cannot proceed with implementation until resolved |\",\n      \"| **P1 — High** | Significantly affects scope, security, or architecture |\",\n      \"| **P2 — Medium** | Affects quality or completeness but doesn't block progress |\",\n      \"| **P3 — Low** | Minor clarification, can be resolved asynchronously |\",\n      \"\",\n      \"### Subsection Types\",\n      \"\",\n      \"- **Identified Gaps** — Missing functionality, unhandled edge cases,\",\n      \"  incomplete aspects\",\n      \"- **Follow-up Questions** — Ambiguities where intent cannot be\",\n      \"  confidently inferred\",\n      \"- **Contradictions & Inconsistencies** — Conflicts between\",\n      \"  requirements, documentation, or stated goals\",\n      \"\",\n      \"Number each item within its subsection. Assign a priority. Call out\",\n      \"interdependencies with open items in other documents using the\",\n      `format: \\`-> Depends on: [FR-001 Open Item #2](../${paths.requirementCategoryDirs.functional}/FR-001-slug.md#open-items)\\`.`,\n      \"\",\n      \"The `## Open Items` section is **not optional** — it appears in every\",\n      'document, even if a subsection is empty (write \"None identified.\").',\n      \"\",\n      \"---\",\n      \"\",\n      \"## Reading the Templates and Standards Reference\",\n      \"\",\n      \"Before writing any requirement document:\",\n      \"\",\n      \"1. **Read the matching template** under `<TEMPLATES_ROOT>` for the\",\n      \"   category specified in the issue (`_template-FR.md`,\",\n      \"   `_template-ADR.md`, etc.). Templates are named\",\n      \"   `_template-{PREFIX}.md`. Every section in the template must\",\n      \"   appear in the final document.\",\n      \"\",\n      \"2. **Read `<STANDARDS_REF>`** if the category requires it (especially\",\n      \"   SEC, NFR, INT, ADR, TR). The reference covers OWASP ASVS, ISO\",\n      \"   25010, BABOK, MADR, Enterprise Integration Patterns, WCAG, and\",\n      \"   related standards that ground the templates.\",\n      \"\",\n      \"Templates and the standards reference ship with this skill — they\",\n      \"are the same files for every project that adopts the bundle.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Maintaining the Registry Index\",\n      \"\",\n      \"Each category directory contains a `README.md` (or `_index.md`,\",\n      \"depending on project convention) that lists every requirement in\",\n      \"that category. **After writing any new requirement document, update\",\n      \"the category index:**\",\n      \"\",\n      \"1. Read the index file in the same directory as the new requirement.\",\n      \"2. Add a row to the requirements table with: ID (linked to the\",\n      \"   file), Title, Status, Priority, Last Updated date.\",\n      \"3. Insert the row in sequence-number order.\",\n      \"4. If the index contains a placeholder message, remove it.\",\n      \"\",\n      \"If the project has not seeded category READMEs yet, generate one\",\n      \"from `_template-category-README.md` (shipped with this skill) and\",\n      \"commit it alongside the requirement document.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Agent Loop\",\n      \"\",\n      \"Run this loop exactly once per session. Never start a second issue.\",\n      \"\",\n      \"1. Claim one open `req:write` issue (also carries `type:requirement`\",\n      \"   and a `tier:*` label).\",\n      \"2. Transition `status:ready` → `status:in-progress` and create the\",\n      \"   branch per your project's branch-naming convention.\",\n      \"3. Execute the write phase below.\",\n      \"4. Commit, push, open a PR, and close the issue per your project's\",\n      \"   PR workflow. Closing the PR transitions the issue to\",\n      \"   `status:done` per the standard label conventions.\",\n      \"   Stamp every PR you open with the `origin:agent` label — see the\",\n      \"   **Origin label** section below.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...renderClaimVerificationSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderOriginStampSection(),\n      \"\",\n      \"---\",\n      \"\",\n      \"## The `req:write` Issue Schema\",\n      \"\",\n      \"This section is the **authoritative schema** for `req:write` issue\",\n      \"bodies. Upstream producers (the `requirements-analyst` trace phase,\",\n      \"the `requirements-reviewer` follow-up generator, and any human\",\n      \"authoring a `req:write` issue directly) must embed or link to this\",\n      \"same schema so the three required fields are always present when\",\n      \"the writer picks the issue up.\",\n      \"\",\n      ...REQ_WRITE_ISSUE_SCHEMA_SECTION,\n      \"\",\n      \"---\",\n      \"\",\n      \"## The `req:write` Phase\",\n      \"\",\n      \"**Goal:** Read the proposal that produced this issue, write a single\",\n      \"requirement document under `<REQUIREMENTS_ROOT>`, and update the\",\n      \"category index.\",\n      \"\",\n      \"**Budget:** Read the issue body, the named proposal file under\",\n      \"`<RESEARCH_REQUIREMENTS_ROOT>`, the matching category template under\",\n      \"`<TEMPLATES_ROOT>`, and `<STANDARDS_REF>` if the category needs it.\",\n      \"Write one requirement document and one category-index update. No web\",\n      \"searches.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Parse the issue.** The `req:write` issue body follows the\",\n      \"   authoritative schema in the\",\n      \"   [The `req:write` Issue Schema](#the-reqwrite-issue-schema)\",\n      \"   section below. Before writing, verify every required field\",\n      \"   (Category, Tier, Output Path) is present and internally\",\n      \"   consistent:\",\n      \"\",\n      \"   - Category matches the prefix on the requirement title and on\",\n      \"     the Output Path filename.\",\n      \"   - Tier matches the `tier:*` label applied to the issue.\",\n      \"   - Output Path sits under\",\n      \"     `<REQUIREMENTS_ROOT>/<category-dir>/<PREFIX>-<NNN>-<slug>.md`.\",\n      \"\",\n      \"   If any required field is missing, contradictory, or the issue\",\n      \"   already carries `status:needs-attention` with a `Missing:` line\",\n      \"   (upstream could not derive it), comment on the issue with\",\n      \"   which field is wrong, ensure `status:needs-attention` is set,\",\n      \"   and stop without writing. A human triages before the writer\",\n      \"   tries again.\",\n      \"\",\n      \"2. **Read the proposal.** Open the proposals file referenced in the\",\n      \"   issue inputs (under `<RESEARCH_REQUIREMENTS_ROOT>`). Find the\",\n      \"   specific proposal entry that matches this requirement's title and\",\n      \"   category. Treat the proposal as the authoritative source — do not\",\n      \"   invent fields it omits.\",\n      \"\",\n      \"3. **Read the matching template** under `<TEMPLATES_ROOT>` for the\",\n      \"   category. Read `<STANDARDS_REF>` if the category is SEC, NFR,\",\n      \"   INT, ADR, or TR — these depend on the standards reference for\",\n      \"   correct framing.\",\n      \"\",\n      \"4. **Finalize the requirement ID first — before you author any\",\n      \"   document content, filename, or self-reference.** Run\",\n      \"   `.claude/procedures/next-requirement-id.sh <PREFIX> <category-dir> <this-issue-number>`\",\n      \"   to compute the next free ID from live state (existing docs plus\",\n      \"   open `req:write` issues, with the issue-number tiebreak). Use\",\n      \"   `<category-dir>` = the resolved `<REQUIREMENTS_ROOT>/<category-dir>`\",\n      \"   for the target category, and `<this-issue-number>` = the number of\",\n      \"   the `req:write` issue you are working.\",\n      \"\",\n      \"   - If the issue's reserved `Requirement ID` hint is present **and\",\n      \"     equals** the procedure's output, use it.\",\n      \"   - Otherwise use the **procedure's output** — a concurrent claim\",\n      \"     took the reserved number, and the procedure has already resolved\",\n      \"     the collision in your favor via the issue-number order.\",\n      \"\",\n      \"   **Author the document exactly once with this finalized ID** — the\",\n      \"   filename and every in-body self-reference. **Never renumber after\",\n      \"   authoring:** the ID is fixed before any body content exists, so a\",\n      \"   concurrent claim is resolved here for free — no rename, no\",\n      \"   self-reference rewrite, no post-authoring renumber treadmill.\",\n      \"\",\n      \"   After finalizing, and before opening the PR, you SHOULD update this\",\n      \"   issue's `Requirement ID` field to the finalized value\",\n      \"   (`gh issue edit <this-issue-number>`) so other in-flight writers\",\n      \"   see the resolved claim. This is best-effort — do not block or fail\",\n      \"   the write if the edit does not succeed.\",\n      \"\",\n      \"   If `next-requirement-id.sh` is unavailable, fall back to scanning\",\n      \"   the target category directory under `<REQUIREMENTS_ROOT>` for\",\n      \"   existing files matching `{PREFIX}-NNN-*.md` and take the next\",\n      \"   unused three-digit number.\",\n      \"\",\n      \"5. **Apply the decision-authority rules.** Default to `Status:\",\n      \"   Draft` for direct-write categories (BR, FR, NFR, SEC, UX). Set\",\n      \"   `Status: Proposed` for ADR and TR documents and frame the\",\n      \"   Recommendation section as a human decision. For DR/MT/INT/OPS\",\n      \"   categories that imply a technology choice, write the requirement\",\n      \"   directly but spin the technology decision off into a separate\",\n      \"   `Proposed` ADR or TR — record the cross-link in the Open Items\",\n      \"   section of both documents.\",\n      \"\",\n      \"6. **Write the document.** Fill every section in the template. For\",\n      \"   sections the proposal does not supply, write `TODO:` plus a brief\",\n      \"   note describing what input is needed, and add a corresponding\",\n      \"   `## Open Items` entry. Never leave a template section out.\",\n      \"\",\n      \"7. **Set frontmatter.** At minimum: `title`, `description`, `tier`.\",\n      \"   If the project declares optional frontmatter conventions in\",\n      `   \\`${paths.docsRoot}/project-context.md\\` (such as \\`referencedIn.meetings[]\\`),`,\n      \"   honor them. Otherwise stop at the minimum.\",\n      \"\",\n      \"8. **Update the category index.** If the category directory has a\",\n      \"   `README.md` or `_index.md` registry, add a row for the new\",\n      \"   document in sequence order. If no index exists yet, generate one\",\n      \"   from `_template-category-README.md`. The requirement ID was\",\n      \"   already finalized at write-start (step 4), so this is a plain\",\n      \"   append-only, deterministic row insert — never renumber existing\",\n      \"   rows or mutate a sequence counter here.\",\n      \"\",\n      \"9. **Cross-link upstream.** Add `## Traceability` entries pointing\",\n      \"   to the proposals file (under `<RESEARCH_REQUIREMENTS_ROOT>`),\",\n      \"   the source documents the proposal cited, and any BCM capability\",\n      \"   the requirement supports.\",\n      \"\",\n      \"10. **Quality checks.** Before committing, verify:\",\n      \"    - [ ] Frontmatter has `title` and `description` (and `tier` if\",\n      \"          the project uses tier classification)\",\n      \"    - [ ] Title matches the `# Heading` line\",\n      \"    - [ ] File name follows `{PREFIX}-{NNN}-{slug}.md`\",\n      \"    - [ ] Status is `Draft` for direct-write categories or `Proposed`\",\n      \"          for ADR/TR\",\n      \"    - [ ] Every template section is present (use `TODO:` or `Not\",\n      \"          applicable — <reason>` for unfilled sections)\",\n      \"    - [ ] `## Traceability` exists with at least one upstream link\",\n      \"    - [ ] No technology decisions made in direct-write categories —\",\n      \"          deferred to `Proposed` ADR/TR with cross-links in Open\",\n      \"          Items\",\n      \"    - [ ] `## Open Items` is present with Identified Gaps,\",\n      \"          Follow-up Questions, and Contradictions subsections\",\n      \"    - [ ] ADR/TR documents include a Recommendation section and an\",\n      \"          Open Item flagging the human decision required\",\n      \"    - [ ] Category index updated with a row for the new document\",\n      \"    - [ ] Tier value matches the issue's `tier:*` label\",\n      \"    - [ ] Cross-tier traceability entries exist where the document\",\n      \"          depends on or enables a different tier\",\n      \"\",\n      \"11. **Commit and push.** Use a `docs(<category>):` conventional\",\n      \"    commit message. The PR closes the `req:write` issue.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Output Boundaries\",\n      \"\",\n      \"This agent writes **only** to:\",\n      \"\",\n      \"- `<REQUIREMENTS_ROOT>/<category-dir>/<PREFIX>-<NNN>-<slug>.md` — one\",\n      \"  requirement document per session\",\n      \"- `<REQUIREMENTS_ROOT>/<category-dir>/README.md` (or `_index.md`) —\",\n      \"  category index, one row appended per session\",\n      \"- `<REQUIREMENTS_ROOT>/README.md` (or `_index.md`) — only if the\",\n      \"  top-level requirements README does not yet exist; generate from\",\n      \"  `_template-requirements-README.md` and stop\",\n      \"\",\n      \"The pipeline produces **requirement documents**. It does not write\",\n      \"BCM capability models, people profiles, company profiles, software\",\n      \"profiles, scan reports, or proposal files — those belong to\",\n      \"specialized upstream/downstream agents.\",\n      \"\",\n      \"**Do NOT create:**\",\n      \"- `req:scan` or `req:draft-trace` issues — those belong to\",\n      \"  the `requirements-analyst` bundle\",\n      \"- `bcm:*` issues — those belong to the `bcm-writer` bundle\",\n      \"- `people:*`, `company:*`, `software:*`, `research:*`, or\",\n      \"  `industry:*` issues — those belong to their respective bundles\",\n      \"\",\n      \"If the proposal surfaces work that needs one of the above, comment\",\n      \"on the `req:write` issue with the suggested follow-up and let a\",\n      \"human route it.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Coordination with Other Agents\",\n      \"\",\n      \"| Direction | Agent | What |\",\n      \"|-----------|-------|------|\",\n      \"| Upstream | `requirements-analyst` | Discovers gaps, drafts proposals, and creates `req:write` issues that this agent picks up |\",\n      \"| Upstream | `bcm-writer` | Provides BCM capability documents that requirements trace back to via `## Traceability` links |\",\n      \"| Peer | `meeting-analyst` | Provides meeting transcripts that may inform a requirement's traceability extensions (optional) |\",\n      \"\",\n      \"**File boundaries:** Reads `<RESEARCH_REQUIREMENTS_ROOT>` (proposals)\",\n      \"and the source documents the proposals cite. Writes\",\n      \"`<REQUIREMENTS_ROOT>` and the category index files. Never edits\",\n      \"proposals, scan reports, BCM documents, or profiles.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Rules\",\n      \"\",\n      \"- **One requirement per session.** Never write two documents in one\",\n      \"  session and never start a second issue.\",\n      \"- **Templates are authoritative.** Use the shipped template verbatim\",\n      \"  for the category. Every template section must appear in the final\",\n      \"  document.\",\n      \"- **Decision authority is non-negotiable.** Direct-write categories\",\n      \"  ship as `Draft`. ADR and TR ship as `Proposed` with a Recommendation\",\n      \"  framed for human decision. Mixed-deferral categories spin\",\n      \"  technology choices off into separate `Proposed` documents.\",\n      \"- **Cite, don't invent.** When the proposal omits a stakeholder,\",\n      \"  metric, threat model entry, or technology option, write `TODO:` and\",\n      \"  flag the issue with `status:needs-attention`.\",\n      \"- **Trace upstream.** Every requirement links back to its proposal,\",\n      \"  the source documents the proposal cited, and the BCM capability\",\n      \"  it supports (when applicable).\",\n      \"- **Update the category index every time.** A requirement that\",\n      \"  exists as a file but is missing from its category index is\",\n      \"  invisible to anyone browsing the documentation tree.\",\n      \"- **Write requirements, not capability models or gap reports.**\",\n      \"  Never open `req:scan`, `req:draft-trace`, or `bcm:*` issues from\",\n      \"  this pipeline.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off a requirement-writing session. */\nfunction buildWriteRequirementSkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: WRITE_REQUIREMENT_SKILL_NAME,\n    description:\n      \"Write one formal requirement document (BR / FR / NFR / TR / ADR / SEC / DR / INT / OPS / UX / MT) using the shipped category template and decision-authority rules. Picks up a req:write issue created by the upstream requirements-analyst pipeline (or kicked off ad hoc) and dispatches the requirements-writer agent.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"requirements-writer\",\n    platforms: { cursor: { exclude: true } },\n    referenceFiles: buildRequirementsWriterReferenceFiles(paths),\n    instructions: [\n      \"# Write Requirement\",\n      \"\",\n      \"Write one formal requirement document using the 11-category taxonomy\",\n      \"(BR, FR, NFR, TR, ADR, SEC, DR, INT, OPS, UX, MT) and the\",\n      \"decision-authority rules (direct-write vs. propose-only ADR/TR).\",\n      \"Dispatches the `requirements-writer` agent.\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/write-requirement <category> <short-title>\",\n      \"\",\n      \"Where `<category>` is one of `BR`, `FR`, `NFR`, `TR`, `ADR`, `SEC`,\",\n      \"`DR`, `INT`, `OPS`, `UX`, `MT`.\",\n      \"\",\n      \"Optional extensions in the issue body:\",\n      \"- `tier: platform | industry | customer-workflow | consumer-app` —\",\n      \"  the architectural tier (default: `platform`)\",\n      \"- `prefix: <PROJECT_PREFIX>` — override the default category prefix\",\n      `  with a project-specific one declared in \\`${paths.docsRoot}/project-context.md\\``,\n      \"- `customer: <link-or-slug>` — link the requirement to a customer\",\n      \"  profile (expected for Customer Workflow / Consumer Application\",\n      \"  tiers in projects that track customer profiles)\",\n      \"- `proposal: <path>` — pin the upstream proposal file under\",\n      \"  `<RESEARCH_REQUIREMENTS_ROOT>` (default: derived from the issue\",\n      \"  context)\",\n      \"- `output: <path>` — override the default Output Path\",\n      \"\",\n      \"## Default Paths\",\n      \"\",\n      `If the project has no override in \\`${paths.docsRoot}/project-context.md\\` or`,\n      \"`agentConfig.rules`, outputs land under:\",\n      \"\",\n      `- \\`${paths.requirementsRoot}/<category-dir>/<PREFIX>-<NNN>-<slug>.md\\``,\n      `- \\`${paths.requirementsRoot}/<category-dir>/README.md\\` (registry update)`,\n      `- \\`${paths.requirementsRoot}/README.md\\` (top-level README, generated on`,\n      \"  first use only)\",\n      \"\",\n      \"Templates and the standards reference ship with this skill under\",\n      \"`_references/templates/` and `_references/standards-and-frameworks.md`.\",\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `req:write` issue with `type:requirement`,\",\n      `   \\`priority:${labelsForPhase(issueDefaults, \"req:write\").priority}\\`, \\`status:${labelsForPhase(issueDefaults, \"req:write\").status}\\`, and the matching \\`tier:*\\` label.`,\n      \"   Body must include the category, tier, output path, and a pointer\",\n      \"   to the upstream proposal (or a direct user description if no\",\n      \"   proposals file exists).\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute the write phase of the requirements-writer agent.\",\n      \"3. The agent writes one requirement document, updates the category\",\n      \"   index, opens a PR, and closes the issue.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- One requirement document under `<REQUIREMENTS_ROOT>` following the\",\n      \"  shipped category template, with `Status: Draft` for direct-write\",\n      \"  categories or `Status: Proposed` for ADR/TR\",\n      \"- A category-index row pointing at the new document\",\n      \"- (First-time only) a top-level requirements README derived from\",\n      \"  `_template-requirements-README.md`\",\n    ].join(\"\\n\"),\n  };\n}\n\n/**\n * Render the shell body of the\n * `.claude/procedures/next-requirement-id.sh` helper. Exported so the\n * requirements-writer bundle (and, by re-export, the analyst bundle)\n * can register it as an `AgentProcedure` and the bundles test suite\n * can assert on the script's contents.\n *\n * Contract:\n *\n * ```\n * next-requirement-id.sh <PREFIX> <category-dir> [<self-issue-number>]\n * ```\n *\n * Prints the next free requirement ID (e.g. `FR-1240`) to stdout and\n * exits `0`. The number is the max of two candidate sources plus one:\n *\n *   1. **Merged docs** — files in `<category-dir>` whose names match\n *      `^<PREFIX>-([0-9]+)-.*\\.md$`.\n *   2. **Live state** — open `req:write` GitHub issues whose body\n *      carries a `Requirement ID: <PREFIX>-<NNN>` field. When\n *      `<self-issue-number>` is supplied, only issues **strictly\n *      lower-numbered** than it are counted; this excludes the caller's\n *      own reservation and imposes an issue-number total order so two\n *      concurrent writers never both pick the same number (the\n *      lower-numbered issue ignores the higher; the higher accounts for\n *      the lower). Omit the argument (analyst use) to count every open\n *      `req:write` issue.\n *\n * Every `gh`/`jq` call is guarded so a missing binary, missing auth, or\n * a non-repo cwd contributes nothing — the helper degrades to the\n * directory scan and still prints a valid ID. Side-effect-free; never\n * mutates issues, docs, or any counter.\n *\n * A separate open-PR query is intentionally omitted: a `req:write`\n * issue stays OPEN until its PR MERGES (`Closes #N` closes on merge),\n * so open issues already subsume in-flight PRs — provided each writer\n * publishes its finalized ID back to the issue field per the write-start\n * step.\n */\nexport function renderNextRequirementIdProcedure(): string {\n  return [\n    \"#!/usr/bin/env bash\",\n    \"# next-requirement-id.sh — print the next free requirement ID for a\",\n    \"# category, allocated from live GitHub state (open req:write issues)\",\n    \"# plus the merged docs already on disk.\",\n    \"#\",\n    \"# Usage:\",\n    \"#   .claude/procedures/next-requirement-id.sh <PREFIX> <category-dir> [<self-issue-number>]\",\n    \"#\",\n    \"# Example:\",\n    \"#   next-requirement-id.sh FR docs/src/content/docs/requirements/functional 850\",\n    \"#   -> FR-1240\",\n    \"#\",\n    \"# Behaviour:\",\n    \"#   - Collects candidate NNN numbers from (1) files in <category-dir>\",\n    \"#     matching ^<PREFIX>-([0-9]+)-.*\\\\.md$ and (2) open req:write\",\n    \"#     issues whose body carries a `Requirement ID: <PREFIX>-<NNN>`\",\n    \"#     line. Prints `<PREFIX>-<max+1>` zero-padded to at least three\",\n    \"#     digits (grows past 999 naturally, e.g. FR-1240).\",\n    \"#   - When <self-issue-number> is given, only open req:write issues\",\n    \"#     with a STRICTLY LOWER number are counted. This excludes the\",\n    \"#     caller's own reservation and imposes an issue-number total\",\n    \"#     order so two concurrent writers never both pick the same\",\n    \"#     number. Omit it (analyst use, before any issue is filed) to\",\n    \"#     count every open req:write issue.\",\n    \"#\",\n    \"# Guards:\",\n    \"#   - Side-effect-free: never edits issues, docs, or any counter.\",\n    \"#   - Every gh/jq call is guarded (|| true, 2>/dev/null); a missing\",\n    \"#     binary, missing auth, or non-repo cwd contributes nothing and\",\n    \"#     the helper falls back to the directory scan.\",\n    \"#   - Prints a usage message to stderr and exits 2 on bad args; a\",\n    \"#     missing or empty <category-dir> is tolerated (scan finds\",\n    \"#     nothing). Happy path always exits 0.\",\n    \"\",\n    \"set -uo pipefail\",\n    \"\",\n    \"usage() {\",\n    '  printf \"usage: next-requirement-id.sh <PREFIX> <category-dir> [<self-issue-number>]\\\\n\" >&2',\n    \"}\",\n    \"\",\n    \"# Require at least a prefix and a category directory argument.\",\n    'if [ \"$#\" -lt 2 ]; then',\n    \"  usage\",\n    \"  exit 2\",\n    \"fi\",\n    \"\",\n    'prefix=\"$1\"',\n    'category_dir=\"$2\"',\n    'self_issue=\"${3:-}\"',\n    \"\",\n    \"# The running maximum NNN seen across both candidate sources. Starts\",\n    \"# at 0 so an empty category with no open issues yields <PREFIX>-001.\",\n    \"max=0\",\n    \"\",\n    \"# Fold a bare integer candidate into the running max. Ignores any\",\n    \"# value that is not a run of digits (defensive against malformed\",\n    \"# filenames or issue bodies).\",\n    \"consider() {\",\n    '  local n=\"$1\"',\n    '  case \"$n\" in',\n    \"    '' | *[!0-9]*) return 0 ;;\",\n    \"  esac\",\n    \"  # Strip leading zeros for base-10 arithmetic (avoid octal parsing).\",\n    \"  n=$((10#$n))\",\n    '  if [ \"$n\" -gt \"$max\" ]; then',\n    '    max=\"$n\"',\n    \"  fi\",\n    \"}\",\n    \"\",\n    \"# --- Source 1: merged docs on disk -------------------------------------\",\n    \"# Scan <category-dir> for files named <PREFIX>-<NNN>-<slug>.md and fold\",\n    \"# each NNN into the running max. A missing/empty directory is a no-op.\",\n    'if [ -n \"$category_dir\" ] && [ -d \"$category_dir\" ]; then',\n    '  for f in \"$category_dir\"/\"$prefix\"-*.md; do',\n    \"    # Guard the literal-glob case when nothing matches.\",\n    '    [ -e \"$f\" ] || continue',\n    '    base=\"$(basename \"$f\")\"',\n    \"    # Extract the digit run between the prefix and the next hyphen.\",\n    '    nnn=\"${base#\"$prefix\"-}\"',\n    '    nnn=\"${nnn%%-*}\"',\n    '    consider \"$nnn\"',\n    \"  done\",\n    \"fi\",\n    \"\",\n    \"# --- Source 2: live state — open req:write issues ----------------------\",\n    \"# Ask GitHub for open req:write issues and parse each body for a\",\n    \"# `Requirement ID: <PREFIX>-<NNN>` field. The whole block is guarded so\",\n    \"# a missing gh/jq, missing auth, or non-repo cwd simply yields no\",\n    \"# candidates and the directory scan stands alone.\",\n    \"if command -v gh >/dev/null 2>&1 && command -v jq >/dev/null 2>&1; then\",\n    '  issues_json=\"$(gh issue list --label req:write --state open --limit 500 --json number,body 2>/dev/null || true)\"',\n    '  if [ -n \"$issues_json\" ]; then',\n    \"    # Flatten each issue to a single `<number>\\\\t<body>` line (newlines\",\n    \"    # in the body collapsed to spaces) so a plain read loop can walk\",\n    \"    # them. jq is guarded; on any parse error `parsed` is empty and the\",\n    \"    # loop runs zero times. Captured into a variable first so the loop\",\n    \"    # runs in THIS shell (a piped `while` would subshell and lose max).\",\n    '    parsed=\"$(printf \\'%s\\' \"$issues_json\" | jq -r \\'.[] | \"\\\\(.number)\\\\t\\\\(.body // \"\" | gsub(\"[\\\\\\\\n\\\\\\\\r]\"; \" \"))\"\\' 2>/dev/null || true)\"',\n    '    if [ -n \"$parsed\" ]; then',\n    \"      while IFS=$'\\\\t' read -r issue_number issue_body; do\",\n    '        [ -n \"$issue_number\" ] || continue',\n    \"        # Skip non-numeric issue numbers defensively.\",\n    '        case \"$issue_number\" in',\n    \"          '' | *[!0-9]*) continue ;;\",\n    \"        esac\",\n    \"        # Issue-number total order: when a self issue is given, count\",\n    \"        # this issue only if it is STRICTLY lower-numbered than us.\",\n    '        if [ -n \"$self_issue\" ]; then',\n    '          case \"$self_issue\" in',\n    \"            '' | *[!0-9]*) : ;;\",\n    \"            *)\",\n    '              if [ \"$issue_number\" -ge \"$self_issue\" ]; then',\n    \"                continue\",\n    \"              fi\",\n    \"              ;;\",\n    \"          esac\",\n    \"        fi\",\n    \"        # Pull the NNN out of a `Requirement ID: <PREFIX>-<NNN>` field.\",\n    \"        # Tolerant of surrounding markdown (**bold**, leading `- `) and\",\n    \"        # case-insensitive on the label. First match wins.\",\n    '        id_match=\"$(printf \\'%s\\\\n\\' \"$issue_body\" | grep -ioE \"Requirement ID:[^A-Za-z0-9]*$prefix-[0-9]+\" | head -n1 || true)\"',\n    '        if [ -n \"$id_match\" ]; then',\n    \"          id_nnn=\\\"$(printf '%s' \\\"$id_match\\\" | grep -oE '[0-9]+$' || true)\\\"\",\n    '          consider \"$id_nnn\"',\n    \"        fi\",\n    \"      done <<EOF\",\n    \"$parsed\",\n    \"EOF\",\n    \"    fi\",\n    \"  fi\",\n    \"fi\",\n    \"\",\n    \"# next = max seen + 1, printed zero-padded to at least three digits.\",\n    \"next=$((max + 1))\",\n    'printf \\'%s-%03d\\\\n\\' \"$prefix\" \"$next\"',\n    \"\",\n    \"exit 0\",\n  ].join(\"\\n\");\n}\n\n/**\n * `AgentProcedure` definition for\n * `.claude/procedures/next-requirement-id.sh`. Registered on **both**\n * the requirements-writer and requirements-analyst bundles — both auto-\n * detect (`appliesWhen: () => true`) and `AgentConfig.resolveProcedures`\n * dedupes by `name` into a `Map`, so the script is emitted to disk\n * exactly once even when both bundles are active. The writer invokes it\n * at write-start to finalize the ID before authoring; the analyst\n * invokes it to seed the first reserved ID in a category.\n */\nexport const nextRequirementIdProcedure: AgentProcedure = {\n  name: \"next-requirement-id.sh\",\n  description:\n    \"Prints the next free requirement ID (e.g. FR-1240) for a category, allocated from live GitHub state (open req:write issues, with an optional strictly-lower issue-number tiebreak) plus the merged docs on disk. Side-effect-free; every gh/jq call is guarded so a missing binary, missing auth, or non-repo cwd degrades to the directory scan. Exits 0 on the happy path.\",\n  content: renderNextRequirementIdProcedure(),\n};\n\n/**\n * Requirements writer bundle — enabled by default for projects that adopt\n * this batch.\n *\n * Consuming projects can disable it with\n * `excludeBundles: [\"requirements-writer\"]`. `appliesWhen` always returns\n * `true` per this batch's directive that bundles assume peers are\n * present.\n *\n * Ships a single consolidated sub-agent (`requirements-writer`) with the\n * 11-category taxonomy and decision-authority logic in one prompt, a\n * user-invocable skill (`/write-requirement`) that ships all 13 templates\n * plus `standards-and-frameworks.md` as `referenceFiles`, and the\n * `req:write` plus four `tier:*` labels via the `labels` mechanism.\n *\n * `type:requirement` is intentionally **not** declared here — it is\n * already declared by the `requirements-analyst` bundle and reused.\n */\nexport function buildRequirementsWriterBundle(\n  paths: ResolvedAgentPaths = DEFAULT_AGENT_PATHS,\n  issueDefaults: ResolvedIssueDefaults = DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n): AgentRuleBundle {\n  return {\n    name: \"requirements-writer\",\n    description:\n      \"Requirements writer agent bundle. Authors formal requirement documents from upstream proposals using the 11-category taxonomy (BR, FR, NFR, TR, ADR, SEC, DR, INT, OPS, UX, MT), the four-tier classification, and decision-authority rules (direct-write vs. propose-only). Ships 13 templates plus a standards-and-frameworks reference.\",\n    appliesWhen: () => true,\n    rules: [\n      {\n        name: \"requirements-writer-workflow\",\n        description:\n          \"Describes the requirements-writer pipeline, the req:write phase label, the four tier:* labels, and the boundary with the upstream requirements-analyst and bcm-writer bundles.\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Requirements Writer Workflow\",\n          \"\",\n          \"Use `/write-requirement <category> <short-title>` to author one\",\n          \"formal requirement document. The writer runs in a single phase\",\n          \"tracked by a GitHub issue labeled `req:write` plus the matching\",\n          \"`tier:*` label. Issues also carry `type:requirement` (declared\",\n          \"by the upstream `requirements-analyst` bundle).\",\n          \"\",\n          \"The pipeline produces **requirement documents only** — capability\",\n          \"models are written by the `bcm-writer` agent and gap discovery is\",\n          \"the responsibility of the `requirements-analyst` agent. The\",\n          \"writer never opens `req:scan`, `req:draft-trace`, or `bcm:*`\",\n          \"issues.\",\n          \"\",\n          \"Documents follow the 11-category taxonomy (BR, FR, NFR, TR, ADR,\",\n          \"SEC, DR, INT, OPS, UX, MT) and the four-tier classification\",\n          \"(Platform, Industry, Customer Workflow, Consumer Application).\",\n          \"Templates and a standards-and-frameworks reference ship with the\",\n          \"skill — they are the same files for every project that adopts\",\n          \"the bundle.\",\n          \"\",\n          \"Decision-authority rules are non-negotiable: BR / FR / NFR /\",\n          \"SEC / UX ship as `Status: Draft`; ADR and TR ship as\",\n          \"`Status: Proposed` with a Recommendation framed for human\",\n          \"decision; DR / MT / INT / OPS spin technology choices off into\",\n          \"separate `Proposed` ADR or TR documents.\",\n          \"\",\n          \"See the `requirements-writer` agent definition for full workflow\",\n          \"details, configurable paths, decision-authority rules, and\",\n          \"phase-by-phase instructions.\",\n        ].join(\"\\n\"),\n        platforms: {\n          cursor: { exclude: true },\n        },\n        tags: [\"workflow\"],\n      },\n    ],\n    skills: [buildWriteRequirementSkill(paths, issueDefaults)],\n    subAgents: [buildRequirementsWriterSubAgent(paths)],\n    procedures: [nextRequirementIdProcedure],\n    labels: [\n      {\n        name: \"req:write\",\n        color: \"FEF2C0\",\n        description:\n          \"Phase: write a formal requirement document using the requirements-writer skill\",\n      },\n      {\n        name: \"tier:platform\",\n        color: \"EDEDED\",\n        description:\n          \"Architectural tier: core platform (shared infrastructure, APIs, auth, tenant isolation)\",\n      },\n      {\n        name: \"tier:industry\",\n        color: \"EDEDED\",\n        description:\n          \"Architectural tier: industry vertical (capabilities not every tenant needs)\",\n      },\n      {\n        name: \"tier:customer-workflow\",\n        color: \"EDEDED\",\n        description:\n          \"Architectural tier: customer-configured workflow (business logic tenants configure)\",\n      },\n      {\n        name: \"tier:consumer-app\",\n        color: \"EDEDED\",\n        description:\n          \"Architectural tier: consumer application (UI/UX and integrations in external front-ends/systems)\",\n      },\n    ],\n  };\n}\n\n/**\n * Default-paths instance of the requirements-writer bundle, preserved\n * for backward compatibility with consumers that import the const\n * directly. The factory above is the canonical entry point when a\n * consumer supplies `AgentConfigOptions.paths`.\n */\nexport const requirementsWriterBundle: AgentRuleBundle =\n  buildRequirementsWriterBundle();\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { renderClaimVerificationSection } from \"./claim-verification\";\nimport {\n  DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n  ResolvedIssueDefaults,\n  labelsForPhase,\n} from \"./issue-defaults\";\nimport { renderIssueTypeAssignmentStep } from \"./issue-type\";\nimport { renderOriginStampSection } from \"./origin-label\";\nimport { DEFAULT_AGENT_PATHS, ResolvedAgentPaths } from \"./paths\";\nimport { PROJECT_CONTEXT_MAINTAINER_SECTION } from \"./project-context\";\nimport { REQ_WRITE_ISSUE_SCHEMA_SECTION } from \"./requirements-taxonomy\";\nimport { nextRequirementIdProcedure } from \"./requirements-writer\";\nimport {\n  AGENT_MODEL,\n  AGENT_RULE_SCOPE,\n  AgentSkill,\n  AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that discovers requirement gaps from BCM model documents,\n * competitive analysis, product roadmaps, and meeting extracts, then\n * produces deduplicated scan reports, requirement proposals, and\n * `req:write` issues for the downstream `requirements-writer` agent.\n * The draft-trace phase creates issues carrying the `req:write` label\n * so the writer bundle picks them up automatically.\n */\nfunction buildRequirementsAnalystSubAgent(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSubAgent {\n  return {\n    name: \"requirements-analyst\",\n    description:\n      \"Discovers requirement gaps from BCM model docs, competitive analysis, product docs, and meeting extracts. Produces scan reports, proposals, and req:write issues for the downstream requirements-writer agent. Runs through a 2-phase pipeline (scan → draft-trace), one phase per session, tracked by req:* GitHub issue labels.\",\n    model: AGENT_MODEL.POWERFUL,\n    maxTurns: 80,\n    platforms: { cursor: { exclude: true } },\n    prompt: [\n      \"# Requirements Analyst Agent\",\n      \"\",\n      \"Dedicated agent loop for discovering requirement gaps from BCM (Business\",\n      \"Capability Model) documents, product docs, and competitive analysis — then\",\n      \"creating well-formed requirement issues for the downstream\",\n      \"`requirements-writer` agent to draft. Designed for scheduled execution\",\n      \"downstream of the BCM writer and company research agents.\",\n      \"\",\n      \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n      \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...PROJECT_CONTEXT_MAINTAINER_SECTION,\n      \"## Design Principles\",\n      \"\",\n      \"1. **Discover, don't write.** This agent identifies *what requirements are\",\n      \"   missing*. The `requirements-writer` agent writes the actual documents.\",\n      \"   The boundary keeps this agent fast and the `requirements-writer`\",\n      \"   authoritative.\",\n      \"2. **Trace everything.** Every discovered gap links to the source that\",\n      \"   revealed it (a BCM model doc, competitive analysis, product doc, or\",\n      \"   meeting extract).\",\n      \"3. **Respect the taxonomy.** Route every discovered requirement to the\",\n      \"   correct BCM category (FR, BR, NFR, SEC, DR, INT, OPS, UX, MT, ADR, TR)\",\n      \"   using the shared disambiguation rules — the same taxonomy the\",\n      \"   `requirements-writer` and `requirements-reviewer` load. The\",\n      \"   canonical source lives in `requirements-taxonomy.ts` and is\",\n      \"   embedded verbatim in both downstream agents' prompts.\",\n      \"4. **Deduplicate.** Before creating an issue, check whether a requirement\",\n      \"   already exists or an issue is already open for it.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## State Machine Overview\",\n      \"\",\n      \"Requirements synthesis flows through **2 phases**:\",\n      \"\",\n      \"```\",\n      \"┌──────────────┐     ┌──────────────────┐\",\n      \"│  1. SCAN     │────▶│  2. DRAFT-TRACE  │\",\n      \"│  Read docs,  │     │  Write proposals,│\",\n      \"│  identify    │     │  create req:write│\",\n      \"│  gaps, check │     │  issues, update  │\",\n      \"│  for dupes   │     │  source docs     │\",\n      \"│              │     │  with traceability│\",\n      \"└──────────────┘     └──────────────────┘\",\n      \"```\",\n      \"\",\n      \"This pipeline matches the `scan → draft-trace → write` pattern\",\n      \"used by the sibling openhi project. Draft and Trace were previously\",\n      \"separate phases; they were collapsed because the proposals file Draft\",\n      \"wrote was only ever consumed by Trace (no human review, no async work\",\n      \"between the two), so the phase boundary added latency without value.\",\n      \"See ADR-009 for the full reasoning.\",\n      \"\",\n      \"**Issue labels encode the phase:**\",\n      \"\",\n      \"| Label | Phase | Session work |\",\n      \"|-------|-------|-------------|\",\n      \"| `req:scan` | 1. Scan | Read source docs, identify potential requirement gaps, check against existing requirements and open issues, write deduplicated scan report |\",\n      \"| `req:draft-trace` | 2. Draft & Trace | Write proposals, create `req:write` GitHub issues for each proposal, and update source documents with traceability notes — all in a single session |\",\n      \"\",\n      \"All issues also carry `type:requirement` and a `status:*` label.\",\n      \"\",\n      \"**Issue count per scan cycle:** 1 scan + 1 draft-trace = **2 sessions**.\",\n      \"\",\n      \"**Shortened paths:**\",\n      \"- No gaps found after scan → skip draft-trace → **1 session**\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Configurable Paths\",\n      \"\",\n      \"Projects adopting this bundle must define these paths in their agent\",\n      \"configuration (`agentConfig.rules` extension or project-level docs):\",\n      \"\",\n      \"| Placeholder | Meaning | Typical value |\",\n      \"|-------------|---------|---------------|\",\n      `| \\`<BCM_DOCS_ROOT>\\` | Root of BCM model docs (capability models) | \\`${paths.bcmRoot}/\\` |`,\n      `| \\`<COMPETITIVE_ROOT>\\` | Competitive analysis docs | \\`${paths.docsRoot}/business-strategy/competitive/\\` |`,\n      `| \\`<PRODUCT_ROOT>\\` | Product roadmap / entity taxonomy | \\`${paths.docsRoot}/product/\\` |`,\n      `| \\`<MEETINGS_ROOT>\\` | Meeting extracts | \\`${paths.docsRoot}/research/meetings/\\` |`,\n      `| \\`<RESEARCH_REQUIREMENTS_ROOT>\\` | Scan reports and proposals | \\`${paths.researchRequirementsRoot}/\\` |`,\n      `| \\`<REQUIREMENTS_ROOT>\\` | Final requirement documents (owned by requirements-writer) | \\`${paths.requirementsRoot}/\\` |`,\n      \"| `<PREFIX>` | Project-specific requirement ID prefix | e.g. `VRTX`, `ACME` |\",\n      \"\",\n      \"If your project stores these in different locations, substitute accordingly\",\n      \"wherever the phase instructions reference a path.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Agent Loop\",\n      \"\",\n      \"Run this loop exactly once per session. Never start a second issue.\",\n      \"\",\n      \"1. Claim one open `type:requirement` issue using phase priority:\",\n      \"   `req:scan` > `req:draft-trace`.\",\n      \"2. Transition `status:ready` → `status:in-progress` and create the branch\",\n      \"   per your project's branch-naming convention.\",\n      \"3. Execute the phase handler that matches the issue's `req:*` label.\",\n      \"4. Commit, push, open a PR (if applicable), and close the issue per your\",\n      \"   project's PR workflow.\",\n      \"   Stamp every PR you open with the `origin:agent` label — see the\",\n      \"   **Origin label** section below.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...renderClaimVerificationSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderOriginStampSection(),\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 1: Scan (`req:scan`)\",\n      \"\",\n      \"**Goal:** Read source documents, identify where requirements are missing,\",\n      \"incomplete, or contradictory, then check each potential gap against existing\",\n      \"requirements and open issues to eliminate duplicates. Produces a single\",\n      \"deduplicated scan report.\",\n      \"\",\n      \"**Budget:** Reading source docs + reading requirement registries + searching\",\n      \"issues. Write one deduplicated scan output file.\",\n      \"\",\n      \"### Scan Sources\",\n      \"\",\n      \"The issue specifies which source(s) to scan. Common scan scopes:\",\n      \"\",\n      \"| Scope | What to read | What to look for |\",\n      \"|-------|-------------|-----------------|\",\n      `| **BCM model doc** | One \\`{PREFIX}-NNN\\` doc under \\`<BCM_DOCS_ROOT>\\` | The doc's project-relevance section (commonly \\`## <Project> Relevance\\` or \\`## Strategic Implications\\`) — gaps where capabilities exist but no FR/BR/INT addresses them. Use \\`${paths.docsRoot}/project-context.md\\` to judge what is relevant. |`,\n      \"| **Competitive analysis** | One `comp-*.md` doc under `<COMPETITIVE_ROOT>` | Feature comparison gaps — competitor features the product lacks requirements for |\",\n      \"| **Product roadmap** | `<PRODUCT_ROOT>/prioritized-feature-roadmap.md` | Roadmap items without corresponding FRs |\",\n      \"| **Entity taxonomy** | `<PRODUCT_ROOT>/entity-taxonomy.md` | Entities without CRUD requirements (FR), data requirements (DR), or security requirements (SEC) |\",\n      \"| **Meeting extract** | `<MEETINGS_ROOT>/meeting-*.extract.md` | Requirements identified but not yet formalized |\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the source documents** specified in the issue.\",\n      \"\",\n      \"2. **Identify potential gaps.** For each potential missing requirement:\",\n      \"   - Classify into the correct BCM category (FR, BR, NFR, SEC, DR, INT,\",\n      \"     OPS, UX, MT, ADR, TR)\",\n      \"   - Apply the shared disambiguation rules (from `requirements-taxonomy.ts`,\",\n      \"     also embedded in the requirements-writer and requirements-reviewer\",\n      \"     prompts)\",\n      \"   - Note the source that revealed the gap\",\n      \"   - Estimate priority based on the source context\",\n      \"\",\n      \"3. **Read the requirements registry.** Scan `_index.md` files in each\",\n      \"   `<REQUIREMENTS_ROOT>/<category>/` directory to know what already exists.\",\n      \"\",\n      \"4. **Search for existing issues.** For each potential gap, search open issues:\",\n      \"   ```bash\",\n      '   gh issue list --label \"type:requirement\" --state open \\\\',\n      \"     --json number,title --limit 100\",\n      \"   ```\",\n      \"\",\n      \"5. **Classify each gap:**\",\n      \"   - **New** — no existing requirement or open issue covers this\",\n      \"   - **Duplicate** — an existing requirement already addresses this\",\n      \"   - **In progress** — an open issue already targets this\",\n      \"   - **Partial** — existing requirement partially covers this; note the gap\",\n      \"\",\n      \"6. **Write the deduplicated scan report** to:\",\n      \"   ```\",\n      \"   <RESEARCH_REQUIREMENTS_ROOT>/req-scan-<scope>-<YYYY-MM-DD>.md\",\n      \"   ```\",\n      \"\",\n      \"   Format:\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"Requirements Scan: <scope>\"',\n      \"   date: YYYY-MM-DD\",\n      \"   parent_issue: <N>\",\n      \"   status: complete\",\n      \"   ---\",\n      \"\",\n      \"   ## Source Documents Reviewed\",\n      \"   - <path> — <brief description>\",\n      \"\",\n      \"   ## Existing Requirements Checked\",\n      \"   - <category>: <count> existing docs, <count> open issues\",\n      \"\",\n      \"   ## Identified Gaps (New)\",\n      \"   ### Gap 1: <Title>\",\n      \"   - **Category:** FR / BR / NFR / SEC / DR / INT / OPS / UX / MT / ADR / TR\",\n      \"   - **Source:** <path to doc + section that revealed this gap>\",\n      \"   - **Priority:** High / Normal / Low\",\n      \"   - **Rationale:** <why this requirement is needed>\",\n      \"   - **Duplicate check:** No existing requirement or open issue found\",\n      \"   - **Proposed scope:** <1-2 sentences on what the requirement should cover>\",\n      \"\",\n      \"   ## Already Covered\",\n      \"   <list of potential gaps that turned out to already have requirements>\",\n      \"\",\n      \"   ## In Progress\",\n      \"   <gaps that already have open issues — include issue numbers>\",\n      \"\",\n      \"   ## Ambiguous / Needs Human Decision\",\n      \"   <gaps where the correct category or scope is unclear>\",\n      \"   ```\",\n      \"\",\n      \"7. **Create downstream issues based on findings:**\",\n      \"   - If any new gaps were identified → create `req:draft-trace` issue\",\n      \"     (blocked on this issue via `Depends on: #N`).\",\n      \"   - If **no gaps** were found → stop (no further phases needed). Comment\",\n      \"     on the issue noting that no gaps were identified, and proceed directly\",\n      \"     to commit and push. The scan issue will be marked done with no\",\n      \"     downstream work needed.\",\n      \"\",\n      \"8. **Commit and push.**\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 2: Draft & Trace (`req:draft-trace`)\",\n      \"\",\n      \"**Goal:** Expand each identified gap into a requirement proposal, create\",\n      \"a `req:write` GitHub issue for each proposal so the downstream\",\n      \"`requirements-writer` bundle picks it up, and backfill source-document\",\n      \"traceability notes — all in a single session.\",\n      \"\",\n      \"**Budget:** No web searches. Reading + writing proposals + issue creation\",\n      \"+ minor traceability edits to source documents.\",\n      \"\",\n      \"Draft and Trace were previously separate phases. They were collapsed\",\n      \"because the proposals file written by Draft was only ever consumed by\",\n      \"Trace — no human review, no async work, no CI validation sat between\",\n      \"them. See ADR-009 for the decision record.\",\n      \"\",\n      \"### `req:write` issue schema\",\n      \"\",\n      \"The `req:write` issues this phase creates are picked up by the\",\n      \"downstream `requirements-writer` agent, which parses a strict\",\n      \"schema on intake. The authoritative schema is defined in the\",\n      \"`requirements-writer` sub-agent prompt under **The `req:write`\",\n      \"Issue Schema** — every `req:write` issue this phase opens must\",\n      \"conform. The same schema is embedded in the\",\n      \"`requirements-reviewer` follow-up generator so the three\",\n      \"producers never drift apart.\",\n      \"\",\n      ...REQ_WRITE_ISSUE_SCHEMA_SECTION,\n      \"\",\n      \"**Deriving the three required fields from the proposal.** For\",\n      \"every `req:write` issue this phase opens, the three fields come\",\n      \"directly from the proposal entry written earlier in the same\",\n      \"session:\",\n      \"\",\n      \"- **Category** — the proposal's `**Category:**` line.\",\n      \"- **Tier** — the proposal's `**Tier:**` line.\",\n      \"- **Output Path** —\",\n      \"  `<REQUIREMENTS_ROOT>/<category-dir>/<PREFIX>-<NNN>-<slug>.md`,\",\n      \"  using the sequence number determined in the proposal step below.\",\n      \"\",\n      \"**Validation step — required before opening the issue.** Before\",\n      \"calling `gh issue create`, verify all three required fields are\",\n      \"populated and internally consistent (Category matches title\",\n      \"prefix, Tier matches `tier:*` label, Output Path filename starts\",\n      \"with the Category prefix). If any field cannot be derived, open\",\n      \"the issue with `status:needs-attention` (not `status:ready`) and\",\n      \"include a `Missing: <field> — <one-line reason>` line so a human\",\n      \"triaging the issue only has to supply the remaining value(s)\",\n      \"before flipping the label to `status:ready`.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the scan report** from Phase 1.\",\n      \"\",\n      \"2. **For each gap**, write a detailed proposal:\",\n      \"\",\n      \"   ```markdown\",\n      \"   ## Proposed: <PREFIX>-<NNN> — <Title>\",\n      \"\",\n      \"   **Category:** <FR/BR/NFR/SEC/DR/INT/OPS/UX/MT/ADR/TR>\",\n      \"   **Tier:** <platform/industry/customer-workflow/consumer-app>\",\n      \"   **Priority:** <High/Normal/Low>\",\n      \"   **Source:** <document path and section>\",\n      \"\",\n      \"   ### Summary\",\n      \"   <2-3 sentences describing what the requirement should capture>\",\n      \"\",\n      \"   ### Draft Acceptance Criteria\",\n      \"   - [ ] <testable criterion 1>\",\n      \"   - [ ] <testable criterion 2>\",\n      \"   - [ ] <testable criterion 3>\",\n      \"\",\n      \"   ### Traceability\",\n      \"   - **Implements:** <BR or parent requirement if applicable>\",\n      \"   - **Related:** list each interacting requirement on its own\",\n      \"     `- <PREFIX>-<NNN>` line in ascending ID order (append-only —\",\n      \"     add your own entries, never rewrite or collapse existing ones\",\n      \"     into a comma-separated line), not a single comma-joined line\",\n      \"   - **Source:** <BCM doc, competitive analysis, or meeting that revealed\",\n      \"     the gap — use a markdown link. If the source is a meeting note, the\",\n      \"     downstream requirement doc must include the same meeting as a link in\",\n      \"     its Traceability `Related:` list.>\",\n      \"\",\n      \"   ### Decision Authority\",\n      '   <\"Direct write\" for BR/FR/NFR/SEC/UX, or \"Proposed — needs human',\n      '   decision\" for ADR/TR, or \"Mixed — defer technology choices\" for',\n      \"   DR/MT/INT/OPS>\",\n      \"\",\n      \"   ### Notes for Requirements Writer\",\n      \"   <any context the writer should know — related ADRs, existing partial\",\n      \"   coverage, relevant competitive features>\",\n      \"   ```\",\n      \"\",\n      \"3. **Write the proposals** to:\",\n      \"   ```\",\n      \"   <RESEARCH_REQUIREMENTS_ROOT>/req-proposals-<scope>-<YYYY-MM-DD>.md\",\n      \"   ```\",\n      \"\",\n      \"4. **Determine next sequence numbers.** For the **first** proposal\",\n      \"   in a given category this session, run\",\n      \"   `.claude/procedures/next-requirement-id.sh <PREFIX> <category-dir>`\",\n      \"   (no issue number — the `req:write` issues are not filed yet) to\",\n      \"   get the starting ID from live state (existing docs plus open\",\n      \"   `req:write` issues). For each subsequent proposal in the **same**\",\n      \"   category within this single batch session, increment the ID\",\n      \"   locally (the freshly-filed issues from this batch are not yet\",\n      \"   reflected in the procedure's live-state query). These IDs are\",\n      \"   **hints** stamped into the issue body; the downstream writer\",\n      \"   re-validates and finalizes each ID at write-start, so a residual\",\n      \"   collision costs nothing. If the procedure is unavailable, fall\",\n      \"   back to scanning `<REQUIREMENTS_ROOT>/<category>/` for the next\",\n      \"   available `NNN`.\",\n      \"\",\n      \"5. **Create requirement issues.** For each proposal, file a\",\n      \"   `req:write` issue using the canonical recipe documented in\",\n      \"   `## Template: req:write` of\",\n      \"   `docs/src/content/docs/agents/issue-templates.md`.\",\n      \"\",\n      `   All \\`type:requirement\\` issues default to \\`priority:${labelsForPhase(issueDefaults, \"req:write\").priority}\\` (override`,\n      \"   only if the proposal's priority was explicitly High or Low). Each\",\n      \"   issue must also carry the `req:write` phase label plus the matching\",\n      \"   `tier:*` label so the downstream `requirements-writer` bundle picks\",\n      \"   it up with the correct tier. Concretely, the label list includes\",\n      '   `--label \"type:requirement\"`, `--label \"req:write\"`,',\n      `   \\`--label \"tier:<tier-slug>\"\\`, \\`--label \"status:${labelsForPhase(issueDefaults, \"req:write\").status}\"\\`, and`,\n      `   \\`--label \"priority:${labelsForPhase(issueDefaults, \"req:write\").priority}\"\\`.`,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"   The body must carry the three writer-required fields in an\",\n      \"   `## Objective` block, written as bold-prefixed lines so the\",\n      \"   writer's intake parser can pull them out, plus the reserved-ID\",\n      \"   hint from step 4:\",\n      \"\",\n      \"   - `**Category:** <BR/FR/NFR/TR/ADR/SEC/DR/INT/OPS/UX/MT>`\",\n      \"   - `**Tier:** <platform/industry/customer-workflow/consumer-app>`\",\n      \"   - `**Output Path:** <REQUIREMENTS_ROOT>/<category-dir>/<PREFIX>-<NNN>-<slug>.md`\",\n      \"   - `**Requirement ID:** <PREFIX>-<NNN>` — the ID reserved in step 4\",\n      \"     (must match the `<PREFIX>-<NNN>` in the Output Path). This is a\",\n      \"     **hint**: the downstream writer re-validates and finalizes the\",\n      \"     ID at write-start, so a residual collision is repaired there\",\n      \"     for free.\",\n      \"\",\n      \"   Then under `## Inputs / Read`, list the proposals file\",\n      \"   (`<RESEARCH_REQUIREMENTS_ROOT>/req-proposals-<scope>-<date>.md`)\",\n      \"   and any source documents the writer should consult (BCM model\",\n      \"   docs, competitive analyses, product docs).\",\n      \"\",\n      \"   When one of Category / Tier / Output Path could not be derived\",\n      \"   from the proposal (for example, the proposal omitted the Tier\",\n      `   line), replace \\`status:${labelsForPhase(issueDefaults, \"req:write\").status}\\` with \\`status:needs-attention\\` in`,\n      \"   the label list and add a `Missing: <field> — <reason>` line\",\n      \"   directly below the Output Path line in the body. Populate\",\n      \"   whichever of the three fields **could** be derived so a human\",\n      \"   triaging the issue has the minimum possible cleanup.\",\n      \"\",\n      \"6. **Update source documents.** In each BCM model doc or competitive\",\n      \"   analysis that was scanned, add a note in the project-relevance /\",\n      \"   strategic-implications section (whichever heading the source doc uses)\",\n      \"   indicating that a requirement issue was created. Each note is its\",\n      \"   own single line:\",\n      \"\",\n      \"   ```markdown\",\n      \"   - Gap addressed: see [<PREFIX>-<NNN>](<relative path to requirement doc>)\",\n      \"     (issue #<N>)\",\n      \"   ```\",\n      \"\",\n      \"   These `Gap addressed:` notes form an **append-only,\",\n      \"   one-per-line, deterministically sorted** list — the shared BCM /\",\n      \"   competitive-analysis source docs are edited concurrently by\",\n      \"   sibling `req:draft-trace` sessions, so this list is a\",\n      \"   merge-conflict hotspot. Maintain it under the same discipline\",\n      \"   the `shared-editing-safety` rule prescribes for shared registries,\",\n      \"   applied here to this one list section (the surrounding source doc\",\n      \"   is a hand-authored document, not a registry, so only this list is\",\n      \"   governed):\",\n      \"\",\n      \"   - **One entry per line.** Add each `- Gap addressed:` note as its\",\n      \"     own new bullet. Never collapse notes into a single\",\n      \"     comma-separated line — a single mutable line always conflicts\",\n      \"     when two sessions touch it.\",\n      \"   - **Ascending order.** Insert your bullet in the position that\",\n      \"     keeps the list sorted by requirement ID (`<PREFIX>-<NNN>`), so\",\n      \"     concurrent sibling inserts land on different lines and git\",\n      \"     auto-merges them.\",\n      \"   - **Append-only.** Never rewrite, reorder, or merge existing\",\n      \"     notes; add only your own.\",\n      \"   - **Defer the commit of this section to the final pre-push\",\n      \"     step.** Pull the latest default branch before inserting, insert\",\n      \"     only your own note, and if a concurrent sibling already landed a\",\n      \"     bullet, rebase and re-insert. Commit this shared list section on\",\n      \"     its own at the end, then push immediately.\",\n      \"\",\n      \"7. **Comment on the scan issue** with a summary of all issues created and\",\n      \"   all docs updated.\",\n      \"\",\n      \"8. **Commit and push.**\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Coordination with Other Agents\",\n      \"\",\n      \"| Direction | Agent | What |\",\n      \"|-----------|-------|------|\",\n      `| Upstream | BCM Writer | Scans capability-model docs for project-relevance gaps (judged against \\`${paths.docsRoot}/project-context.md\\`) |`,\n      \"| Upstream | Company Research | Scans competitive analysis for feature comparison gaps |\",\n      \"| Upstream | Meeting Analyst | Scans meeting extracts for requirement proposals |\",\n      \"| Downstream | `requirements-writer` | Picks up the `type:requirement` + `req:write` issues this agent creates and drafts the actual requirement document |\",\n      \"\",\n      \"**File boundaries:** Writes to `<RESEARCH_REQUIREMENTS_ROOT>/req-*.md` and\",\n      \"minor traceability edits to `<BCM_DOCS_ROOT>` and `<COMPETITIVE_ROOT>`.\",\n      \"Never writes to `<REQUIREMENTS_ROOT>/` — that is owned by the\",\n      \"requirements-writer agent.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Blocked Issues\",\n      \"\",\n      \"Additional block reasons specific to requirements synthesis:\",\n      \"- Source document has unresolved contradictions\",\n      \"- Category classification is ambiguous (needs human disambiguation)\",\n      \"- Dependent BCM documents are still in draft with placeholder content\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Rules\",\n      \"\",\n      \"- **Discover, don't write requirements.** Create issues for the\",\n      \"  `requirements-writer` agent — don't write requirement documents\",\n      \"  directly.\",\n      \"- **Deduplicate rigorously.** Check both existing docs and open issues\",\n      \"  before flagging a gap.\",\n      \"- **Respect decision authority.** Mark ADR/TR proposals as needing human\",\n      \"  decision. Don't create direct-write issues for technology choices.\",\n      \"- **Bidirectional traceability.** Every `req-scan-*.md` and\",\n      \"  `req-proposals-*.md` must include a `## Produced` section listing the\",\n      \"  downstream requirement issues (and eventual requirement documents) it\",\n      \"  spawned, as markdown links; each formal requirement document under\",\n      \"  `<REQUIREMENTS_ROOT>/` must include a forward link back to the scan or\",\n      \"  proposal that produced it.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off a requirements scan. */\nfunction buildScanRequirementsSkill(\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"scan-requirements\",\n    description:\n      \"Kick off a requirements-analyst scan across BCM model docs, competitive analysis, product docs, or meeting extracts. Creates a req:scan issue and dispatches Phase 1.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"requirements-analyst\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Scan Requirements\",\n      \"\",\n      \"Kick off a requirements-analyst scan cycle. Creates a `req:scan` issue\",\n      \"targeted at the requested scope and dispatches Phase 1 (Scan) in the\",\n      \"requirements-analyst agent.\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/scan-requirements <scope>\",\n      \"\",\n      \"Where `<scope>` is one of:\",\n      \"- `bcm:<PREFIX-NNN>` — a single BCM model doc\",\n      \"- `competitive:<slug>` — a single competitive analysis doc\",\n      \"- `product-roadmap` — the prioritized feature roadmap\",\n      \"- `entity-taxonomy` — the entity taxonomy doc\",\n      \"- `meeting:<slug>` — a meeting extract\",\n      \"- `all-bcm` / `all-competitive` — full sweep (long-running)\",\n      \"\",\n      \"## Steps\",\n      \"\",\n      `1. Create a \\`req:scan\\` issue with \\`type:requirement\\`, \\`priority:${labelsForPhase(issueDefaults, \"req:scan\").priority}\\`,`,\n      `   and \\`status:${labelsForPhase(issueDefaults, \"req:scan\").status}\\`. Body must list the files to read and the scan scope.`,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 1 (Scan) of the requirements-analyst agent.\",\n      \"3. If gaps are found, a `req:draft-trace` issue is created automatically.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- A `req-scan-<scope>-<YYYY-MM-DD>.md` file under the project's research\",\n      \"  requirements directory.\",\n      \"- A `req:draft-trace` issue if any gaps were identified.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/**\n * Build the requirements-analyst bundle with the supplied resolved\n * paths.\n *\n * Every reference to a canonical agent path (docs root, requirements\n * root, bcm root, etc.) inside the rule / skill / sub-agent content\n * strings is an interpolation of the supplied `paths` struct, so a\n * consumer override of `AgentConfigOptions.paths` propagates to the\n * rendered output.\n */\nexport function buildRequirementsAnalystBundle(\n  paths: ResolvedAgentPaths = DEFAULT_AGENT_PATHS,\n  issueDefaults: ResolvedIssueDefaults = DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n): AgentRuleBundle {\n  return {\n    name: \"requirements-analyst\",\n    description:\n      \"Requirements gap-discovery agent bundle for BCM-driven projects. 2-phase pipeline (scan, draft-trace) with req:* phase labels.\",\n    appliesWhen: () => true,\n    rules: [\n      {\n        name: \"requirements-analyst-workflow\",\n        description:\n          \"Describes the 2-phase requirements gap-discovery pipeline, the req:* label taxonomy, and the boundary with the downstream requirements-writer agent.\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Requirements Analyst Workflow\",\n          \"\",\n          \"Use `/scan-requirements <scope>` to kick off a requirements gap\",\n          \"discovery cycle. The pipeline runs in 2 phases — scan and\",\n          \"draft-trace — each tracked by its own GitHub issue labeled\",\n          \"`req:scan` or `req:draft-trace`. All issues carry\",\n          \"`type:requirement`.\",\n          \"\",\n          \"The requirements-analyst *discovers gaps, drafts proposals, and\",\n          \"opens `req:write` issues for the downstream writer*; it does\",\n          \"**not** write final requirement documents. Writing is the job of\",\n          \"the downstream `requirements-writer` agent (a separate bundle).\",\n          \"Keep that boundary clean: proposals land under the research\",\n          \"requirements directory, not under the authoritative requirements\",\n          \"tree. The draft-trace phase tags new issues with `req:write` so\",\n          \"the writer bundle picks them up automatically.\",\n          \"\",\n          \"See the `requirements-analyst` agent definition for full workflow\",\n          \"details and phase-by-phase instructions.\",\n        ].join(\"\\n\"),\n        platforms: {\n          cursor: { exclude: true },\n        },\n        tags: [\"workflow\"],\n      },\n    ],\n    skills: [buildScanRequirementsSkill(issueDefaults)],\n    subAgents: [buildRequirementsAnalystSubAgent(paths, issueDefaults)],\n    // Shares the write-start ID allocator with the writer bundle. Both\n    // bundles auto-detect and AgentConfig.resolveProcedures dedupes by\n    // name, so `next-requirement-id.sh` is emitted to disk exactly once.\n    // The analyst runs it (without a self-issue-number) to seed the first\n    // reserved ID in a category during draft-trace.\n    procedures: [nextRequirementIdProcedure],\n    labels: [\n      {\n        name: \"type:requirement\",\n        color: \"1D76DB\",\n        description:\n          \"Work that produces or discovers a requirement document (FR, BR, NFR, etc.)\",\n      },\n      {\n        name: \"req:scan\",\n        color: \"C5DEF5\",\n        description:\n          \"Phase 1: scan source docs for requirement gaps and deduplicate\",\n      },\n      {\n        name: \"req:draft-trace\",\n        color: \"BFDADC\",\n        description:\n          \"Phase 2: draft proposals, create req:write issues, and backfill source-doc traceability\",\n      },\n    ],\n  };\n}\n\n/**\n * Default-paths instance of the requirements-analyst bundle, preserved\n * for backward compatibility with consumers that import the const\n * directly. The factory above is the canonical entry point when a\n * consumer supplies `AgentConfigOptions.paths`.\n */\nexport const requirementsAnalystBundle: AgentRuleBundle =\n  buildRequirementsAnalystBundle();\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { renderClaimVerificationSection } from \"./claim-verification\";\nimport {\n  DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n  ResolvedIssueDefaults,\n  labelsForPhase,\n} from \"./issue-defaults\";\nimport { renderIssueTypeAssignmentStep } from \"./issue-type\";\nimport { renderOriginStampSection } from \"./origin-label\";\nimport { DEFAULT_AGENT_PATHS, ResolvedAgentPaths } from \"./paths\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n  REQ_WRITE_ISSUE_SCHEMA_SECTION,\n  REQUIREMENTS_TAXONOMY_DISAMBIGUATION_SECTION,\n} from \"./requirements-taxonomy\";\nimport { REQUIREMENTS_WRITER_PATHS } from \"./requirements-writer\";\nimport {\n  AGENT_MODEL,\n  AGENT_RULE_SCOPE,\n  AgentSkill,\n  AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that audits and deprecates existing requirement documents\n * written under the 11-category taxonomy and the four-tier classification\n * (the same taxonomy used by the upstream `requirements-writer` bundle).\n *\n * Runs in one of two single-phase modes per session:\n *\n * - `req:review` — audits documents and produces a structured review\n *   report grouped by Critical / Warning / Info severity. Files\n *   follow-up issues for actionable findings. Never edits requirement\n *   documents.\n * - `req:deprecate` — transitions one or more requirement documents to\n *   `Deprecated` or `Superseded`, appends a Deprecation reason, adds a\n *   `Superseded-by` traceability link when applicable, updates the\n *   category index row, and files `req:write` follow-ups for every\n *   back-reference so the writer can rewrite them.\n *\n * The deprecation phase is the only path by which this agent mutates\n * requirement documents, and it is narrowly scoped to the frontmatter\n * Status, the Revision History entry, the Traceability Superseded-by\n * line, and the matching category index row. All other document edits\n * remain the exclusive responsibility of the `requirements-writer`\n * bundle.\n *\n * This agent **never** authors new requirement documents, capability\n * models, or research notes. New requirement authoring belongs to the\n * `requirements-writer` bundle; gap discovery belongs to the\n * `requirements-analyst` bundle; capability-model authoring belongs to\n * the `bcm-writer` bundle.\n *\n * Soft dependency: this agent expects the requirement templates to be\n * available at `REQUIREMENTS_WRITER_PATHS.templatesRoot`, which is\n * shipped by the `requirements-writer` bundle. The reviewer reads those\n * templates to know which sections are required for each category but\n * does **not** ship its own copy.\n */\nfunction buildRequirementsReviewerSubAgent(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSubAgent {\n  return {\n    name: \"requirements-reviewer\",\n    description:\n      \"Audits and deprecates existing requirement documents (BR, FR, NFR, TR, ADR, SEC, DR, INT, OPS, UX, MT). In `req:review` mode, runs the 12-check audit (structural compliance, categorization, traceability, cross-reference integrity, sequence integrity, content quality, registry sync, decision-authority compliance, tier classification, cross-referencing conventions, stale `Proposed` ADR/TR decisions) and produces a report grouped by Critical / Warning / Info (plus a dedicated Stale decisions section). In `req:deprecate` mode, transitions target documents to `Deprecated` or `Superseded`, updates the category index row, and files `req:write` follow-ups for every back-reference so the writer can rewrite them. One phase per session.\",\n    model: AGENT_MODEL.POWERFUL,\n    maxTurns: 80,\n    platforms: { cursor: { exclude: true } },\n    prompt: [\n      \"# Requirements Reviewer Agent\",\n      \"\",\n      \"You audit and deprecate existing requirement documents. Each session\",\n      \"handles **one** issue in **one** of two phases:\",\n      \"\",\n      \"- **`req:review`** (Phase 1) — audit documents and produce a\",\n      \"  structured review report grouped by Critical / Warning / Info\",\n      \"  severity. File follow-up issues for actionable findings. **Do not**\",\n      \"  edit any requirement documents in this phase.\",\n      \"- **`req:deprecate`** (Phase 2) — transition one or more requirement\",\n      \"  documents to `Deprecated` or `Superseded`, append a Deprecation\",\n      \"  reason, add a `Superseded-by` traceability link when applicable,\",\n      \"  update the category index row, and file `req:write` follow-ups for\",\n      \"  every back-reference so the `requirements-writer` can rewrite\",\n      \"  them.\",\n      \"\",\n      \"Classify the session up front by reading the issue's phase label. If\",\n      \"the issue carries both labels, or neither, comment on the issue\",\n      \"requesting clarification and apply `status:needs-attention` rather\",\n      \"than guessing.\",\n      \"\",\n      \"The deprecation phase is the **only** path by which this agent\",\n      \"mutates requirement documents, and it is narrowly scoped to:\",\n      \"\",\n      \"- The frontmatter `Status` field and the `Status` row in the\",\n      \"  Metadata table of each target document\",\n      \"- A new entry in the target document's `## Revision History`\",\n      \"  describing the transition\",\n      \"- A `Superseded-by:` line in the target document's `## Traceability`\",\n      \"  section when a superseding document was provided\",\n      \"- The matching row in the category `README.md` / `index.md` index\",\n      \"\",\n      \"All other document edits — section rewrites, description changes,\",\n      \"acceptance-criteria edits, additions of new sections, retitles, etc. —\",\n      \"remain the exclusive responsibility of the `requirements-writer`\",\n      \"bundle and flow through `req:write` follow-up issues.\",\n      \"\",\n      \"This agent **never** authors new requirement documents, capability\",\n      \"models, gap reports, or research notes. New authoring belongs to the\",\n      \"`requirements-writer` bundle (requirement docs) and `bcm-writer`\",\n      \"bundle (capability models). Gap discovery belongs to the\",\n      \"`requirements-analyst` bundle. Keep this boundary clean: never open\",\n      \"`req:scan`, `req:draft-trace`, `req:review`, or `bcm:*` issues\",\n      \"from this pipeline. The only follow-ups you open are the\",\n      \"`req:write` issues documented below.\",\n      \"\",\n      \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n      \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...PROJECT_CONTEXT_READER_SECTION,\n      \"## Soft Dependency on the Requirements Writer Bundle\",\n      \"\",\n      \"This reviewer expects the requirement category templates to be\",\n      \"available at:\",\n      \"\",\n      \"```\",\n      REQUIREMENTS_WRITER_PATHS.templatesRoot,\n      \"```\",\n      \"\",\n      \"Those templates are shipped by the `requirements-writer` bundle —\",\n      \"this bundle does **not** ship its own copy. If the templates are\",\n      \"missing, either add the `requirements-writer` bundle to your project\",\n      \"(via `includeBundles: ['requirements-writer']` or by removing it\",\n      \"from `excludeBundles`) or supply equivalent templates at the same\",\n      \"path before running a review.\",\n      \"\",\n      \"Read the templates before reviewing each document so you know which\",\n      \"sections are required for that category. The standards reference at\",\n      `\\`${REQUIREMENTS_WRITER_PATHS.standardsRef}\\``,\n      \"(also shipped by the writer bundle) is useful when evaluating\",\n      \"whether a SEC/NFR/INT requirement meets the depth expected by its\",\n      \"governing standard.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Design Principles\",\n      \"\",\n      \"1. **One phase per session.** Each session handles either one\",\n      \"   `req:review` issue or one `req:deprecate` issue — never both, and\",\n      \"   never two of the same. Stop after the phase's terminal step.\",\n      \"2. **Audit-only in `req:review`.** In the review phase, findings are\",\n      \"   reported in the review report and as follow-up issues. Direct\",\n      \"   edits to requirement documents belong to the `requirements-writer`\",\n      \"   agent picking up a follow-up `req:write` issue.\",\n      \"3. **Narrow-write in `req:deprecate`.** In the deprecation phase,\",\n      \"   edits are limited to the Status field, the Revision History, the\",\n      \"   Traceability `Superseded-by` line, and the category index row.\",\n      \"   Every other edit flows through `req:write` follow-ups for the\",\n      \"   `requirements-writer` to execute.\",\n      \"4. **Templates are authoritative.** When a document is missing a\",\n      \"   section that the matching category template requires, that is a\",\n      \"   structural finding — not a stylistic choice.\",\n      \"5. **Resolve every link against the filesystem.** Cross-reference\",\n      \"   integrity findings and back-reference sweeps only count when the\",\n      \"   target path is actually verified on disk. Do not eyeball —\",\n      \"   resolve relative paths and confirm the file exists (or is\",\n      \"   missing).\",\n      \"6. **Cite, don't invent.** Every finding and every deprecation\",\n      \"   rationale cites the file path, line range (when available), and\",\n      \"   the specific check or reason that produced it. Never speculate\",\n      \"   about author intent.\",\n      \"7. **Deprecation is irreversible in practice.** Before writing any\",\n      \"   status change in the deprecation phase, pause for explicit human\",\n      \"   confirmation on the `req:deprecate` issue. Never self-approve.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Configurable Paths\",\n      \"\",\n      \"The pipeline uses these placeholders. Consuming projects override\",\n      \"the defaults by passing paths in the `/review-requirements` skill\",\n      `invocation, by recording overrides in \\`${paths.docsRoot}/project-context.md\\`, or`,\n      \"by extending this rule in their own `agentConfig.rules`.\",\n      \"\",\n      \"| Placeholder | Meaning | Default |\",\n      \"|-------------|---------|---------|\",\n      `| \\`<REQUIREMENTS_ROOT>\\` | Root folder for final requirement documents | \\`${paths.requirementsRoot}/\\` |`,\n      `| \\`<REVIEW_REPORTS_ROOT>\\` | Where review reports are written | \\`${paths.researchRoot}/reviews/\\` |`,\n      `| \\`<TEMPLATES_ROOT>\\` | Where the writer bundle ships category templates (read-only for this agent) | \\`${REQUIREMENTS_WRITER_PATHS.templatesRoot}\\` |`,\n      `| \\`<STANDARDS_REF>\\` | Standards & frameworks reference shipped by the writer bundle | \\`${REQUIREMENTS_WRITER_PATHS.standardsRef}\\` |`,\n      \"| `<STALE_PROPOSED_THRESHOLD_DAYS>` | Age (in days) after which a `Proposed` ADR/TR is flagged as a stale decision by Check 12 | `14` |\",\n      \"\",\n      `If \\`${paths.docsRoot}/project-context.md\\` specifies a different requirements`,\n      \"tree, prefer that. Otherwise fall back to the defaults above.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...renderClaimVerificationSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderOriginStampSection(),\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase Router\",\n      \"\",\n      \"Before reading any documents, classify the session by reading the\",\n      \"issue's phase label:\",\n      \"\",\n      \"- `req:review` → run the **Review Phase** (sections `Review Scope`\",\n      \"  through `Iterating on Reviews` below).\",\n      \"- `req:deprecate` → run the **Deprecation Phase** (section\",\n      \"  `Deprecation Phase` below).\",\n      \"\",\n      \"If the issue carries neither label, or both, comment on the issue\",\n      \"asking the author to pick one, apply `status:needs-attention`, and\",\n      \"stop. Do not attempt to infer the phase from the issue title or body.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Review Scope\",\n      \"\",\n      \"*(This and the following sections through `Iterating on Reviews`\",\n      \"describe the `req:review` phase. For `req:deprecate`, skip ahead to\",\n      \"the `Deprecation Phase` section.)*\",\n      \"\",\n      \"Read the `req:review` issue body to determine the scope. The skill\",\n      \"supports four scopes — clarify with the issue author or in a\",\n      \"follow-up comment if the scope is not stated:\",\n      \"\",\n      \"1. **Full audit** — every requirement document under\",\n      \"   `<REQUIREMENTS_ROOT>` across all categories\",\n      \"2. **Category audit** — every document in one category directory\",\n      `   (e.g., all FRs under \\`<REQUIREMENTS_ROOT>/${paths.requirementCategoryDirs.functional}/\\`)`,\n      \"3. **Single document** — one specific requirement file\",\n      \"4. **Targeted check** — one or more checks from the catalog below,\",\n      '   run across the documents in scope (e.g., \"check all traceability',\n      '   links\" or \"verify tier classification only\")',\n      \"\",\n      \"A full audit on a large document set can be extensive. If the issue\",\n      \"does not state a scope, comment on the issue requesting one and\",\n      \"leave the issue in `status:needs-attention` rather than guessing.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Review Checklist\",\n      \"\",\n      \"Apply the following 12 checks. Each check produces zero or more\",\n      \"findings. Findings are graded Critical / Warning / Info using the\",\n      \"severity ladder in the next section.\",\n      \"\",\n      \"### 1. Structural Compliance\",\n      \"\",\n      \"For each document in scope, verify:\",\n      \"\",\n      \"- YAML frontmatter present with `title` and `description` fields\",\n      \"- Title in frontmatter matches the `# Heading` line\",\n      \"- File name follows `{PREFIX}-{NNN}-{slug}.md` (or the project\",\n      `  prefix declared in \\`${paths.docsRoot}/project-context.md\\`)`,\n      \"- File is in the correct category directory under\",\n      \"  `<REQUIREMENTS_ROOT>`\",\n      \"- `Status` field is set to one of the valid values: `Draft`,\",\n      \"  `Proposed`, `Accepted`, `Implemented`, `Deprecated`, `Superseded`\",\n      \"- All sections from the matching category template at\",\n      \"  `<TEMPLATES_ROOT>` are present (sections that do not apply must\",\n      \"  carry `Not applicable — <reason>` rather than being silently\",\n      \"  omitted)\",\n      \"- `## Open Items` section exists with all three subsections\",\n      \"  (Identified Gaps, Follow-up Questions, Contradictions &\",\n      \"  Inconsistencies)\",\n      \"- `## Revision History` section exists\",\n      \"- `## Traceability` section exists\",\n      \"\",\n      \"### 2. Categorization Accuracy\",\n      \"\",\n      \"Verify each document is in the right category by applying the\",\n      \"shared taxonomy disambiguation rules. The reviewer and the\",\n      \"`requirements-writer` load the **same** rules from\",\n      \"`requirements-taxonomy.ts` so the reviewer never flags a\",\n      \"correctly-categorized document as wrong:\",\n      \"\",\n      ...REQUIREMENTS_TAXONOMY_DISAMBIGUATION_SECTION,\n      \"\",\n      \"Flag any documents that appear miscategorized. Explain where they\",\n      \"should live and why.\",\n      \"\",\n      \"### 3. Traceability Completeness\",\n      \"\",\n      \"Check that the requirement dependency graph is connected. Apply\",\n      \"these expectations as defaults; override them when the project's\",\n      `\\`${paths.docsRoot}/project-context.md\\` defines a different traceability shape:`,\n      \"\",\n      \"- Every FR should trace back to at least one BR (via\",\n      '  \"Implements\")',\n      '- Every TR should trace to at least one ADR (via \"Justified by\")',\n      \"- Every ADR should trace to at least one BR or FR (via\",\n      '  \"Supports\")',\n      \"- Every SEC, NFR, UX should appear as a constraint or\",\n      \"  cross-reference on the FRs they affect\",\n      \"- Every INT should trace to at least one FR that depends on it\",\n      \"- Every DR should be referenced by SEC documents that govern its\",\n      \"  protection\",\n      \"- Every OPS should reference the NFR targets it monitors\",\n      \"\",\n      \"Identify orphaned requirements (documents with no inbound or\",\n      \"outbound traceability links) and flag them.\",\n      \"\",\n      \"### 4. Cross-Reference Integrity\",\n      \"\",\n      \"Check **every markdown link to a `.md` file in the entire\",\n      \"document** — not just links inside the Traceability section.\",\n      \"Broken links frequently appear in body text (Description, Main\",\n      \"Flow, Acceptance Criteria, etc.) where documents reference other\",\n      \"requirements inline.\",\n      \"\",\n      \"For every link in every document:\",\n      \"\",\n      \"- The target file exists at the referenced path — **resolve the\",\n      \"  relative path against the filesystem**, do not eyeball it\",\n      \"- The target file's ID matches the link text\",\n      \"- Relative paths are correct (cross-category uses `../`,\",\n      \"  same-category is direct)\",\n      \"- All links include the `.md` extension\",\n      \"- Bidirectional links exist where expected (if A references B in\",\n      \"  Traceability, B should reference A)\",\n      \"\",\n      \"Findings from this check describe edits inside an existing\",\n      \"requirement document (the broken link lives in the body of the\",\n      \"doc and must be rewritten or removed). Route follow-up issues to\",\n      \"`req:write` so the `requirements-writer` — the only agent scoped\",\n      \"to edit under `<REQUIREMENTS_ROOT>` — picks them up. Do **not**\",\n      \"route Check 4 findings to `req:draft-trace`; the analyst bundle\",\n      \"does not edit requirement documents and the issue would sit\",\n      \"unresolved. See the Follow-Up Issues section below for the full\",\n      \"Check 3 vs. Check 4 routing split.\",\n      \"\",\n      \"### 5. Sequence Number Integrity\",\n      \"\",\n      \"Within each category directory under `<REQUIREMENTS_ROOT>`:\",\n      \"\",\n      \"- No duplicate sequence numbers\",\n      \"- No gaps in the sequence (gaps may be intentional from deleted\",\n      \"  docs but should be noted as Info)\",\n      \"- Sequence numbers are zero-padded to three digits (`001`, `012`,\",\n      \"  `127`)\",\n      \"\",\n      \"### 6. Content Quality\",\n      \"\",\n      \"For each document, evaluate:\",\n      \"\",\n      \"- **Completeness** — Are all template sections filled in\",\n      \"  meaningfully, or are there unexplained TBDs?\",\n      \"- **Specificity** — Are acceptance criteria testable? Are NFR\",\n      \"  targets numeric and measurable? Are success metrics concrete?\",\n      \"- **Consistency** — Do related documents agree with each other?\",\n      \"  (e.g., does an FR's description match the corresponding INT's\",\n      \"  integration shape?)\",\n      \"- **Staleness** — Are statuses up to date? Are there `Draft`\",\n      \"  documents that should have progressed?\",\n      `- **Naming consistency** — When \\`${paths.docsRoot}/project-context.md\\` declares`,\n      \"  a project name or product name, verify it is used consistently\",\n      \"  across documents.\",\n      \"\",\n      \"### 7. Open Items Review\",\n      \"\",\n      \"Across all documents in scope:\",\n      \"\",\n      \"- Are open items prioritized (P0–P3)?\",\n      \"- Are interdependencies between open items documented with\",\n      \"  cross-references?\",\n      \"- Are there P0 (Blocker) items that have not been resolved?\",\n      \"- Are there stale open items that should have been addressed?\",\n      \"\",\n      \"### 8. Registry Index Sync\",\n      \"\",\n      \"Each category directory has a `README.md` (or `index.md`) file\",\n      \"that serves as a registry table listing all requirements in that\",\n      \"category. Check that these are in sync:\",\n      \"\",\n      \"- Every requirement file in the directory has a corresponding row\",\n      \"  in the index\",\n      \"- No rows in the index reference files that do not exist (stale\",\n      \"  entries from deleted docs)\",\n      \"- Rows are in sequence number order\",\n      \"- The ID, Title, Status, and Priority in each row match the\",\n      \"  document's metadata\",\n      \"- No placeholder message remains when requirements exist\",\n      \"\",\n      \"Flag missing entries as **Warning** and stale or incorrect entries\",\n      \"as **Warning**.\",\n      \"\",\n      \"### 9. Decision Authority Compliance\",\n      \"\",\n      \"Verify that the `requirements-writer` decision-authority rules\",\n      \"were followed:\",\n      \"\",\n      \"- ADR and TR documents should be in `Proposed` status if they\",\n      \"  have not been explicitly accepted by a human\",\n      \"- Direct-write categories (BR, FR, NFR, SEC, UX) should not\",\n      \"  contain technology-specific decisions — those should be deferred\",\n      \"  to ADR/TR documents\",\n      \"- Partial-deferral categories (DR, MT, INT, OPS) should defer\",\n      \"  technology/tooling choices to `Proposed` ADR/TR documents\",\n      \"  rather than embedding them inline\",\n      \"\",\n      \"For `Proposed` ADR and TR documents, additionally verify the\",\n      \"comparison and recommendation structure:\",\n      \"\",\n      \"- **Alternatives Considered** section exists with at least 2\",\n      \"  options\",\n      \"- Each alternative has a description, pros, and cons — no option\",\n      \"  is given cursory treatment\",\n      \"- **Recommendation** section exists with a named recommended\",\n      \"  option\",\n      \"- Recommendation includes a reasoned explanation specific to this\",\n      \"  project's context (not generic)\",\n      \"- Recommendation identifies key trade-offs being accepted\",\n      '- Decision section says \"Pending human review\" (not \"We',\n      '  will...\" or \"We decided...\")',\n      \"- Open Items include an item flagging that human decision is\",\n      \"  required, with references to dependent requirements blocked on\",\n      \"  this decision\",\n      \"\",\n      \"### 10. Tier Classification Compliance\",\n      \"\",\n      \"Verify that every document has a valid tier classification. The\",\n      \"default tier set is `platform`, `industry`, `customer-workflow`,\",\n      \"`consumer-app`; consuming projects may rename or reduce the tier\",\n      `set in their own \\`${paths.docsRoot}/project-context.md\\`.`,\n      \"\",\n      \"- `tier` field is set in YAML frontmatter (one of the project's\",\n      \"  declared tier slugs)\",\n      \"- `Tier` row is set in the Metadata table with a matching value\",\n      \"- `Implementor` field is set for Customer Workflow and Consumer\",\n      \"  Application tiers when the project tracks that distinction\",\n      \"  (Consortium Member / Customer / TBD)\",\n      \"- `Implementor` field is absent or N/A for Platform and Industry\",\n      \"  tiers\",\n      '- When `Implementor` is \"Consortium Member\", it links to a',\n      \"  valid org profile\",\n      \"- `Customer` field is set for Customer Workflow and Consumer\",\n      \"  Application tiers when the project tracks customer profiles,\",\n      \"  linking to a valid customer org profile\",\n      \"- `Customer` field in YAML frontmatter (if present) matches the\",\n      \"  Customer row in the Metadata table\",\n      \"- `customer:<slug>` label exists on the corresponding GitHub issue\",\n      \"  (when traceable)\",\n      \"- Industry-tier requirements specify which industry/vertical they\",\n      \"  apply to\",\n      \"- Platform-tier requirements do not contain industry-specific\",\n      \"  concerns that should be scoped to the Industry tier\",\n      \"- Cross-tier traceability links exist where expected:\",\n      \"  - Consumer Application requirements have `Depends on\",\n      \"    (cross-tier)` links to Platform requirements (the APIs they\",\n      \"    consume)\",\n      \"  - Customer Workflow requirements have `Depends on (cross-tier)`\",\n      \"    links to Platform requirements (the configuration capabilities\",\n      \"    they use)\",\n      \"  - Industry requirements have `Depends on (cross-tier)` links to\",\n      \"    Platform requirements (the core services they extend)\",\n      \"  - Platform requirements that enable higher-tier work have\",\n      \"    `Enables (cross-tier)` links\",\n      \"- Multi-tier decompositions are complete — if a customer need was\",\n      \"  decomposed across tiers, all expected tiers have corresponding\",\n      \"  requirements linked together\",\n      \"\",\n      \"Flag as **Critical**: missing tier field; platform requirements\",\n      \"containing industry-specific logic.\",\n      \"Flag as **Warning**: missing cross-tier traceability; missing\",\n      \"Implementor field on Customer Workflow / Consumer Application\",\n      \"requirements when the project tracks that field; missing Customer\",\n      \"field on Customer Workflow / Consumer Application requirements;\",\n      'Implementor claiming \"Consortium Member\" without a linked org',\n      \"profile.\",\n      \"\",\n      \"### 11. Cross-Referencing Convention Compliance\",\n      \"\",\n      \"Verify alignment with the project's cross-referencing conventions\",\n      `(usually documented in \\`${paths.docsRoot}/project-context.md\\` or a profile`,\n      \"registry index):\",\n      \"\",\n      \"- Requirements that reference profiled organizations use the\",\n      \"  project's profile-link convention (e.g., `profilePath`\",\n      \"  frontmatter, or relative links into the profiles tree)\",\n      \"- Requirements that trace to research output link to the correct\",\n      \"  paths under the project's research tree\",\n      \"- Optional convention: meeting-sourced requirements may reference\",\n      \"  the meeting transcript or insight document. This is **optional** —\",\n      \"  only flag missing meeting links when the project documents the\",\n      \"  reverse-link structure (e.g., a `referencedIn.meetings[]`\",\n      \"  frontmatter block) and that structure is in active use.\",\n      \"\",\n      \"### 12. Stale Proposed Decisions\",\n      \"\",\n      \"ADR and TR documents ship as `Status: Proposed` because they\",\n      \"encode architectural or technology decisions that require explicit\",\n      \"human acceptance (see Check 9 and the `requirements-writer`\",\n      \"decision-authority rules). Once `Proposed`, there is no automatic\",\n      \"signal that surfaces long-`Proposed` documents for decision — the\",\n      \"backlog silently accumulates. Check 12 surfaces them.\",\n      \"\",\n      \"For every document under `<REQUIREMENTS_ROOT>` whose category is\",\n      \"**ADR** or **TR** and whose `Status` is `Proposed`:\",\n      \"\",\n      \"- Determine the document's last-touched date. Prefer the YAML\",\n      \"  frontmatter `updated` field when present. If frontmatter does\",\n      \"  not carry an `updated` field, fall back to the most recent entry\",\n      \"  in the `## Revision History` section. If neither exists, fall\",\n      \"  back to `git log -1 --format=%cI -- <path>` for the file.\",\n      \"- Compare that date to today. If the document has carried\",\n      \"  `Status: Proposed` for longer than\",\n      \"  `<STALE_PROPOSED_THRESHOLD_DAYS>` days (default 14), record a\",\n      \"  **Warning** finding that names the document, the age in days,\",\n      \"  the threshold, and the source used for the last-touched date.\",\n      \"- Do **not** flag `Proposed` ADRs or TRs that are below the\",\n      \"  threshold — they are in active decision and not stale.\",\n      \"- Do **not** auto-transition any status. Deprecation and\",\n      \"  acceptance both remain human decisions: Check 12 only surfaces\",\n      \"  the backlog for the human running `/review-requirements` (or\",\n      \"  for the follow-up issue it files) to act on.\",\n      \"\",\n      \"The threshold placeholder `<STALE_PROPOSED_THRESHOLD_DAYS>` is\",\n      \"configurable — override it in the `req:review` issue body, in\",\n      `\\`${paths.docsRoot}/project-context.md\\`, or via \\`agentConfig.rules\\`. The default`,\n      \"of 14 days sits above the orchestrator's existing 72h / 168h stale\",\n      \"thresholds for `status:in-progress` / `status:blocked` and fits\",\n      \"the pace at which architectural decisions are typically ratified.\",\n      \"\",\n      \"Findings from Check 12 describe a decision the human must make —\",\n      \"not an edit to the requirement document itself. Follow-up routing\",\n      \"is therefore different from Checks 3 and 4:\",\n      \"\",\n      \"- Surface every stale `Proposed` ADR/TR in a distinct\",\n      \"  **Stale decisions** section in the review report (see Reporting\",\n      \"  Format below), separate from Critical / Warning / Info.\",\n      \"- File **one** follow-up issue covering the stale decisions found\",\n      \"  in this review. Title:\",\n      \"  `req(review): decide on stale Proposed ADR/TR documents`.\",\n      \"  Labels: `type:requirement`, `req:review`, `priority:medium`,\",\n      \"  `status:needs-attention`. Body must list each stale document\",\n      \"  path, its age in days, and a link back to the review report.\",\n      \"  Do **not** file one follow-up per document — humans triage the\",\n      \"  backlog in a single pass.\",\n      \"- When no stale documents are found, omit the Stale decisions\",\n      \"  section entirely and do not file the follow-up issue.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Severity Ladder\",\n      \"\",\n      \"Group every finding by severity:\",\n      \"\",\n      \"### Critical (Must Fix)\",\n      \"\",\n      \"Issues that undermine the integrity of the requirements\",\n      \"documentation:\",\n      \"\",\n      \"- Miscategorized requirements\",\n      \"- Broken cross-references (target file does not exist on disk)\",\n      \"- Missing mandatory template sections\",\n      \"- Technology decisions embedded in direct-write categories without\",\n      \"  a corresponding `Proposed` ADR/TR\",\n      \"- P0 open items that are unresolved\",\n      \"- Missing `tier` field; platform requirements containing\",\n      \"  industry-specific logic\",\n      \"\",\n      \"### Warning (Should Fix)\",\n      \"\",\n      \"Issues that reduce quality but do not break the documentation:\",\n      \"\",\n      \"- Missing traceability links (orphaned requirements)\",\n      \"- Unidirectional cross-references (A links to B, but B does not\",\n      \"  link to A)\",\n      \"- Vague acceptance criteria or unmeasurable NFR targets\",\n      \"- Stale statuses or unaddressed open items\",\n      \"- Sequence number gaps\",\n      \"- Registry index out of sync with actual files (missing entries,\",\n      \"  stale rows, incorrect metadata)\",\n      \"- Missing cross-tier traceability; missing Implementor / Customer\",\n      \"  fields on Customer Workflow / Consumer Application requirements\",\n      \"  when the project tracks those fields\",\n      \"- Stale `Proposed` ADR/TR documents that have carried the\",\n      \"  `Proposed` status longer than\",\n      \"  `<STALE_PROPOSED_THRESHOLD_DAYS>` (default 14) days. The\",\n      \"  underlying document is valid; only the absence of human\",\n      \"  decision is stale, so these are reported in the report's\",\n      \"  dedicated **Stale decisions** section rather than inline in\",\n      \"  the Warning list.\",\n      \"\",\n      \"### Info (Consider)\",\n      \"\",\n      \"Observations and suggestions:\",\n      \"\",\n      \"- Opportunities to add cross-references between related\",\n      \"  requirements\",\n      \"- TBD sections that could be filled in with available information\",\n      \"- Style inconsistencies across documents\",\n      \"- Sequence number gaps that appear intentional from deleted docs\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Reporting Format\",\n      \"\",\n      \"Write the review report to\",\n      \"`<REVIEW_REPORTS_ROOT>/review-<scope>-YYYY-MM-DD.md` (substitute\",\n      \"the date and a short scope slug). Structure the report as:\",\n      \"\",\n      \"```markdown\",\n      \"# Requirements Review: <scope>\",\n      \"\",\n      \"**Date:** YYYY-MM-DD\",\n      \"**Scope:** <full audit | category | single document | targeted\",\n      \"check>\",\n      \"**Source issue:** #NNN\",\n      \"\",\n      \"## Critical (Must Fix)\",\n      \"\",\n      \"1. **[<file path>] <short title>** `Critical`\",\n      \"   <one-paragraph description, citing the specific check that\",\n      \"   failed>\",\n      \"\",\n      \"## Warning (Should Fix)\",\n      \"\",\n      \"1. **[<file path>] <short title>** `Warning`\",\n      \"   ...\",\n      \"\",\n      \"## Info (Consider)\",\n      \"\",\n      \"1. **[<file path>] <short title>** `Info`\",\n      \"   ...\",\n      \"\",\n      \"## Stale decisions\",\n      \"\",\n      \"*Omit this section entirely when Check 12 found no stale\",\n      \"`Proposed` ADR/TR documents.*\",\n      \"\",\n      \"| Document | Age (days) | Threshold | Last-touched source |\",\n      \"|----------|------------|-----------|---------------------|\",\n      \"| `<file path>` | N | <STALE_PROPOSED_THRESHOLD_DAYS> | frontmatter `updated` / revision history / git log |\",\n      \"\",\n      \"Human decision required for each row. A single follow-up\",\n      \"`req:review` issue (labels `type:requirement`, `req:review`,\",\n      \"`priority:medium`, `status:needs-attention`) is filed to\",\n      \"track triage; see Check 12 for the exact follow-up contract.\",\n      \"\",\n      \"## Review Summary\",\n      \"\",\n      \"| Severity | Count |\",\n      \"|---|---|\",\n      \"| Critical | N |\",\n      \"| Warning | N |\",\n      \"| Info | N |\",\n      \"| Stale decisions | N |\",\n      \"\",\n      \"**Categories reviewed:** [list]\",\n      \"**Documents reviewed:** N\",\n      \"**Overall assessment:** [Brief 1-2 sentence assessment]\",\n      \"```\",\n      \"\",\n      \"Each finding must cite the file path and the specific check that\",\n      'produced it (e.g., \"Check 4: Cross-Reference Integrity — target',\n      `file \\`../${paths.requirementCategoryDirs.security}/SEC-007-audit-logs.md\\` does not exist on`,\n      'disk\").',\n      \"\",\n      \"---\",\n      \"\",\n      \"## Automated Verification (>10 documents)\",\n      \"\",\n      \"For audits covering more than 10 documents, **write a Python\",\n      \"verification script** rather than reading files one by one.\",\n      \"Manual review of large document sets always misses things —\",\n      \"especially broken links where the filename is plausible but wrong.\",\n      \"\",\n      \"Save the script alongside the review report at\",\n      \"`<REVIEW_REPORTS_ROOT>/review-<scope>-YYYY-MM-DD-verify.py` so\",\n      \"future reviews can re-run it. The script must be idempotent and\",\n      \"read-only — it inspects files, it does not mutate them.\",\n      \"\",\n      \"At minimum, the script must:\",\n      \"\",\n      \"1. **Resolve every markdown link.** For each `[text](path.md)`\",\n      \"   link in every document in scope, resolve the relative path\",\n      \"   against the filesystem and verify the target file exists.\",\n      \"   Do not skip links outside Traceability sections.\",\n      \"2. **Extract traceability links.** Parse the `## Traceability`\",\n      \"   section of each document, collect all `[PREFIX-NNN](path)`\",\n      \"   references, and build a directed link graph.\",\n      \"3. **Check bidirectionality.** For every (A → B) link in the\",\n      \"   graph, verify (B → A) exists.\",\n      \"4. **Verify structural sections.** Check for required section\",\n      \"   headings (`## Open Items`, `## Revision History`,\",\n      \"   `## Traceability`, etc.) using string matching.\",\n      \"5. **Check registry sync.** Compare files on disk in each\",\n      \"   category directory against entries in the directory's\",\n      \"   `README.md` / `index.md`.\",\n      \"\",\n      \"Present the script's output as the basis for the audit report.\",\n      \"This ensures reproducible, complete results.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Filesystem Durability and Issue-Graph Sequencing\",\n      \"\",\n      \"Write the review report to disk **before** opening any follow-up\",\n      \"issues. The report is the durable record; the issues are pointers\",\n      \"into it. If the session is interrupted after issues are filed but\",\n      \"before the report is committed, future runs cannot reconstruct the\",\n      \"context.\",\n      \"\",\n      \"Sequence:\",\n      \"\",\n      \"1. Read scope from the `req:review` issue.\",\n      \"2. Read the matching templates from `<TEMPLATES_ROOT>` for every\",\n      \"   category in scope.\",\n      \"3. Run the 12 checks. For audits >10 documents, write the\",\n      \"   verification script to disk first and run it.\",\n      \"4. Write the report to\",\n      \"   `<REVIEW_REPORTS_ROOT>/review-<scope>-YYYY-MM-DD.md`.\",\n      \"5. Commit the report (and verification script, if written).\",\n      \"6. Open one follow-up issue per actionable finding (Critical or\",\n      \"   Warning). Every follow-up issue includes the file path, a link\",\n      \"   to the report, and the specific check that produced it.\",\n      \"7. Comment on the `req:review` issue with a summary of findings\",\n      \"   and links to the follow-up issues.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Follow-Up Issues\",\n      \"\",\n      \"Open follow-up issues for **Critical** and **Warning** findings.\",\n      \"Skip Info findings — they are guidance, not work items.\",\n      \"\",\n      \"Each follow-up issue:\",\n      \"\",\n      \"- Carries `type:requirement` (the type owned by the upstream\",\n      \"  `requirements-analyst` bundle)\",\n      \"- Carries the appropriate phase label for the work needed:\",\n      \"  - Structural / content fixes that an existing requirement\",\n      \"    document needs (including broken internal cross-references\",\n      \"    from Check 4 — e.g., a `See: [FR-012](...)` link pointing at\",\n      \"    a renamed or deleted requirement) → `req:write` (the\",\n      \"    `requirements-writer` agent picks it up to revise the\",\n      \"    document). Only the writer is scoped to edit requirement\",\n      \"    documents, so anything that requires an in-place edit under\",\n      \"    `<REQUIREMENTS_ROOT>` routes here. `req:write` follow-ups\",\n      \"    must also carry the matching `tier:*` label and an issue\",\n      \"    body that conforms to the `req:write` issue schema below.\",\n      \"  - Missing traceability in **source documents** — BCM model\",\n      \"    docs, competitive-analysis notes, product-roadmap entries,\",\n      \"    meeting extracts — that should link forward to an existing\",\n      \"    requirement (Check 3: orphaned requirements whose fix lives\",\n      \"    in the source tree, not the requirement doc) → `req:draft-trace`\",\n      \"    (the `requirements-analyst` agent picks it up to backfill\",\n      \"    source-doc traceability inside its combined draft-trace phase).\",\n      \"    **Do not** route Check 4 broken cross-references here — the\",\n      \"    analyst bundle never writes to `<REQUIREMENTS_ROOT>` and the\",\n      \"    issue would sit unresolved.\",\n      \"  - A new requirement is needed (e.g., a `Proposed` ADR is missing\",\n      \"    for a deferred technology choice) → `req:scan` (the analyst\",\n      \"    runs a scoped scan to confirm the gap, then drafts the new\",\n      \"    requirement through the normal pipeline)\",\n      \"- Sets priority based on finding severity: Critical →\",\n      \"  `priority:high`; Warning → `priority:medium`\",\n      \"- Includes the affected file path in the body and links back to\",\n      \"  the review report\",\n      \"- Adds `status:ready` (or `status:blocked` when the finding\",\n      \"  declares a `Depends on: #N` on another open issue)\",\n      \"\",\n      \"**Check 12 exception — stale `Proposed` ADR/TR triage.** Check 12\",\n      \"findings are the one case where follow-up flows through a new\",\n      \"`req:review` issue rather than `req:write` / `req:draft-trace` /\",\n      \"`req:scan`. The finding is a decision a human must make, not an\",\n      \"edit to a requirement document, so:\",\n      \"\",\n      \"- File **one** aggregated follow-up (not one per document). The\",\n      \"  title is\",\n      \"  `req(review): decide on stale Proposed ADR/TR documents`.\",\n      \"- Labels: `type:requirement`, `req:review`, `priority:medium`,\",\n      \"  `status:needs-attention`.\",\n      \"- Body lists every stale document surfaced in this review with\",\n      \"  its path, age in days, and the threshold used, and links back\",\n      \"  to the Stale decisions section of the review report.\",\n      \"- This is the **only** case in which the reviewer opens a\",\n      \"  `req:review` issue — it is explicitly not self-referential\",\n      \"  because the new issue triages decisions rather than triggering\",\n      \"  another review.\",\n      \"- The `req:write` follow-up schema below does **not** apply to\",\n      \"  this Check 12 issue; the schema governs `req:write` payloads,\",\n      \"  and this follow-up is a `req:review` triage item.\",\n      \"\",\n      \"### `req:write` follow-up schema\",\n      \"\",\n      \"Because this bundle is the second-largest producer of `req:write`\",\n      \"issues (the analyst's trace phase is the first), every `req:write`\",\n      \"follow-up opened in either the review phase or the deprecation\",\n      \"phase must satisfy the schema the writer parses on intake:\",\n      \"\",\n      ...REQ_WRITE_ISSUE_SCHEMA_SECTION,\n      \"\",\n      \"**Deriving the three required fields from the target document.**\",\n      \"For every structural-repair follow-up the reviewer generates, the\",\n      \"three fields come directly from the requirement document being\",\n      \"edited:\",\n      \"\",\n      \"- **Category** — read the category prefix from the document's\",\n      \"  filename (`FR-012-...` → `FR`). Confirm against the frontmatter\",\n      \"  / Metadata table `ID` row and the document's `# Heading`. If\",\n      \"  the three disagree, route through `Missing:` with the\",\n      \"  disagreement noted rather than picking one.\",\n      \"- **Tier** — read the Metadata table `Tier` row. Normalize to the\",\n      \"  slug form (`platform`, `industry`, `customer-workflow`,\",\n      \"  `consumer-app`). If the Tier row is missing, empty, or set to\",\n      \"  a value outside the four-tier taxonomy, route through\",\n      \"  `Missing:`.\",\n      \"- **Output Path** — the current absolute-from-repo-root path of\",\n      \"  the document being edited. The writer edits in place; the path\",\n      \"  does not change for a structural repair.\",\n      \"\",\n      \"For deprecation back-reference follow-ups, the three fields come\",\n      \"from the **referencing** document (the one that still mentions\",\n      \"the deprecated ID), not the deprecated target itself.\",\n      \"\",\n      \"**Validation step — required before opening the issue.** The\",\n      \"reviewer asserts all three required fields are populated before\",\n      \"it calls `gh issue create`. If any field cannot be derived:\",\n      \"\",\n      \"1. Open the follow-up with `status:needs-attention` (not\",\n      \"   `status:ready`).\",\n      \"2. Include a `Missing: <field> — <one-line reason>` line at the\",\n      \"   top of the body explaining which field could not be\",\n      \"   determined and why (e.g., `Missing: Tier — Metadata table\",\n      \"   has no Tier row and the document predates the four-tier\",\n      \"   classification`).\",\n      \"3. Populate whichever of the three fields **could** be derived\",\n      \"   so a human triaging the issue only has to supply the\",\n      \"   remaining value(s) before flipping the label to\",\n      \"   `status:ready`.\",\n      \"\",\n      \"**Do NOT create:**\",\n      \"\",\n      \"- `req:review` issues for any reason other than the Check 12\",\n      \"  stale-decisions triage documented above — that would be\",\n      \"  self-referential\",\n      \"- `bcm:*`, `people:*`, `company:*`, `software:*`, `research:*`,\",\n      \"  or `industry:*` issues — those belong to their respective\",\n      \"  bundles. If the review surfaces work for one of those bundles,\",\n      \"  comment on the `req:review` issue with the suggested follow-up\",\n      \"  and let a human triage it\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Output Boundaries\",\n      \"\",\n      \"### In `req:review`\",\n      \"\",\n      \"This agent writes **only** to:\",\n      \"\",\n      \"- `<REVIEW_REPORTS_ROOT>/review-<scope>-YYYY-MM-DD.md` — one\",\n      \"  review report per session\",\n      \"- `<REVIEW_REPORTS_ROOT>/review-<scope>-YYYY-MM-DD-verify.py` —\",\n      \"  the verification script for audits >10 documents (read-only,\",\n      \"  idempotent)\",\n      \"- Follow-up GitHub issues (one per actionable finding)\",\n      \"- A summary comment on the `req:review` issue\",\n      \"\",\n      \"**Do NOT write to** in the review phase:\",\n      \"\",\n      \"- The requirement documents themselves under\",\n      \"  `<REQUIREMENTS_ROOT>` — those edits belong to the\",\n      \"  `requirements-writer` agent picking up a follow-up `req:write`\",\n      \"  issue, or to this agent operating under `req:deprecate` for the\",\n      \"  narrow set of deprecation edits\",\n      \"- The category index files — those edits belong to the writer (or\",\n      \"  to this agent under `req:deprecate` for the index row update)\",\n      \"- The templates at `<TEMPLATES_ROOT>` — those are owned by the\",\n      \"  `requirements-writer` bundle source, not by per-project state\",\n      \"\",\n      \"### In `req:deprecate`\",\n      \"\",\n      \"This agent writes **only** to:\",\n      \"\",\n      \"- The `Status` field, the Metadata table `Status` row, the\",\n      \"  Revision History, the Traceability `Superseded-by` line, and the\",\n      \"  Deprecation reason on each target document under\",\n      \"  `<REQUIREMENTS_ROOT>` (see `Deprecation Phase` for the exact\",\n      \"  edits)\",\n      \"- The affected category `README.md` / `index.md` row(s) to reflect\",\n      \"  the new status\",\n      \"- `req:write` follow-up GitHub issues — one per referencing\",\n      \"  requirement document surfaced by the back-reference sweep\",\n      \"- A summary comment on the `req:deprecate` issue\",\n      \"\",\n      \"**Do NOT write to** in the deprecation phase:\",\n      \"\",\n      \"- Any section of the target document not named in the Deprecation\",\n      \"  Phase edits list (do not rewrite Description, Acceptance\",\n      \"  Criteria, Open Items, or any other section)\",\n      \"- The templates at `<TEMPLATES_ROOT>`\",\n      \"- Review reports under `<REVIEW_REPORTS_ROOT>` (the review phase\",\n      \"  owns those)\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Iterating on Reviews\",\n      \"\",\n      \"After the report is committed and follow-up issues are filed:\",\n      \"\",\n      \"1. Comment on the `req:review` issue with a one-paragraph summary,\",\n      \"   the severity counts, and links to the report and follow-up\",\n      \"   issues.\",\n      \"2. If the user asked for re-review after fixes land, open a fresh\",\n      \"   `req:review` issue rather than reopening the original. Each\",\n      \"   review session produces a new dated report.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Deprecation Phase\",\n      \"\",\n      \"The deprecation phase is how requirement documents transition to\",\n      \"`Deprecated` or `Superseded`. None of the other requirements\",\n      \"bundles owns this transition — the writer only ships new documents,\",\n      \"and the reviewer's `req:review` mode can *detect* stale status but\",\n      \"has no mechanism to fix it. This phase fills that gap.\",\n      \"\",\n      \"Deprecation never deletes files. It leaves the document in place\",\n      \"with a clearly updated `Status`, a Deprecation reason, a\",\n      \"`Superseded-by` link when applicable, and a matching index row so\",\n      \"readers who arrive via old links can follow the trail forward.\",\n      \"\",\n      \"### Input\",\n      \"\",\n      \"One `req:deprecate` issue with the following body sections:\",\n      \"\",\n      \"- **Targets** — one or more requirement IDs or paths to deprecate\",\n      \"  (for example, `ADR-007-auth-provider.md` or\",\n      `  \\`${paths.requirementsRoot}/architecture/ADR-007-auth-provider.md\\`).`,\n      \"- **Transition** — per target, either `Deprecated` (no successor)\",\n      \"  or `Superseded-by: <path>` (where `<path>` is the relative path\",\n      \"  or requirement ID of the replacement document). When the\",\n      \"  transition is `Superseded`, the replacement must already exist\",\n      \"  under `<REQUIREMENTS_ROOT>` — verify before proceeding.\",\n      \"- **Reason** — a one-paragraph rationale that becomes the\",\n      \"  Deprecation reason recorded on the target document.\",\n      \"- **Confirmation** (optional) — the body may include\",\n      \"  `Pre-approved: yes` to skip the human pause below. If omitted,\",\n      \"  pause and request confirmation.\",\n      \"\",\n      \"If the issue is missing any of the first three fields, comment on\",\n      \"the issue requesting the missing input, apply\",\n      \"`status:needs-attention`, and stop. Do not guess.\",\n      \"\",\n      \"### Required Human Confirmation\",\n      \"\",\n      \"Deprecation is irreversible in practice. Before writing any\",\n      \"status change, comment on the `req:deprecate` issue with:\",\n      \"\",\n      \"- The target paths that will be edited\",\n      \"- The exact `Status` value each will receive\",\n      \"- Any `Superseded-by` links that will be written\",\n      \"- The list of back-references that will receive `req:write`\",\n      \"  follow-ups\",\n      \"\",\n      \"Then pause and wait for the issue author (or a maintainer) to reply\",\n      \"with an affirmative confirmation (e.g., `approved`, `confirmed`, or\",\n      \"`yes`). If the issue body already contains `Pre-approved: yes`, the\",\n      \"pause is skipped — record that fact in the final summary comment.\",\n      \"The human decision is what authorizes the edit; never self-approve.\",\n      \"\",\n      \"### Edits Performed\",\n      \"\",\n      \"For each target document, make the following **narrow** edits in a\",\n      \"single commit per target (or one commit for the full batch when the\",\n      \"targets are tightly related). All other edits — description\",\n      \"rewrites, acceptance-criteria tweaks, introduction of new sections —\",\n      \"are out of scope and flow through `req:write` follow-ups.\",\n      \"\",\n      \"1. **Frontmatter `Status`.** Set the YAML frontmatter `Status`\",\n      \"   field to `Deprecated` or `Superseded`.\",\n      \"2. **Metadata table `Status` row.** Update the `Status` row inside\",\n      \"   the Metadata table at the top of the document to match.\",\n      \"3. **`## Revision History`.** Append a new row/entry recording the\",\n      \"   date, the new status, the deprecating agent (this reviewer), and\",\n      \"   the issue number. Use the project's existing Revision History\",\n      \"   format — do not introduce a new format.\",\n      \"4. **`## Traceability` Superseded-by line.** When the transition is\",\n      \"   `Superseded`, insert (or update) a\",\n      \"   `- **Superseded-by:** [<ID>](<relative-path>.md)` line under the\",\n      \"   existing Traceability section. When the transition is plain\",\n      \"   `Deprecated`, no Traceability edit is required.\",\n      \"5. **Deprecation reason.** Add a `- **Deprecation reason:** <one\",\n      \"   paragraph>` line directly below the Superseded-by line (or at\",\n      \"   the top of the Traceability section when no successor exists).\",\n      \"   The paragraph must be the reason from the issue, verbatim.\",\n      \"6. **Category index row.** Open the category directory's\",\n      \"   `README.md` (or `index.md`) and update the target's row:\",\n      \"   change its `Status` column to the new status, and, when\",\n      \"   applicable, append `— superseded by [<ID>](<relative-path>.md)`\",\n      \"   to the title cell. Do not delete the row.\",\n      \"\",\n      \"Do **not** edit any section or field on the target document that is\",\n      \"not named in the six steps above. Do not retitle, do not rewrite\",\n      \"Description, do not change acceptance criteria, do not touch Open\",\n      \"Items. Every other edit belongs to the `requirements-writer`.\",\n      \"\",\n      \"### Back-Reference Sweep\",\n      \"\",\n      \"After the target document edits land, sweep `<REQUIREMENTS_ROOT>`\",\n      \"for every markdown link or inline reference to the deprecated\",\n      \"document. Use the same resolution discipline as Check 4: resolve\",\n      \"each link against the filesystem, do not eyeball. For every\",\n      \"document that still references the deprecated target:\",\n      \"\",\n      \"- File one `req:write` follow-up issue per referencing document\",\n      \"  (not one per link — a single document may carry multiple\",\n      \"  references that a single writer session can address together).\",\n      \"- The issue title must be\",\n      \"  `req(deprecate): update references to <deprecated-ID> in <referencing-ID>`.\",\n      \"- The body must conform to the `req:write` issue schema defined\",\n      \"  in the review phase's **`req:write` follow-up schema** section\",\n      \"  above: Category, Tier, and Output Path derived from the\",\n      \"  **referencing** document (not the deprecated target) via the\",\n      \"  same rules — prefix from filename, Tier from the Metadata\",\n      \"  table, Output Path is the referencing document's current path.\",\n      \"  In addition, the body must include: the deprecated document\",\n      \"  path, the successor path (when applicable), the list of line\",\n      \"  ranges that mention the deprecated ID, the `req:deprecate`\",\n      \"  issue number, and a short instruction asking the writer to\",\n      \"  either remove the reference, point it at the successor, or\",\n      \"  convert it to a historical note (the writer decides per\",\n      \"  reference).\",\n      \"- Labels: `type:requirement`, `req:write`, the matching\",\n      \"  `tier:*` label derived from the referencing document's Tier,\",\n      `  \\`priority:${labelsForPhase(issueDefaults, \"req:write\").priority}\\`, \\`status:${labelsForPhase(issueDefaults, \"req:write\").status}\\`.`,\n      ...renderIssueTypeAssignmentStep({ indent: \"\", bullet: true }),\n      \"- If any of Category / Tier / Output Path cannot be derived from\",\n      \"  the referencing document, open the follow-up with\",\n      \"  `status:needs-attention` and a `Missing:` line, per the same\",\n      \"  validation rule that applies in the review phase.\",\n      \"- Body must include `Depends on: #<req:deprecate issue number>`\",\n      \"  when the rewrite should wait for the deprecation to land, or\",\n      \"  omit that line when the rewrite can run in parallel.\",\n      \"\",\n      \"If the sweep surfaces references from non-requirement documents\",\n      \"(for example, research notes, meeting insights, or capability\",\n      \"models), do **not** open `req:write` for them. Instead, list them\",\n      \"in the summary comment on the `req:deprecate` issue so a human can\",\n      \"triage them into the appropriate bundle. This keeps the bundle\",\n      \"boundary clean.\",\n      \"\",\n      \"### Output\",\n      \"\",\n      \"- One or more edited requirement documents under\",\n      \"  `<REQUIREMENTS_ROOT>` (narrow edits per the list above).\",\n      \"- An updated category `README.md` / `index.md` per affected\",\n      \"  category.\",\n      \"- One `req:write` follow-up issue per referencing requirement\",\n      \"  document.\",\n      \"- A summary comment on the `req:deprecate` issue recording the\",\n      \"  edits made, the follow-ups opened, any non-requirement\",\n      \"  references surfaced, and whether the human confirmation was\",\n      \"  received interactively or via a `Pre-approved: yes` marker.\",\n      \"- A single commit (or tightly-scoped batch) per target, with a\",\n      \"  `chore(requirements): deprecate <ID>` or\",\n      \"  `chore(requirements): supersede <ID> by <new-ID>` message.\",\n      \"\",\n      \"### Filesystem Durability\",\n      \"\",\n      \"As with the review phase, write edits to disk **before** opening\",\n      \"follow-up issues. The edited documents and the updated index are\",\n      \"the durable record; the `req:write` follow-ups are pointers into\",\n      \"that state. If the session is interrupted after follow-ups are\",\n      \"filed but before the commit lands, subsequent runs cannot\",\n      \"reconstruct the rewrite context.\",\n      \"\",\n      \"Sequence:\",\n      \"\",\n      \"1. Read the `req:deprecate` issue and verify required inputs.\",\n      \"2. Verify every successor document referenced in `Superseded-by`\",\n      \"   exists on disk.\",\n      \"3. Pause for human confirmation (unless `Pre-approved: yes` is in\",\n      \"   the body).\",\n      \"4. Apply the six narrow edits to each target document.\",\n      \"5. Update the category index row(s).\",\n      \"6. Commit the deprecation changes.\",\n      \"7. Run the back-reference sweep.\",\n      \"8. File one `req:write` follow-up per referencing requirement\",\n      \"   document.\",\n      \"9. Comment on the `req:deprecate` issue with the summary.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Working Rules\",\n      \"\",\n      \"- **One phase per session.** In `req:review`, stop after the report\",\n      \"  is written, follow-up issues are filed, and the summary comment is\",\n      \"  posted. In `req:deprecate`, stop after the edits commit, the\",\n      \"  back-reference sweep runs, follow-ups are filed, and the summary\",\n      \"  comment is posted.\",\n      \"- **Audit-only in `req:review`.** Never edit requirement documents,\",\n      \"  category indexes, or templates from the review phase. Findings flow\",\n      \"  through follow-up issues.\",\n      \"- **Narrow-write in `req:deprecate`.** Only the six edits listed in\",\n      \"  the Deprecation Phase section are allowed. Every other edit flows\",\n      \"  through `req:write` follow-ups.\",\n      \"- **Deprecation requires human confirmation.** Never self-approve a\",\n      \"  status transition. Either pause on the issue and wait for an\",\n      \"  explicit reply, or verify that the body carries\",\n      \"  `Pre-approved: yes` before editing.\",\n      \"- **Resolve, do not eyeball.** Cross-reference findings and\",\n      \"  back-reference sweeps only count when the target path is verified\",\n      \"  on disk.\",\n      \"- **Cite every finding.** Every entry in the review report must cite\",\n      \"  the file path and the numbered check that produced it. Every\",\n      \"  deprecation follow-up must cite the referencing document path and\",\n      \"  the line(s) that mention the deprecated ID.\",\n      \"- **Do not invent traceability rules.** Use the defaults documented\",\n      `  above unless the project's \\`${paths.docsRoot}/project-context.md\\` declares a`,\n      \"  different traceability shape.\",\n      \"- **Audits >10 documents must use a verification script.** Manual\",\n      \"  review of large sets always misses broken links.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off a requirements-review session. */\nfunction buildReviewRequirementsSkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"review-requirements\",\n    description:\n      \"Audit existing requirement documents (BR / FR / NFR / TR / ADR / SEC / DR / INT / OPS / UX / MT) for structural compliance, categorization, traceability, cross-reference integrity, sequence integrity, content quality, registry sync, decision-authority compliance, tier classification, cross-referencing conventions, and stale `Proposed` ADR/TR decisions. Supports four scopes (full audit, category, single document, targeted check) and dispatches the requirements-reviewer agent. Audits documents — never writes them. Soft dependency: expects requirement templates at `\" +\n      REQUIREMENTS_WRITER_PATHS.templatesRoot +\n      \"`, shipped by the requirements-writer bundle.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"requirements-reviewer\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Review Requirements\",\n      \"\",\n      \"Audit existing requirement documents for structural compliance,\",\n      \"traceability, categorization, and content quality. Dispatches the\",\n      \"`requirements-reviewer` agent.\",\n      \"\",\n      \"## Soft Dependency\",\n      \"\",\n      \"This skill reads requirement category templates from\",\n      `\\`${REQUIREMENTS_WRITER_PATHS.templatesRoot}\\`,`,\n      \"which is shipped by the `requirements-writer` bundle. If your\",\n      \"project does not use the `requirements-writer` bundle, supply\",\n      \"equivalent templates at the same path before running a review.\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/review-requirements <scope>\",\n      \"\",\n      \"Where `<scope>` is one of:\",\n      \"\",\n      \"- `full` — audit every requirement document under\",\n      \"  `<REQUIREMENTS_ROOT>` across all categories\",\n      \"- `category:<slug>` — audit one category directory (e.g.,\",\n      \"  `category:functional` audits every FR)\",\n      \"- `doc:<path>` — audit one specific requirement file\",\n      \"- `check:<n>[,<n>...]` — run one or more checks (1–12) across the\",\n      \"  documents in scope (e.g., `check:4` runs cross-reference\",\n      \"  integrity only, `check:12` runs the stale-proposed-decision\",\n      \"  audit only)\",\n      \"\",\n      \"Optional extensions in the issue body:\",\n      \"\",\n      \"- `output: <path>` — override the default report path\",\n      \"- `requirements-root: <path>` — override `<REQUIREMENTS_ROOT>`\",\n      \"- `targets: <glob>` — restrict the document set with a glob\",\n      \"  pattern relative to `<REQUIREMENTS_ROOT>`\",\n      \"- `stale-proposed-threshold-days: <n>` — override the default\",\n      \"  14-day threshold used by Check 12 (stale `Proposed` ADR/TR\",\n      \"  decisions) for this review\",\n      \"\",\n      \"## Default Paths\",\n      \"\",\n      `If the project has no override in \\`${paths.docsRoot}/project-context.md\\` or`,\n      \"`agentConfig.rules`, outputs land under:\",\n      \"\",\n      `- \\`${paths.researchRoot}/reviews/review-<scope>-YYYY-MM-DD.md\\` — the`,\n      \"  review report\",\n      `- \\`${paths.researchRoot}/reviews/review-<scope>-YYYY-MM-DD-verify.py\\` —`,\n      \"  the Python verification script (only for audits >10 documents)\",\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `req:review` issue with `type:requirement`,\",\n      `   \\`priority:${labelsForPhase(issueDefaults, \"req:review\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"req:review\").status}\\`. Body must include the`,\n      \"   scope, the requirements root (or accept the default), and the\",\n      \"   output path.\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute the review phase of the requirements-reviewer agent.\",\n      \"3. The agent runs the 12-check audit, writes a structured report\",\n      \"   grouped by Critical / Warning / Info (plus a separate\",\n      \"   **Stale decisions** section when Check 12 surfaces stale\",\n      \"   `Proposed` ADR/TR documents), files follow-up issues for\",\n      \"   actionable findings, and comments on the `req:review` issue\",\n      \"   with the summary.\",\n      \"\",\n      \"## Audits >10 Documents\",\n      \"\",\n      \"For audits covering more than 10 documents, the agent writes a\",\n      \"Python verification script alongside the report and uses its\",\n      \"output as the basis for the audit. The script is read-only and\",\n      \"idempotent — it can be re-run after fixes land to confirm\",\n      \"remediation. The script is generated per-audit; it is not shipped\",\n      \"as a static asset.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- One review report under `<REVIEW_REPORTS_ROOT>` grouped by\",\n      \"  Critical / Warning / Info severity\",\n      \"- One verification script under `<REVIEW_REPORTS_ROOT>` (only\",\n      \"  for audits >10 documents)\",\n      \"- Follow-up GitHub issues for every Critical and Warning finding,\",\n      \"  carrying the appropriate phase label (`req:write`,\",\n      \"  `req:draft-trace`, or `req:scan`) for the downstream agent that\",\n      \"  should act\",\n      \"- An aggregated `req:review` follow-up issue labeled\",\n      \"  `status:needs-attention` when Check 12 surfaces stale `Proposed`\",\n      \"  ADR/TR documents (one issue per review, not one per document);\",\n      \"  the review report also includes a dedicated **Stale decisions**\",\n      \"  section in that case\",\n      \"- A summary comment on the originating `req:review` issue\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off a deprecation session. */\nfunction buildDeprecateRequirementSkill(\n  _paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"deprecate-requirement\",\n    description:\n      \"Transition one or more requirement documents to `Deprecated` or `Superseded`. Creates a `req:deprecate` issue and dispatches the requirements-reviewer agent's deprecation phase, which edits the target document's Status, Revision History, Superseded-by traceability link, and category index row, then files `req:write` follow-ups for every back-reference so the requirements-writer can rewrite them. The deprecation phase pauses for explicit human confirmation before editing (unless the issue body pre-approves the change).\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"requirements-reviewer\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Deprecate Requirement\",\n      \"\",\n      \"Transition one or more requirement documents to `Deprecated` or\",\n      \"`Superseded`. Creates a `req:deprecate` issue and dispatches the\",\n      \"`requirements-reviewer` agent's deprecation phase. The agent pauses\",\n      \"for explicit human confirmation before writing any status change.\",\n      \"\",\n      \"## When to use\",\n      \"\",\n      \"- An ADR is superseded by a newer decision and the old decision\",\n      \"  should no longer be referenced.\",\n      \"- A functional requirement has been removed from the roadmap and\",\n      \"  should carry `Status: Deprecated` so downstream documents stop\",\n      \"  linking to it as if it were active.\",\n      \"- A reviewer run (via `/review-requirements`) surfaced a stale\",\n      \"  `Accepted` status that should transition to `Deprecated` or\",\n      \"  `Superseded`.\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/deprecate-requirement <target> [--superseded-by <path>]\",\n      \"\",\n      \"Where `<target>` is either a requirement ID (e.g. `ADR-007`) or a\",\n      \"path relative to `<REQUIREMENTS_ROOT>` (e.g.\",\n      \"`architecture/ADR-007-auth-provider.md`). Pass\",\n      \"`--superseded-by <path>` to record a replacement document; omit it\",\n      \"for a plain deprecation with no successor.\",\n      \"\",\n      \"Multiple targets may be passed by repeating the skill invocation or\",\n      \"by editing the issue body before the agent runs.\",\n      \"\",\n      \"## Required issue body fields\",\n      \"\",\n      \"The `req:deprecate` issue body must include:\",\n      \"\",\n      \"- **Targets** — the requirement IDs or paths to deprecate\",\n      \"- **Transition** — `Deprecated` or `Superseded-by: <path>` per\",\n      \"  target (when `Superseded-by` is given, the replacement document\",\n      \"  must already exist on disk)\",\n      \"- **Reason** — a one-paragraph rationale that becomes the\",\n      \"  Deprecation reason recorded on the target document\",\n      \"- **Pre-approved: yes** *(optional)* — include this line to skip\",\n      \"  the interactive human-confirmation pause. Omit it to force the\",\n      \"  agent to comment on the issue and wait for an affirmative\",\n      \"  reply before editing.\",\n      \"\",\n      \"Issues that are missing any of the first three fields are flagged\",\n      \"`status:needs-attention` and the agent stops without editing\",\n      \"anything.\",\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `req:deprecate` issue with `type:requirement`,\",\n      `   \\`priority:${labelsForPhase(issueDefaults, \"req:deprecate\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"req:deprecate\").status}\\`. Body must include the`,\n      \"   Targets, Transition, and Reason sections above (optionally\",\n      \"   `Pre-approved: yes`).\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute the deprecation phase of the requirements-reviewer\",\n      \"   agent.\",\n      \"3. The agent verifies inputs, pauses for human confirmation (or\",\n      \"   skips the pause when `Pre-approved: yes` is set), edits each\",\n      \"   target document's `Status`, Revision History, Superseded-by,\",\n      \"   and Deprecation reason, updates the matching category index\",\n      \"   row, commits the changes, sweeps `<REQUIREMENTS_ROOT>` for\",\n      \"   inbound references, files one `req:write` follow-up per\",\n      \"   referencing document, and comments on the `req:deprecate`\",\n      \"   issue with the summary.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- Narrow edits to each target requirement document (Status,\",\n      \"  Metadata row, Revision History, Traceability Superseded-by,\",\n      \"  Deprecation reason)\",\n      \"- Updated category index row(s)\",\n      \"- One `req:write` follow-up issue per requirement document that\",\n      \"  still references the deprecated target, so the\",\n      \"  `requirements-writer` can rewrite those references\",\n      \"- A summary comment on the originating `req:deprecate` issue\",\n      \"\",\n      \"## What this skill does NOT do\",\n      \"\",\n      \"- It does not delete files. Deprecated documents stay on disk with\",\n      \"  updated status so readers following old links can follow the\",\n      \"  trail forward.\",\n      \"- It does not rewrite the body of the target document beyond the\",\n      \"  narrow fields listed above. Description, acceptance criteria,\",\n      \"  open items, and other sections are left unchanged. If the\",\n      \"  deprecation implies a rewrite of other sections, the issue\",\n      \"  author should open a separate `req:write` issue for the writer.\",\n      \"- It does not rewrite references in the referencing documents.\",\n      \"  That work is handed off to the `requirements-writer` through\",\n      \"  the `req:write` follow-ups.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/**\n * Requirements reviewer bundle — enabled by default for projects that\n * adopt this batch.\n *\n * Consuming projects can disable it with\n * `excludeBundles: [\"requirements-reviewer\"]`. `appliesWhen` always\n * returns `true` per this batch's directive that bundles assume peers\n * are present.\n *\n * Ships a single consolidated sub-agent (`requirements-reviewer`) that\n * runs in one of two phases per session — `req:review` (the 11-check\n * audit) or `req:deprecate` (narrow-write deprecation with back-\n * reference sweep). Two user-invocable skills dispatch the two phases:\n * `/review-requirements` and `/deprecate-requirement`. Labels declared\n * here are `req:review` and `req:deprecate`.\n *\n * **Soft dependency on the `requirements-writer` bundle.** This bundle\n * does **not** ship its own copy of the requirement category\n * templates. The reviewer reads them from the path the\n * `requirements-writer` bundle ships\n * (`REQUIREMENTS_WRITER_PATHS.templatesRoot`). If a consuming project\n * disables the writer bundle but enables this one, the project must\n * supply equivalent templates at the same path.\n *\n * `type:requirement` is intentionally **not** declared here — it is\n * already declared by the `requirements-analyst` bundle and reused.\n * `type:review` is intentionally **not** declared either; review and\n * deprecate issues both use `type:requirement` plus the matching\n * phase label so they share the same queue and triage flow as the\n * rest of the requirements pipeline.\n */\nexport function buildRequirementsReviewerBundle(\n  paths: ResolvedAgentPaths = DEFAULT_AGENT_PATHS,\n  issueDefaults: ResolvedIssueDefaults = DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n): AgentRuleBundle {\n  return {\n    name: \"requirements-reviewer\",\n    description:\n      \"Requirements reviewer agent bundle. Audits existing requirement documents (BR, FR, NFR, TR, ADR, SEC, DR, INT, OPS, UX, MT) via the 12-check review phase (including Check 12: stale `Proposed` ADR/TR decisions), and transitions requirements to `Deprecated` or `Superseded` via the deprecation phase (narrow writes to Status, Revision History, Superseded-by, and category index row, with `req:write` follow-ups for every back-reference). Reads templates from the requirements-writer bundle's reference directory; ships no templates of its own.\",\n    appliesWhen: () => true,\n    rules: [\n      {\n        name: \"requirements-reviewer-workflow\",\n        description:\n          \"Describes the requirements-reviewer pipeline, the req:review and req:deprecate phase labels, the four review scopes, the deprecation-phase contract, the soft dependency on the requirements-writer bundle's templates, and the boundary with the writer and analyst bundles.\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Requirements Reviewer Workflow\",\n          \"\",\n          \"The requirements-reviewer agent runs in one of two phases per\",\n          \"session, each tracked by its own GitHub issue label. Issues in\",\n          \"both phases also carry `type:requirement` (declared by the\",\n          \"upstream `requirements-analyst` bundle).\",\n          \"\",\n          \"| Phase | Skill | Label | Writes requirement docs? |\",\n          \"|-------|-------|-------|--------------------------|\",\n          \"| Review | `/review-requirements <scope>` | `req:review` | No — audit only |\",\n          \"| Deprecate | `/deprecate-requirement <target>` | `req:deprecate` | Narrow writes (Status, Revision History, Superseded-by, index row) |\",\n          \"\",\n          \"## Review phase\",\n          \"\",\n          \"Use `/review-requirements <scope>` to audit existing requirement\",\n          \"documents. Four scopes are supported: `full` (every document),\",\n          \"`category:<slug>` (one category directory), `doc:<path>` (one\",\n          \"specific document), and `check:<n>` (one or more of the 12\",\n          \"checks across the documents in scope).\",\n          \"\",\n          \"Check 12 flags ADR and TR documents that have carried\",\n          \"`Status: Proposed` longer than\",\n          \"`<STALE_PROPOSED_THRESHOLD_DAYS>` days (default 14, configurable\",\n          `via the \\`req:review\\` issue body, \\`${paths.docsRoot}/project-context.md\\`, or`,\n          \"`agentConfig.rules`). Stale decisions are reported in a separate\",\n          \"**Stale decisions** section of the review report and trigger one\",\n          \"aggregated `req:review` follow-up issue labeled\",\n          \"`status:needs-attention` so a human can triage the backlog. The\",\n          \"reviewer never auto-transitions status — acceptance and\",\n          \"deprecation both remain human decisions.\",\n          \"\",\n          \"The review phase produces **review reports and follow-up issues\",\n          \"only** — it never edits requirement documents, capability\",\n          \"models, or research notes. It files follow-up issues with the\",\n          \"appropriate phase label (`req:write`, `req:draft-trace`,\",\n          \"`req:scan`, or — only for Check 12 stale-decision triage —\",\n          \"`req:review`) for the downstream agent or human to pick up.\",\n          \"\",\n          \"For audits covering more than 10 documents, the reviewer writes\",\n          \"a read-only Python verification script alongside the report and\",\n          \"uses its output as the basis for findings — manual review of\",\n          \"large document sets always misses broken links.\",\n          \"\",\n          \"## Deprecation phase\",\n          \"\",\n          \"Use `/deprecate-requirement <target> [--superseded-by <path>]`\",\n          \"to transition one or more requirement documents to `Deprecated`\",\n          \"or `Superseded`. The deprecation phase is the only path by\",\n          \"which this agent mutates requirement documents, and it is\",\n          \"narrowly scoped to:\",\n          \"\",\n          \"- The frontmatter `Status` field and the Metadata table\",\n          \"  `Status` row\",\n          \"- A new entry in the target document's `## Revision History`\",\n          \"- A `Superseded-by` line in the target's `## Traceability`\",\n          \"  section (when applicable) plus a Deprecation reason line\",\n          \"- The matching row in the category `README.md` / `index.md`\",\n          \"\",\n          \"The agent pauses for explicit human confirmation on the\",\n          \"`req:deprecate` issue before editing — deprecation is\",\n          \"irreversible in practice. Issue authors can skip the pause by\",\n          \"adding `Pre-approved: yes` to the issue body. After the edits\",\n          \"commit, the agent sweeps `<REQUIREMENTS_ROOT>` for inbound\",\n          \"references and files one `req:write` follow-up per referencing\",\n          \"requirement document so the `requirements-writer` can rewrite\",\n          \"those references. Documents are never deleted; the deprecated\",\n          \"file stays on disk with updated status.\",\n          \"\",\n          \"The deprecation phase never authors new requirement documents,\",\n          \"never rewrites the body of a target document beyond the narrow\",\n          \"fields listed above, and never rewrites references in the\",\n          \"referencing documents — that work is handed off to the\",\n          \"`requirements-writer`.\",\n          \"\",\n          \"## Cross-bundle boundaries\",\n          \"\",\n          \"Authoring remains the responsibility of the `requirements-writer`\",\n          \"(requirement docs) and `bcm-writer` (capability models) bundles.\",\n          \"Gap discovery is the responsibility of the `requirements-analyst`\",\n          \"bundle. The reviewer never opens `req:scan`, `req:draft-trace`,\",\n          \"`req:review`, or `bcm:*` issues — only `req:write` follow-ups\",\n          \"from either phase.\",\n          \"\",\n          \"**Soft dependency on the `requirements-writer` bundle.** The\",\n          \"reviewer reads category templates from\",\n          `\\`${REQUIREMENTS_WRITER_PATHS.templatesRoot}\\`,`,\n          \"which is shipped by the `requirements-writer` bundle. Projects\",\n          \"that disable the writer bundle but keep the reviewer must\",\n          \"supply equivalent templates at the same path.\",\n          \"\",\n          \"See the `requirements-reviewer` agent definition for full\",\n          \"workflow details, configurable paths, the 11-check catalog, the\",\n          \"severity ladder, the deprecation-phase edit contract, and the\",\n          \"back-reference sweep rules.\",\n        ].join(\"\\n\"),\n        platforms: {\n          cursor: { exclude: true },\n        },\n        tags: [\"workflow\"],\n      },\n    ],\n    skills: [\n      buildReviewRequirementsSkill(paths, issueDefaults),\n      buildDeprecateRequirementSkill(paths, issueDefaults),\n    ],\n    subAgents: [buildRequirementsReviewerSubAgent(paths, issueDefaults)],\n    labels: [\n      {\n        name: \"req:review\",\n        color: \"FBCA04\",\n        description:\n          \"Phase: audit existing requirement documents using the requirements-reviewer skill\",\n      },\n      {\n        name: \"req:deprecate\",\n        color: \"D93F0B\",\n        description:\n          \"Phase: transition requirement docs to Deprecated/Superseded via the requirements-reviewer\",\n      },\n    ],\n  };\n}\n\n/**\n * Default-paths instance of the requirements-reviewer bundle, preserved\n * for backward compatibility with consumers that import the const\n * directly. The factory above is the canonical entry point when a\n * consumer supplies `AgentConfigOptions.paths`.\n */\nexport const requirementsReviewerBundle: AgentRuleBundle =\n  buildRequirementsReviewerBundle();\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { renderClaimVerificationSection } from \"./claim-verification\";\nimport {\n  ISSUE_CLOSE_RULE_REFERENCE,\n  ISSUE_CLOSE_SECTION_TITLE,\n  renderIssueClosePolicySection,\n} from \"./issue-close\";\nimport {\n  DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n  ResolvedIssueDefaults,\n  labelsForPhase,\n} from \"./issue-defaults\";\nimport { renderIssueTypeAssignmentStep } from \"./issue-type\";\nimport { renderOriginStampSection } from \"./origin-label\";\nimport { DEFAULT_AGENT_PATHS, ResolvedAgentPaths } from \"./paths\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n  AGENT_MODEL,\n  AGENT_RULE_SCOPE,\n  AgentSkill,\n  AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that runs a generic research micro-task pipeline. Breaks a\n * research question into scope → slice search/synthesize → verify\n * phases, persists intermediate artifacts to disk, and sequences\n * dependent phases via a GitHub issue graph.\n *\n * The prompt deliberately avoids hardcoded domains, companies, or\n * source projects. Consumers configure scope, output paths, slice\n * counts, and verification rules through the skill invocation and by\n * extending the rule in their own `agentConfig.rules`.\n */\nfunction buildResearchAnalystSubAgent(\n  paths: ResolvedAgentPaths,\n): AgentSubAgent {\n  return {\n    name: \"research-analyst\",\n    description:\n      \"Runs a generic research micro-task pipeline (scope, slice search/synthesize, verify). One phase per session, tracked by research:* GitHub issue labels with filesystem-based durability between phases.\",\n    model: AGENT_MODEL.POWERFUL,\n    maxTurns: 80,\n    platforms: { cursor: { exclude: true } },\n    prompt: [\n      \"# Research Analyst Agent\",\n      \"\",\n      \"Generic research micro-task pipeline. Given a research question, you\",\n      \"break it into a scope, a fixed number of focused search/synthesize\",\n      \"slices, and a verification pass that reconciles the slice outputs into\",\n      \"a single deliverable. Each phase runs as its **own agent session**,\",\n      \"triggered by a GitHub issue with a `research:*` phase label. You\",\n      \"handle exactly **one phase per session** — read the issue to determine\",\n      \"which phase to execute.\",\n      \"\",\n      \"This agent is **domain-neutral**. It makes no assumptions about what\",\n      \"is being researched (companies, products, people, markets, technical\",\n      \"topics, academic literature, etc.). All domain-specific vocabulary,\",\n      \"output locations, and acceptance criteria come from the invoking\",\n      \"issue body or the consuming project's configuration.\",\n      \"\",\n      \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n      \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...PROJECT_CONTEXT_READER_SECTION,\n      \"## Design Principles\",\n      \"\",\n      \"1. **Micro-tasks, not mega-prompts.** Split work into small slices so\",\n      \"   each session has a bounded context window and a single deliverable.\",\n      \"2. **Filesystem durability.** Every phase persists its output to a\",\n      \"   file on disk before closing its issue. Downstream phases read those\",\n      \"   files — never rely on session memory.\",\n      \"3. **Issue graph = state machine.** Phase ordering is encoded with\",\n      \"   `Depends on: #N` links between phase issues. A phase runs only\",\n      \"   after its predecessor is closed.\",\n      \"4. **Generic over specific.** No hardcoded domains, companies, source\",\n      \"   projects, or proprietary taxonomies. Use placeholders that the\",\n      \"   skill invocation or consuming project fills in.\",\n      \"5. **Verifiable synthesis.** The verify phase re-reads every slice\",\n      \"   output and produces a single deliverable whose claims can each be\",\n      \"   traced back to a slice.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## State Machine Overview\",\n      \"\",\n      \"```\",\n      \"┌──────────────┐     ┌─────────────────────┐     ┌──────────────┐\",\n      \"│  1. SCOPE    │────▶│  2. SLICE (×N)      │────▶│  3. VERIFY   │\",\n      \"│  Turn the    │     │  For each slice:    │     │  Read every  │\",\n      \"│  question    │     │  search sources,    │     │  slice       │\",\n      \"│  into N      │     │  synthesize a       │     │  output,     │\",\n      \"│  focused     │     │  bounded note file  │     │  reconcile,  │\",\n      \"│  slices      │     │                     │     │  deliverable │\",\n      \"└──────────────┘     └─────────────────────┘     └──────────────┘\",\n      \"```\",\n      \"\",\n      \"**Issue labels encode the phase:**\",\n      \"\",\n      \"| Label | Phase | Session work |\",\n      \"|-------|-------|-------------|\",\n      \"| `research:scope` | 1. Scope | Decompose the research question into N focused slices. Write a scope file. Create N `research:slice` issues. |\",\n      \"| `research:slice` | 2. Slice | Execute one slice: search authorized sources, synthesize, write a single slice note file. |\",\n      \"| `research:verify` | 3. Verify | Read every slice note, reconcile findings, produce the final deliverable and a verification report. |\",\n      \"\",\n      \"All issues also carry `type:research` and a `status:*` label.\",\n      \"\",\n      \"**Issue count per research cycle:** 1 scope + N slice + 1 verify =\",\n      \"**N + 2 sessions**. Typical N is 3–6.\",\n      \"\",\n      \"**Shortened paths:**\",\n      \"- Scope phase determines the question is unanswerable or out of scope\",\n      \"  → scope issue closes with a justification and no downstream issues\",\n      \"  are created → **1 session**.\",\n      \"- Single-slice research (N = 1) → **3 sessions**. Never skip verify,\",\n      \"  even with one slice — verify is where the deliverable lands.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Configurable Paths\",\n      \"\",\n      \"The pipeline uses these placeholders. Consuming projects override the\",\n      \"defaults by passing paths in the `/research` skill invocation or by\",\n      \"extending this rule in their own `agentConfig.rules`.\",\n      \"\",\n      \"| Placeholder | Meaning | Default |\",\n      \"|-------------|---------|---------|\",\n      `| \\`<RESEARCH_ROOT>\\` | Root folder for all research outputs | \\`${paths.researchRoot}/\\` |`,\n      \"| `<SCOPE_DIR>` | Scope files | `<RESEARCH_ROOT>/scopes/` |\",\n      \"| `<SLICES_DIR>` | Slice note files | `<RESEARCH_ROOT>/slices/` |\",\n      \"| `<DELIVERABLES_DIR>` | Final verified deliverables | `<RESEARCH_ROOT>/deliverables/` |\",\n      \"| `<RESEARCH_SLUG>` | Short kebab-case slug identifying one research cycle | derived from the question |\",\n      \"| `<N>` | Number of slices (default 4, max 8) | `4` |\",\n      \"\",\n      `If \\`${paths.docsRoot}/project-context.md\\` specifies a different research tree,`,\n      \"prefer that. Otherwise fall back to the defaults above.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Agent Loop\",\n      \"\",\n      \"Run this loop exactly once per session. Never start a second issue.\",\n      \"\",\n      \"1. Claim one open `type:research` issue using phase priority:\",\n      \"   `research:scope` > `research:slice` > `research:verify`.\",\n      \"2. Transition `status:ready` → `status:in-progress` and create the\",\n      \"   branch per your project's branch-naming convention.\",\n      \"3. Execute the phase handler that matches the issue's `research:*`\",\n      \"   label.\",\n      \"4. Commit, push, open a PR (if applicable), and close the issue per\",\n      `   your project's PR workflow — see the **${ISSUE_CLOSE_SECTION_TITLE}**`,\n      \"   section below before you close anything yourself.\",\n      \"   Stamp every PR you open with the `origin:agent` label — see the\",\n      \"   **Origin label** section below.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...renderClaimVerificationSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderOriginStampSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderIssueClosePolicySection(),\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 1: Scope (`research:scope`)\",\n      \"\",\n      \"**Goal:** Turn a natural-language research question into a bounded\",\n      \"scope file and `N` focused slice issues.\",\n      \"\",\n      \"**Budget:** No web searches in this phase. Read the question, the\",\n      \"project context, and any cited source material already on disk. Write\",\n      \"one scope file. Create N slice issues.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the research question** from the issue body. The body should\",\n      \"   include:\",\n      \"   - The question itself\",\n      \"   - Authorized source categories (e.g. public web, vendor docs, a\",\n      \"     cited local file path) — if absent, default to public web only\",\n      \"   - Output acceptance criteria for the final deliverable\",\n      \"   - Optional: `<N>` override, `<RESEARCH_SLUG>` override, custom\",\n      \"     output paths\",\n      \"\",\n      \"2. **Derive `<RESEARCH_SLUG>`** if not supplied — a 3–5 word kebab-case\",\n      \"   summary of the question. Ensure the slug is not already in use\",\n      \"   under `<SCOPE_DIR>/`.\",\n      \"\",\n      \"3. **Decompose the question into N slices.** Each slice must:\",\n      \"   - Be answerable independently of the others\",\n      \"   - Fit inside a single agent session's context budget\",\n      \"   - Have a clearly scoped set of sources to consult\",\n      \"   - Produce a bounded note file (target: under 1500 words)\",\n      \"\",\n      \"4. **Write the scope file** to\",\n      \"   `<SCOPE_DIR>/<RESEARCH_SLUG>.scope.md`:\",\n      \"\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"Research Scope: <question>\"',\n      \"   slug: <RESEARCH_SLUG>\",\n      \"   date: YYYY-MM-DD\",\n      \"   parent_issue: <N>\",\n      \"   slice_count: <N>\",\n      \"   ---\",\n      \"\",\n      \"   ## Question\",\n      \"   <verbatim question from the issue>\",\n      \"\",\n      \"   ## Authorized Sources\",\n      \"   - <source category or path>\",\n      \"\",\n      \"   ## Acceptance Criteria\",\n      \"   - [ ] <criterion for the final deliverable>\",\n      \"\",\n      \"   ## Slices\",\n      \"   ### Slice 1: <title>\",\n      \"   - **Focus:** <what this slice answers>\",\n      \"   - **Sources:** <the subset of authorized sources this slice uses>\",\n      \"   - **Output:** <SLICES_DIR>/<RESEARCH_SLUG>-01-<slug>.slice.md\",\n      \"\",\n      \"   ### Slice 2: <title>\",\n      \"   ...\",\n      \"\",\n      \"   ## Out of Scope\",\n      \"   <sub-questions deliberately excluded from this cycle>\",\n      \"\",\n      \"   ## Deliverable\",\n      \"   <DELIVERABLES_DIR>/<RESEARCH_SLUG>.md\",\n      \"   ```\",\n      \"\",\n      \"5. **Create N `research:slice` issues**, one per slice, each with\",\n      \"   `Depends on: #<scope-issue>`. Each slice issue body references the\",\n      \"   scope file and names the exact slice (by number and title).\",\n      \"\",\n      \"6. **Create one `research:verify` issue** that depends on all N slice\",\n      \"   issues. Its body references the scope file and lists every slice\",\n      \"   output path that verify must read.\",\n      \"\",\n      \"7. **Commit and push** the scope file. Close the scope issue\",\n      `   ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 2: Slice (`research:slice`)\",\n      \"\",\n      \"**Goal:** Answer one slice by searching the authorized sources and\",\n      \"writing a single slice note file.\",\n      \"\",\n      \"**Budget:** Search budget is one slice — do not expand scope. Write\",\n      \"one slice note. Do not create downstream issues.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the scope file** referenced in the issue body.\",\n      \"\",\n      \"2. **Identify your slice** by number and title. Re-read the slice's\",\n      \"   focus, sources, and output path.\",\n      \"\",\n      \"3. **Search the authorized sources.** Stay within the source list for\",\n      \"   your slice — do not broaden to the full scope's source list unless\",\n      \"   the slice explicitly permits it.\",\n      \"\",\n      \"4. **Synthesize a slice note** and write it to the slice's output\",\n      \"   path (e.g. `<SLICES_DIR>/<RESEARCH_SLUG>-NN-<slug>.slice.md`):\",\n      \"\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"Slice NN: <title>\"',\n      \"   slug: <RESEARCH_SLUG>\",\n      \"   slice: NN\",\n      \"   date: YYYY-MM-DD\",\n      \"   parent_scope: <SCOPE_DIR>/<RESEARCH_SLUG>.scope.md\",\n      \"   parent_issue: <N>\",\n      \"   ---\",\n      \"\",\n      \"   ## Question\",\n      \"   <the slice-level question>\",\n      \"\",\n      \"   ## Key Findings\",\n      \"   - <finding> — source: <citation>\",\n      \"\",\n      \"   ## Evidence\",\n      \"   <short quotations, paraphrases, or structured data with citations>\",\n      \"\",\n      \"   ## Gaps / Open Questions\",\n      \"   <anything the slice could not answer inside its budget>\",\n      \"\",\n      \"   ## Sources\",\n      \"   - <source URL or file path> — <date accessed>\",\n      \"   ```\",\n      \"\",\n      \"5. **Stay within the word budget** (default 1500 words). If the slice\",\n      \"   cannot fit, add an `## Overflow` section at the end noting what was\",\n      \"   cut and flag it for the verify phase — do not expand into other\",\n      \"   slices' territory.\",\n      \"\",\n      \"6. **Commit and push** the slice note. Close the slice issue\",\n      `   ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 3: Verify (`research:verify`)\",\n      \"\",\n      \"**Goal:** Reconcile every slice into a single verified deliverable.\",\n      \"\",\n      \"**Budget:** No new web searches. Read the scope, read every slice\",\n      \"note, reconcile contradictions, write the deliverable and a short\",\n      \"verification report.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the scope file** and every slice note listed in the issue\",\n      \"   body. If any slice file is missing, stop and re-open the\",\n      \"   corresponding slice issue with `status:needs-attention`.\",\n      \"\",\n      \"2. **Build a claim index.** For every assertion in any slice, note\",\n      \"   which slice(s) support it and which sources back it.\",\n      \"\",\n      \"3. **Reconcile contradictions.** When slices disagree:\",\n      \"   - Prefer the slice with stronger sources\",\n      \"   - Flag unresolved contradictions in the verification report\",\n      \"   - Do not silently pick a side\",\n      \"\",\n      \"4. **Write the deliverable** to\",\n      \"   `<DELIVERABLES_DIR>/<RESEARCH_SLUG>.md`. The structure is dictated\",\n      \"   by the acceptance criteria in the scope file. Every factual claim\",\n      \"   in the deliverable must cite at least one slice note.\",\n      \"\",\n      \"5. **Write a verification report** to\",\n      \"   `<DELIVERABLES_DIR>/<RESEARCH_SLUG>.verify.md`:\",\n      \"\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"Verification Report: <question>\"',\n      \"   slug: <RESEARCH_SLUG>\",\n      \"   date: YYYY-MM-DD\",\n      \"   parent_issue: <N>\",\n      \"   slices_read: <count>\",\n      \"   ---\",\n      \"\",\n      \"   ## Acceptance Criteria Coverage\",\n      \"   - [x] <criterion> — covered by slice(s) <NN, NN>\",\n      \"   - [ ] <criterion> — **not covered**; gap noted in deliverable\",\n      \"\",\n      \"   ## Slice Coverage\",\n      \"   | Slice | Claims | Reused in deliverable | Notes |\",\n      \"   |-------|--------|-----------------------|-------|\",\n      \"   | 01 | <count> | <count> | |\",\n      \"\",\n      \"   ## Reconciled Contradictions\",\n      \"   - <short summary of each reconciled contradiction and why>\",\n      \"\",\n      \"   ## Unresolved Contradictions\",\n      \"   - <contradiction the verifier could not resolve>\",\n      \"\",\n      \"   ## Gaps\",\n      \"   - <question the pipeline could not answer>\",\n      \"   ```\",\n      \"\",\n      \"6. **Comment on the scope issue** with a summary linking to the\",\n      \"   deliverable and verification report.\",\n      \"\",\n      \"7. **Commit and push.** Close the verify issue\",\n      `   ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Output Boundaries\",\n      \"\",\n      \"This agent writes **only** to:\",\n      \"\",\n      \"- `<SCOPE_DIR>/` — scope files (Phase 1)\",\n      \"- `<SLICES_DIR>/` — slice notes (Phase 2)\",\n      \"- `<DELIVERABLES_DIR>/` — deliverables and verification reports\",\n      \"  (Phase 3)\",\n      \"\",\n      \"The pipeline produces **notes and deliverables only**. It does not\",\n      \"open downstream `type:requirement`, profile, or comparison issues —\",\n      \"those are the responsibility of specialized downstream agents (e.g.\",\n      \"`requirements-analyst`, `meeting-analyst`) that consume the\",\n      \"deliverables produced here. Keep this boundary clean so the research\",\n      \"pipeline stays generic.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Rules\",\n      \"\",\n      \"- **One phase per session.** Never run two phases back-to-back in a\",\n      \"  single session.\",\n      \"- **Persist before closing.** Every phase must write its output file\",\n      \"  before closing its issue.\",\n      \"- **Do not expand scope mid-slice.** Overflow goes into the slice's\",\n      \"  overflow section and is flagged for verify — not into another\",\n      \"  slice's territory.\",\n      \"- **Cite everything.** Claims without a source citation do not belong\",\n      \"  in a slice note or deliverable.\",\n      \"- **Produce notes, not downstream work.** Do not create\",\n      \"  `type:requirement`, profile, or comparison issues from this\",\n      \"  pipeline. Emit deliverables under `<DELIVERABLES_DIR>/` and let\",\n      \"  downstream agents decide what to do with them.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off a research pipeline cycle. */\nfunction buildResearchSkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"research\",\n    description:\n      \"Kick off a generic research micro-task pipeline. Creates a research:scope issue and dispatches Phase 1 (Scope) in the research-analyst agent.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"research-analyst\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Research\",\n      \"\",\n      \"Kick off a generic research micro-task pipeline. Creates a\",\n      \"`research:scope` issue carrying the research question and dispatches\",\n      \"Phase 1 (Scope) in the research-analyst agent.\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/research <question>\",\n      \"\",\n      \"Optional extensions in the question body:\",\n      \"- `sources: <list>` — authorized source categories or file paths\",\n      \"- `slices: <N>` — override the default slice count (default 4, max 8)\",\n      \"- `slug: <kebab-case>` — override the derived research slug\",\n      \"- `acceptance: <list>` — explicit acceptance criteria for the\",\n      \"  deliverable\",\n      \"\",\n      \"## Default Paths\",\n      \"\",\n      `If the project has no override in \\`${paths.docsRoot}/project-context.md\\` or`,\n      \"`agentConfig.rules`, outputs land under:\",\n      \"\",\n      `- \\`${paths.researchRoot}/scopes/<slug>.scope.md\\``,\n      `- \\`${paths.researchRoot}/slices/<slug>-NN-<slice-slug>.slice.md\\``,\n      `- \\`${paths.researchRoot}/deliverables/<slug>.md\\``,\n      `- \\`${paths.researchRoot}/deliverables/<slug>.verify.md\\``,\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `research:scope` issue with `type:research`,\",\n      `   \\`priority:${labelsForPhase(issueDefaults, \"research:scope\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"research:scope\").status}\\`. Body must include the`,\n      \"   verbatim question, authorized sources, and any overrides.\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 1 (Scope) of the research-analyst agent.\",\n      \"3. Phase 1 creates `research:slice` issues (one per slice) and a\",\n      \"   single `research:verify` issue. Each downstream issue declares\",\n      \"   its `Depends on:` predecessor.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- A scope file under the project's research scope directory\",\n      \"- One slice note per slice under the slices directory\",\n      \"- A single deliverable plus verification report under the deliverables\",\n      \"  directory\",\n      \"- This pipeline produces **notes and deliverables only** — it does\",\n      \"  not open downstream `type:requirement` or profile issues.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/**\n * Build the research-pipeline bundle with the supplied resolved paths.\n *\n * Every reference to a canonical agent path (research root, docs root,\n * etc.) inside the rule / skill / sub-agent content strings is an\n * interpolation of the supplied `paths` struct, so a consumer override\n * of `AgentConfigOptions.paths` propagates to the rendered output.\n */\nexport function buildResearchPipelineBundle(\n  paths: ResolvedAgentPaths = DEFAULT_AGENT_PATHS,\n  issueDefaults: ResolvedIssueDefaults = DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n): AgentRuleBundle {\n  return {\n    name: \"research-pipeline\",\n    description:\n      \"Generic research micro-task pipeline: scope, N-way slice search/synthesize, and verify. Enabled by default; domain-neutral; filesystem-durable between phases.\",\n    appliesWhen: () => true,\n    rules: [\n      {\n        name: \"research-pipeline-workflow\",\n        description:\n          \"Describes the 3-phase generic research pipeline, the research:* label taxonomy, and the boundary against downstream specialized agents.\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Research Pipeline Workflow\",\n          \"\",\n          \"Use `/research <question>` to kick off a generic research\",\n          \"micro-task pipeline. The pipeline runs in 3 phases — scope, slice,\",\n          \"verify — each tracked by its own GitHub issue labeled\",\n          \"`research:scope`, `research:slice`, or `research:verify`. All\",\n          \"issues carry `type:research`.\",\n          \"\",\n          \"The pipeline produces **notes and deliverables only**. It does\",\n          \"not open downstream `type:requirement` or profile issues — those\",\n          \"belong to specialized downstream agents that consume the\",\n          \"deliverables.\",\n          \"\",\n          \"See the `research-analyst` agent definition for full workflow\",\n          \"details, default paths, and phase-by-phase instructions.\",\n        ].join(\"\\n\"),\n        platforms: {\n          cursor: { exclude: true },\n        },\n        tags: [\"workflow\"],\n      },\n    ],\n    skills: [buildResearchSkill(paths, issueDefaults)],\n    subAgents: [buildResearchAnalystSubAgent(paths)],\n    labels: [\n      {\n        name: \"type:research\",\n        color: \"5319E7\",\n        description:\n          \"Work that produces or consumes a research note, slice, or deliverable\",\n      },\n      {\n        name: \"research:scope\",\n        color: \"C5DEF5\",\n        description:\n          \"Phase 1: decompose a research question into N focused slice issues\",\n      },\n      {\n        name: \"research:slice\",\n        color: \"BFDADC\",\n        description:\n          \"Phase 2: execute one research slice — search authorized sources and write a slice note\",\n      },\n      {\n        name: \"research:verify\",\n        color: \"D4C5F9\",\n        description:\n          \"Phase 3: reconcile slice notes into a verified deliverable\",\n      },\n    ],\n  };\n}\n\n/**\n * Default-paths instance of the research-pipeline bundle, preserved\n * for backward compatibility with consumers that import the const\n * directly. The factory above is the canonical entry point when a\n * consumer supplies `AgentConfigOptions.paths`.\n */\nexport const researchPipelineBundle: AgentRuleBundle =\n  buildResearchPipelineBundle();\n","import { Component, Project } from \"projen\";\nimport { NodeProject } from \"projen/lib/javascript\";\nimport {\n  ProjectMetadataOptions,\n  ResolvedProjectMetadata,\n} from \"./project-metadata-options\";\nimport { MONOREPO_LAYOUT_SEED_BLOCK } from \"../agent/bundles/project-context\";\n\n/**\n * Regex patterns for extracting owner and name from GitHub repository URLs.\n *\n * Matches:\n * - `https://github.com/owner/repo`\n * - `https://github.com/owner/repo.git`\n * - `git@github.com:owner/repo.git`\n * - `git+https://github.com/owner/repo.git`\n */\nconst GITHUB_HTTPS_RE =\n  /(?:https?:\\/\\/|git\\+https:\\/\\/)github\\.com\\/([^/]+)\\/([^/.]+)(?:\\.git)?/;\nconst GITHUB_SSH_RE = /git@github\\.com:([^/]+)\\/([^/.]+)(?:\\.git)?/;\n\n/**\n * Extracts owner and name from a GitHub repository URL.\n * Returns undefined values if the URL does not match expected formats.\n */\nfunction parseGitHubUrl(url: string): {\n  owner: string | undefined;\n  name: string | undefined;\n} {\n  const httpsMatch = url.match(GITHUB_HTTPS_RE);\n  if (httpsMatch) {\n    return { owner: httpsMatch[1], name: httpsMatch[2] };\n  }\n\n  const sshMatch = url.match(GITHUB_SSH_RE);\n  if (sshMatch) {\n    return { owner: sshMatch[1], name: sshMatch[2] };\n  }\n\n  return { owner: undefined, name: undefined };\n}\n\n/**\n * Provides structured project metadata consumed by AgentConfig, skills,\n * and other configulator features at synthesis time.\n *\n * This is a project-level component — it describes the project itself,\n * not any specific feature. It lives alongside MonorepoProject and\n * TypeScriptProject and is discovered by consumers via the static\n * `.of()` factory method.\n */\nexport class ProjectMetadata extends Component {\n  /**\n   * Returns the ProjectMetadata instance for a project. Walks up the parent\n   * chain so sub-projects resolve the metadata declared on a root\n   * `MonorepoProject` without needing a duplicate declaration of their own.\n   * Returns `undefined` if no ancestor has a `ProjectMetadata` component.\n   */\n  public static of(project: Project): ProjectMetadata | undefined {\n    const isProjectMetadata = (c: Component): c is ProjectMetadata =>\n      c instanceof ProjectMetadata;\n    let current: Project | undefined = project;\n    while (current) {\n      const found = current.components.find(isProjectMetadata);\n      if (found) {\n        return found;\n      }\n      current = current.parent;\n    }\n    return undefined;\n  }\n\n  /** Resolved metadata with auto-detected values filled in. */\n  public readonly metadata: ResolvedProjectMetadata;\n\n  constructor(project: Project, options: ProjectMetadataOptions = {}) {\n    super(project);\n    this.metadata = this.resolveMetadata(options);\n  }\n\n  /**\n   * Merges explicit options with auto-detected values.\n   * Auto-detection reads the repository URL from package.json\n   * (via Projen's NodePackage manifest) and parses GitHub owner/name.\n   * Explicit options always take precedence over auto-detected values.\n   */\n  private resolveMetadata(\n    options: ProjectMetadataOptions,\n  ): ResolvedProjectMetadata {\n    const autoDetected = this.autoDetectRepository();\n\n    return {\n      repository: {\n        owner: options.repository?.owner ?? autoDetected.owner,\n        name: options.repository?.name ?? autoDetected.name,\n        defaultBranch: options.repository?.defaultBranch ?? \"main\",\n      },\n      githubProject: options.githubProject,\n      organization: options.organization,\n      slack: options.slack,\n      labels: options.labels,\n      milestones: options.milestones,\n      docsPath: options.docsPath,\n      deployment: options.deployment,\n      monorepoLayoutSeedBlock: this.resolveMonorepoLayoutSeedBlock(),\n    };\n  }\n\n  /**\n   * Return the maintainer-seed addendum for the `project-context`\n   * bundle, or an empty string when the root project either has no\n   * layout-enforcement opinion or has opted out\n   * (`layoutEnforcement: \"off\"`).\n   *\n   * Uses duck-typing on the root project's `layoutEnforcement`\n   * property to avoid a circular import with `MonorepoProject`. The\n   * concrete `MonorepoProject` class exposes this property as a\n   * string; anything else resolves to the empty string so repos that\n   * predate the monorepo layout contract see no change.\n   */\n  private resolveMonorepoLayoutSeedBlock(): string {\n    const root: unknown = this.project.root;\n    const enforcement = (root as { readonly layoutEnforcement?: unknown })\n      .layoutEnforcement;\n    if (typeof enforcement !== \"string\" || enforcement === \"off\") {\n      return \"\";\n    }\n    return MONOREPO_LAYOUT_SEED_BLOCK;\n  }\n\n  /**\n   * Attempts to auto-detect repository owner and name from the Projen\n   * project's package.json repository field.\n   */\n  private autoDetectRepository(): {\n    owner: string | undefined;\n    name: string | undefined;\n  } {\n    if (!(this.project instanceof NodeProject)) {\n      return { owner: undefined, name: undefined };\n    }\n\n    const manifest = this.project.package.manifest;\n    const repoField = manifest.repository;\n\n    if (!repoField) {\n      return { owner: undefined, name: undefined };\n    }\n\n    // repository can be a string URL or an object { type, url }\n    const url =\n      typeof repoField === \"string\" ? repoField : (repoField.url ?? \"\");\n\n    return parseGitHubUrl(url);\n  }\n}\n","import { Project } from \"projen/lib\";\nimport { ProjectMetadata } from \"../../projects/project-metadata\";\nimport { SlackMetadata } from \"../../projects/project-metadata-options\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\n\n/**\n * Returns true when the project's resolved metadata declares a Slack\n * integration. A declared integration means any of:\n *\n * - `slack.projectChannel` is set\n * - `slack.alertsChannel` is set\n * - `slack.channels` has at least one entry\n *\n * An empty `slack: {}` block is treated as \"not configured\" so consumers\n * do not accidentally activate the bundle by reserving the key.\n */\nfunction hasSlackConfig(slack: SlackMetadata | undefined): boolean {\n  if (!slack) {\n    return false;\n  }\n  if (slack.projectChannel || slack.alertsChannel) {\n    return true;\n  }\n  if (slack.channels && Object.keys(slack.channels).length > 0) {\n    return true;\n  }\n  return false;\n}\n\n/**\n * Slack bundle — auto-activated when the consuming project declares a\n * Slack integration via `ProjectMetadata.slack`. Consumers can still\n * opt in manually via `includeBundles: [\"slack\"]` when they have no\n * `ProjectMetadata` configured.\n *\n * Detection signal: any truthy value on\n * `ProjectMetadata.of(project).metadata.slack` that carries at least one\n * channel reference (`projectChannel`, `alertsChannel`, or a non-empty\n * `channels` record).\n */\nexport const slackBundle: AgentRuleBundle = {\n  name: \"slack\",\n  description:\n    \"Slack MCP message formatting and best practices. Auto-activates when ProjectMetadata declares a Slack integration; can still be force-included via `includeBundles: ['slack']`.\",\n  appliesWhen: (project: Project) => {\n    const pm = ProjectMetadata.of(project);\n    return hasSlackConfig(pm?.metadata.slack);\n  },\n  rules: [\n    {\n      name: \"slack-message-formatting\",\n      description:\n        \"Format Slack messages with explicit links so bullets and labels render correctly\",\n      scope: AGENT_RULE_SCOPE.ALWAYS,\n      content: [\n        \"# Slack Message Formatting\",\n        \"\",\n        \"When composing or sending messages to Slack (e.g., via Slack MCP tools like `slack_send_message`), use formatting that Slack's mrkdwn parser renders correctly.\",\n        \"\",\n        \"## Rules\",\n        \"\",\n        \"1. **Use Slack's explicit link syntax** for any link in a message:\",\n        \"   - Format: `<https://example.com|display text>`\",\n        \"   - Text outside the angle brackets (bullets, labels) stays separate and won't merge into the link\",\n        \"\",\n        \"2. **Do not rely on auto-linkification** when the message has bullets or labels before URLs — auto-linked URLs can break or merge with surrounding text\",\n        \"\",\n        \"3. **Put each list item on its own line** with a newline between items so list structure is clear\",\n        \"\",\n        \"4. **Example — preferred:**\",\n        \"   ```\",\n        \"   Status update:\",\n        \"\",\n        \"   • Feature A: <https://github.com/org/repo/pull/1|repo#1>\",\n        \"   • Feature B: <https://github.com/org/repo/pull/2|repo#2>\",\n        \"   ```\",\n        \"\",\n        \"5. **Avoid:** Plain URLs immediately after a bullet/label on the same line (e.g., `• Feature A: https://github.com/...`) when sending via API, as it can render with bullets inside or between links\",\n        \"\",\n        \"## Activation\",\n        \"\",\n        \"This bundle auto-activates when the consuming project declares a Slack integration through `ProjectMetadata` (any of `slack.projectChannel`, `slack.alertsChannel`, or a non-empty `slack.channels` record). If no `ProjectMetadata` is configured, opt in manually via `AgentConfigOptions.includeBundles: ['slack']`.\",\n      ].join(\"\\n\"),\n      tags: [\"workflow\"],\n    },\n  ],\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { renderClaimVerificationSection } from \"./claim-verification\";\nimport {\n  ISSUE_CLOSE_RULE_REFERENCE,\n  ISSUE_CLOSE_SECTION_TITLE,\n  renderIssueClosePolicySection,\n} from \"./issue-close\";\nimport {\n  DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n  ResolvedIssueDefaults,\n  labelsForPhase,\n} from \"./issue-defaults\";\nimport { renderIssueTypeAssignmentStep } from \"./issue-type\";\nimport { renderOriginStampSection } from \"./origin-label\";\nimport { DEFAULT_AGENT_PATHS, ResolvedAgentPaths } from \"./paths\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n  AGENT_MODEL,\n  AGENT_RULE_SCOPE,\n  AgentModel,\n  AgentSkill,\n  AgentSubAgent,\n} from \"../types\";\n\n/**\n * Sub-agent that researches and profiles software products into\n * structured markdown. Produces one profile per product, extracts a\n * feature matrix across a set of products, ranks features using\n * configurable segment-importance weights, maps features back to the\n * BCM capability model and flags unmapped features as candidates for\n * new BCM sub-capabilities, and enqueues downstream research issues for\n * the vendor company and primary-attribution people surfaced during\n * profiling (handed off to the `bcm-writer`, `company-profile`, and\n * `people-profile` bundles).\n *\n * The prompt deliberately avoids hardcoded domains, companies, or source\n * projects. Consumers configure the product list, feature taxonomy,\n * segment weights, output paths, BCM tree location, the unmapped-feature\n * threshold, and downstream trigger behavior via the skill invocation\n * and by extending the rule in their own `agentConfig.rules`.\n */\nfunction buildSoftwareProfileAnalystSubAgent(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n  tier: AgentModel,\n): AgentSubAgent {\n  return {\n    name: \"software-profile-analyst\",\n    description:\n      \"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.\",\n    model: tier,\n    maxTurns: 80,\n    platforms: { cursor: { exclude: true } },\n    prompt: [\n      \"# Software Profile Analyst Agent\",\n      \"\",\n      \"You research a single software product from public sources and write\",\n      \"a structured markdown profile. Each profile cycle runs across a small\",\n      \"sequence of GitHub issues — one per phase — and produces a single\",\n      \"profile file on disk, a set of feature-matrix rows, a back-mapping\",\n      \"onto the BCM capability model, and optional follow-up research\",\n      \"issues for adjacent products.\",\n      \"\",\n      \"This agent is **domain-neutral**. It makes no assumptions about what\",\n      \"the consuming project sells, which industry it serves, or which\",\n      \"products matter to it. All domain-specific vocabulary, segment\",\n      \"weights, feature taxonomies, output locations, and profile-template\",\n      \"overrides come from the invoking issue body or the consuming\",\n      \"project's configuration.\",\n      \"\",\n      \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n      \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...PROJECT_CONTEXT_READER_SECTION,\n      \"## Design Principles\",\n      \"\",\n      \"1. **One product per session.** Never profile two products in a\",\n      \"   single session, even if they came up together.\",\n      \"2. **Public sources only.** Use the product's own site, docs, pricing\",\n      \"   pages, changelogs, public demos, and similar public material. Do\",\n      \"   not attempt to access gated or paywalled content unless the\",\n      \"   invoking issue body explicitly authorizes it.\",\n      \"3. **Filesystem durability.** The profile file and feature-matrix\",\n      \"   rows are the deliverables. Both are committed to disk before the\",\n      \"   profile issue closes. Downstream phases read from disk — never\",\n      \"   rely on session memory.\",\n      \"4. **Generic over specific.** No hardcoded product types, feature\",\n      \"   taxonomies, or segment assumptions. Use the generic software-type\",\n      \"   taxonomy below and let consuming projects override it via their\",\n      `   \\`${paths.docsRoot}/project-context.md\\` or \\`agentConfig.rules\\`.`,\n      \"5. **Cite everything.** Every non-trivial factual claim in the\",\n      \"   profile must carry a source citation (URL plus access date).\",\n      \"6. **Follow-up, don't widen scope.** If the session turns up adjacent\",\n      \"   products worth evaluating, emit a follow-up issue rather than\",\n      \"   expanding the profile beyond its scope. The vendor company and\",\n      \"   primary-attribution founders/product leaders are handed off to\",\n      \"   the `company-profile` bundle via `company:research` issues and\",\n      \"   the `people-profile` bundle via `people:research` issues; adjacent\",\n      \"   products stay inside this pipeline via `software:research`\",\n      \"   issues.\",\n      \"7. **Segment weights live in project context.** Segment-importance\",\n      `   weights belong in \\`${paths.docsRoot}/project-context.md\\` (or an override`,\n      \"   passed in the issue body). This agent reads them; it never\",\n      \"   invents them.\",\n      \"8. **Map back to the capability model.** The BCM capability model is\",\n      \"   the single source of truth for what the business does. Every\",\n      \"   feature on every profile is mapped to the owning capability in the\",\n      \"   BCM tree during the map phase. Features that match nothing in the\",\n      \"   tree are candidates for new BCM sub-capabilities — they are\",\n      \"   flagged and handed off to the `bcm-writer` bundle via\",\n      \"   `bcm:outline` issues. This agent never authors BCM documents\",\n      \"   itself.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Software Type Taxonomy\",\n      \"\",\n      \"Pick exactly one type per software profile. The taxonomy is\",\n      \"deliberately generic — consuming projects override it via\",\n      \"`agentConfig.rules` if they need a domain-specific refinement.\",\n      \"\",\n      \"| Type | Use for |\",\n      \"|------|---------|\",\n      \"| `competitor` | Products that offer a substitutable feature set to the same buyers for the same jobs-to-be-done. |\",\n      \"| `adjacent` | Products that solve a neighboring problem or serve an overlapping buyer — not a direct substitute but worth understanding for positioning and integration. |\",\n      \"| `incumbent` | Established, widely-deployed products that define the status quo in the space. Often older, broader, and harder to displace. |\",\n      \"| `enabler` | Products the consuming project might build on, integrate with, or resell. Platforms, SDKs, APIs, and similar building blocks. |\",\n      \"| `infrastructure` | Lower-level infrastructure or runtime components the consuming project depends on (databases, queues, identity, observability, etc.). |\",\n      \"| `ecosystem-tool` | Developer tooling, plugins, extensions, or companion products that surround an incumbent or competitor without being one themselves. |\",\n      \"\",\n      \"If the product plausibly fits two types, prefer the one that reflects\",\n      \"the **reason the profile was requested**, and note the secondary\",\n      \"type in the profile body.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Segment-Importance Weights\",\n      \"\",\n      \"Feature ranking uses **segment-importance weights** — a small table\",\n      \"that assigns a numeric weight to each customer segment the consuming\",\n      \"project cares about. Higher weight means the segment matters more to\",\n      \"the project's own strategy; features that serve high-weight segments\",\n      \"rank higher in the matrix.\",\n      \"\",\n      `**Convention:** segment weights live in \\`${paths.docsRoot}/project-context.md\\``,\n      \"under a `## Segment Weights` section. The format is a simple\",\n      \"markdown table with `segment` and `weight` columns. Weights are\",\n      \"non-negative numbers; the scale is project-defined (0–1, 0–10, and\",\n      \"0–100 are all valid as long as the project is internally\",\n      \"consistent).\",\n      \"\",\n      `Example \\`${paths.docsRoot}/project-context.md\\` fragment:`,\n      \"\",\n      \"```markdown\",\n      \"## Segment Weights\",\n      \"\",\n      \"| segment | weight |\",\n      \"|---------|--------|\",\n      \"| enterprise | 3 |\",\n      \"| mid-market | 2 |\",\n      \"| smb       | 1 |\",\n      \"| hobbyist  | 0.5 |\",\n      \"```\",\n      \"\",\n      `If \\`${paths.docsRoot}/project-context.md\\` does not define segment weights,`,\n      \"**do not invent them**. Either:\",\n      \"\",\n      \"- Accept an `weights:` override in the invoking issue body, or\",\n      \"- Produce the feature matrix with a single segment (`default`)\",\n      \"  weighted `1` and flag the missing weights in the profile's\",\n      \"  `## Open Questions` section.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## State Machine Overview\",\n      \"\",\n      \"```\",\n      \"┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐\",\n      \"│1.RESEARCH│─▶│2.PROFILE │─▶│3.MATRIX  │─▶│4.MAP     │─▶│5.FOLLOWUP│\",\n      \"│Collect   │  │Write the │  │Extract   │  │Map each  │  │Enqueue   │\",\n      \"│public    │  │structured│  │feature   │  │feature to│  │research  │\",\n      \"│sources   │  │markdown  │  │rows and  │  │BCM       │  │for       │\",\n      \"│into      │  │profile to│  │score     │  │capability│  │adjacent  │\",\n      \"│bounded   │  │<PROFILES>│  │against   │  │and flag  │  │products  │\",\n      \"│notes file│  │          │  │weights   │  │gaps      │  │surfaced  │\",\n      \"└──────────┘  └──────────┘  └──────────┘  └──────────┘  └──────────┘\",\n      \"```\",\n      \"\",\n      \"**Issue labels encode the phase:**\",\n      \"\",\n      \"| Label | Phase | Session work |\",\n      \"|-------|-------|-------------|\",\n      \"| `software:research` | 1. Research | Gather public sources. Write a bounded research-notes file. Create the profile issue. |\",\n      \"| `software:profile` | 2. Profile | Read the research notes. Write the structured profile to `<PROFILES_DIR>`. Create the matrix issue. |\",\n      \"| `software:matrix` | 3. Matrix | Read the profile. Extract feature rows into `<MATRIX_FILE>`. Score against segment weights. Create the map issue. |\",\n      \"| `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. |\",\n      \"| `software:followup` | 5. Followup | Read the profile. Enqueue software-research issues for adjacent products surfaced in the profile. |\",\n      \"\",\n      \"All issues also carry `type:software-profile` and a `status:*` label.\",\n      \"\",\n      \"**Issue count per product cycle:** 1 research + 1 profile + 1 matrix +\",\n      \"1 map + 0–1 followup = **4–5 sessions**. The followup phase is\",\n      \"skipped when the profile did not surface any adjacent product worth\",\n      \"researching.\",\n      \"\",\n      \"**Shortened paths:**\",\n      \"- Research phase determines the product is out of scope (not\",\n      \"  relevant, insufficient public material) → research issue closes\",\n      \"  with a justification and no downstream issues are created → **1 session**.\",\n      \"- Narrow product with no adjacent candidates → **4 sessions**.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Configurable Paths\",\n      \"\",\n      \"The pipeline uses these placeholders. Consuming projects override the\",\n      \"defaults by passing paths in the `/profile-software` skill invocation\",\n      \"or by extending this rule in their own `agentConfig.rules`.\",\n      \"\",\n      \"| Placeholder | Meaning | Default |\",\n      \"|-------------|---------|---------|\",\n      `| \\`<SOFTWARE_ROOT>\\` | Root folder for software profiles | \\`${paths.softwareRoot}/\\` |`,\n      \"| `<PROFILES_DIR>` | Final software profile files | `<SOFTWARE_ROOT>/profiles/` |\",\n      \"| `<NOTES_DIR>` | Research-notes files from Phase 1 | `<SOFTWARE_ROOT>/notes/` |\",\n      \"| `<MATRIX_FILE>` | Shared feature-matrix file | `<SOFTWARE_ROOT>/feature-matrix.md` |\",\n      \"| `<PRODUCT_SLUG>` | Short kebab-case slug identifying the product | derived from the product name |\",\n      `| \\`<COMPANY_PROFILES_DIR>\\` | Where existing company profiles live (for duplicate detection during followup) | \\`${paths.companiesRoot}/profiles/\\` |`,\n      `| \\`<PEOPLE_PROFILES_DIR>\\` | Where existing people profiles live (for duplicate detection during followup) | \\`${paths.peopleRoot}/profiles/\\` |`,\n      `| \\`<BCM_DOC_ROOT>\\` | Root folder for BCM capability-model documents (used by Phase 4 to locate capabilities) | \\`${paths.bcmRoot}/\\` |`,\n      \"| `<BCM_CAPABILITY_MAP>` | Capability-map file that lists the L1/L2/L3 hierarchy | `<BCM_DOC_ROOT>/capability-map.md` |\",\n      \"| `<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`) |\",\n      \"\",\n      `If \\`${paths.docsRoot}/project-context.md\\` specifies a different software-research`,\n      \"tree (for example by reusing the research-pipeline deliverables\",\n      \"folder), prefer that. Otherwise fall back to the defaults above.\",\n      \"\",\n      `The \\`<BCM_DOC_ROOT>\\` default above is \\`${paths.bcmRoot}\\` —`,\n      \"the canonical BCM root emitted by configulator's default path\",\n      \"resolution. If the consuming project's capability model lives\",\n      \"somewhere else, pass an override in the invoking issue body or\",\n      \"extend this rule in `agentConfig.rules`; reading\",\n      \"`agentConfig.paths.bcmRoot` directly is not currently wired through\",\n      \"to rule content at synth time. Override `<UNMAPPED_THRESHOLD>` the\",\n      \"same way when the default (one `bcm:outline` per unmapped feature)\",\n      \"is too noisy — for example, raise it to `3` to require at least\",\n      \"three unmapped features on a single profile before any follow-ups\",\n      \"are filed.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Agent Loop\",\n      \"\",\n      \"Run this loop exactly once per session. Never start a second issue.\",\n      \"\",\n      \"1. Claim one open `type:software-profile` issue using phase priority:\",\n      \"   `software:research` > `software:profile` > `software:matrix` >\",\n      \"   `software:map` > `software:followup`.\",\n      \"2. Transition `status:ready` → `status:in-progress` and create the\",\n      \"   branch per your project's branch-naming convention.\",\n      \"3. Execute the phase handler that matches the issue's `software:*`\",\n      \"   label.\",\n      \"4. Commit, push, open a PR (if applicable), and close the issue per\",\n      `   your project's PR workflow — see the **${ISSUE_CLOSE_SECTION_TITLE}**`,\n      \"   section below before you close anything yourself.\",\n      \"   Stamp every PR you open with the `origin:agent` label — see the\",\n      \"   **Origin label** section below.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...renderClaimVerificationSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderOriginStampSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderIssueClosePolicySection(),\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 1: Research (`software:research`)\",\n      \"\",\n      \"**Goal:** Gather public sources into a bounded research-notes file.\",\n      \"\",\n      \"**Budget:** Public web search only, unless the issue body authorizes\",\n      \"additional sources. Write one notes file. Do not write the profile\",\n      \"or extend the feature matrix in this phase.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the issue body.** It should include:\",\n      \"   - The product name and website (if known)\",\n      \"   - The requested software type from the taxonomy above\",\n      \"   - The reason the profile was requested (framing — what does the\",\n      \"     invoking project want to learn?)\",\n      \"   - Optional: `<PRODUCT_SLUG>` override, custom output paths,\",\n      \"     `weights:` override for segment-importance weights\",\n      \"\",\n      \"2. **Derive `<PRODUCT_SLUG>`** if not supplied — a 2–4 word\",\n      \"   kebab-case summary of the product name. Ensure the slug is not\",\n      \"   already in use under `<PROFILES_DIR>/` or `<NOTES_DIR>/`.\",\n      \"\",\n      \"3. **Gather sources.** Prioritize in this order:\",\n      \"   - The product's own website (home, product, pricing, docs,\",\n      \"     changelog, integrations)\",\n      \"   - Public documentation, developer references, API docs\",\n      \"   - Public changelogs, release notes, roadmap posts\",\n      \"   - Reputable independent reviews and comparison articles\",\n      \"   - Public issue trackers or community forums when the issue body\",\n      \"     authorizes them\",\n      \"\",\n      \"4. **Write a research-notes file** to\",\n      \"   `<NOTES_DIR>/<PRODUCT_SLUG>.notes.md`:\",\n      \"\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"Research Notes: <product name>\"',\n      \"   slug: <PRODUCT_SLUG>\",\n      \"   software_type: <one of the taxonomy values>\",\n      \"   date: YYYY-MM-DD\",\n      \"   parent_issue: <N>\",\n      \"   ---\",\n      \"\",\n      \"   ## Framing\",\n      \"   <why this product was requested and what to learn>\",\n      \"\",\n      \"   ## Raw Findings\",\n      \"   - <finding> — source: <citation>\",\n      \"\",\n      \"   ## Candidate Features\",\n      \"   - <feature name>: <one-line description> — source: <citation>\",\n      \"\",\n      \"   ## Candidate Adjacent Products\",\n      \"   - <product name> — source: <citation>\",\n      \"\",\n      \"   ## Open Questions\",\n      \"   <anything the notes could not answer from public sources>\",\n      \"\",\n      \"   ## Sources\",\n      \"   - <source URL or file path> — <date accessed>\",\n      \"   ```\",\n      \"\",\n      \"5. **Create the `software:profile` issue** with\",\n      \"   `Depends on: #<research-issue>`. Its body references the notes\",\n      \"   file path and the requested software type.\",\n      \"\",\n      \"6. **Commit and push** the notes file. Close the research issue\",\n      `   ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 2: Profile (`software:profile`)\",\n      \"\",\n      \"**Goal:** Write the structured software profile from the research\",\n      \"notes.\",\n      \"\",\n      \"**Budget:** No new web searches unless explicitly needed to fill a\",\n      \"gap the notes flagged. Write one profile file.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the research-notes file** referenced in the issue body.\",\n      \"\",\n      \"2. **Check for duplicates.** If `<PROFILES_DIR>/<PRODUCT_SLUG>.md`\",\n      \"   already exists, open it and decide whether to update in place or\",\n      \"   flag a naming collision. Never silently overwrite a non-trivial\",\n      \"   existing profile.\",\n      \"\",\n      \"3. **Write the profile** to `<PROFILES_DIR>/<PRODUCT_SLUG>.md` using\",\n      \"   the template below. All sections are required; use\",\n      \"   `_Not available in public sources._` when a section cannot be\",\n      \"   filled from the notes.\",\n      \"\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"<product name>\"',\n      \"   slug: <PRODUCT_SLUG>\",\n      \"   software_type: <one of the taxonomy values>\",\n      \"   website: <primary URL>\",\n      \"   date: YYYY-MM-DD\",\n      \"   parent_issue: <N>\",\n      \"   notes: <NOTES_DIR>/<PRODUCT_SLUG>.notes.md\",\n      \"   ---\",\n      \"\",\n      \"   ## Summary\",\n      \"   <2–4 sentence elevator description: what it does, who it's for>\",\n      \"\",\n      \"   ## Classification\",\n      \"   - **Primary type:** <taxonomy value>\",\n      \"   - **Secondary type (if any):** <taxonomy value or `n/a`>\",\n      \"   - **Relevance to this project:** <1–2 sentences tying the product\",\n      \"     back to the framing from the notes>\",\n      \"\",\n      \"   ## Offering\",\n      \"   - **Jobs-to-be-done:** <bullet list of core use cases>\",\n      \"   - **Target segments:** <who this product is for; reuse segment\",\n      \"     names from the project's segment-weights table when possible>\",\n      \"   - **Pricing model:** <if disclosed>\",\n      \"   - **Deployment model:** <SaaS / self-hosted / hybrid / on-prem>\",\n      \"\",\n      \"   ## Features\",\n      \"   <grouped bullet list of notable features, each cited. These become\",\n      \"   the rows in the feature matrix during Phase 3 and the rows of the\",\n      \"   capability mapping during Phase 4.>\",\n      \"\",\n      \"   ## Capability Mapping\",\n      \"   _To be filled in during Phase 4 (Map). Leave as\",\n      \"   `_Pending capability mapping — filled in Phase 4._` until then._\",\n      \"\",\n      \"   ## Technology Signals\",\n      \"   <stack hints from docs, integrations, and public engineering\",\n      \"   content — each bullet cited>\",\n      \"\",\n      \"   ## Positioning / Differentiation\",\n      \"   <how the product describes itself and how it differs from adjacent\",\n      \"   products — use its own language, cited, rather than inferred>\",\n      \"\",\n      \"   ## Risks / Open Questions\",\n      \"   <what the profile could not answer; flag anything the matrix or\",\n      \"   follow-up phase should escalate>\",\n      \"\",\n      \"   ## Follow-up Candidates\",\n      \"   - **Vendor company:** <company name and primary domain — always\",\n      \"     one entry; this is the company that builds or maintains the\",\n      \"     product>\",\n      \"   - **Primary-attribution people:** <list of founders, CEOs, or\",\n      \"     principal creators with clear primary attribution to the\",\n      \"     product — full name + role + employing company. Leave blank if\",\n      \"     no person has primary attribution per the restraint guidance\",\n      \"     in Phase 4.>\",\n      \"   - **Adjacent products to evaluate:** <list of candidate product\",\n      \"     names>\",\n      \"\",\n      \"   ## Sources\",\n      \"   - <source URL> — <date accessed>\",\n      \"   ```\",\n      \"\",\n      \"4. **Create the `software:matrix` issue** with\",\n      \"   `Depends on: #<profile-issue>`. Its body references the profile\",\n      \"   path, the matrix file path, and the segment-weights source\",\n      `   (\\`${paths.docsRoot}/project-context.md\\` or an explicit override).`,\n      \"\",\n      \"5. **Commit and push** the profile file. Close the profile issue\",\n      `   ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 3: Matrix (`software:matrix`)\",\n      \"\",\n      \"**Goal:** Extract feature rows from the profile into the shared\",\n      \"feature matrix and score each feature against the segment-importance\",\n      \"weights.\",\n      \"\",\n      \"**Budget:** No new research. Read the profile, update the matrix,\",\n      \"close the phase.\",\n      \"\",\n      \"### Matrix File Format\",\n      \"\",\n      \"The feature matrix is a single markdown file at `<MATRIX_FILE>`. It\",\n      \"uses a wide table with one row per (product, feature) pair and one\",\n      \"column per segment plus a computed `score` column.\",\n      \"\",\n      \"```markdown\",\n      \"---\",\n      'title: \"Software Feature Matrix\"',\n      `weights_source: ${paths.docsRoot}/project-context.md#segment-weights`,\n      \"updated: YYYY-MM-DD\",\n      \"---\",\n      \"\",\n      \"| product | feature | <segment-1> | <segment-2> | ... | score | source |\",\n      \"|---------|---------|-------------|-------------|-----|-------|--------|\",\n      \"| <slug>  | <feature-name> | 0–1 | 0–1 | ... | <weighted-sum> | <profile-path> |\",\n      \"```\",\n      \"\",\n      \"Segment columns carry a **coverage score** in `[0, 1]` representing\",\n      \"how well the feature serves that segment — `1` means fully covered,\",\n      \"`0` means not covered, intermediate values reflect partial coverage\",\n      \"(e.g. self-serve only, gated by pricing tier, limited by scale).\",\n      \"\",\n      \"The `score` column is the weighted sum:\",\n      \"\",\n      \"```\",\n      \"score = Σ (coverage[segment] * weight[segment])\",\n      \"```\",\n      \"\",\n      `using the weights loaded from \\`${paths.docsRoot}/project-context.md\\`.`,\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Load segment weights.** Read `## Segment Weights` from\",\n      `   \\`${paths.docsRoot}/project-context.md\\`. If absent, fall back to the`,\n      \"   `weights:` override in the issue body, or the single-segment\",\n      \"   default described in `## Segment-Importance Weights` above.\",\n      \"\",\n      \"2. **Read the profile file** referenced in the issue body. Extract\",\n      \"   the bullets under `## Features` as candidate matrix rows.\",\n      \"\",\n      \"3. **Open or create `<MATRIX_FILE>`.** If the file does not exist,\",\n      \"   write the front-matter and header row using the current set of\",\n      \"   segment columns. If it exists, ensure its segment columns match\",\n      \"   the loaded weights; if they have drifted, add any missing columns\",\n      \"   and leave a note in the profile's `## Risks / Open Questions`.\",\n      \"\",\n      \"4. **Append or update rows** for the current product. One row per\",\n      \"   feature. For each row:\",\n      \"   - Assign a coverage score in `[0, 1]` for each segment, citing\",\n      \"     the profile section that justifies the score.\",\n      \"   - Compute the `score` as the weighted sum.\",\n      \"   - Set the `source` column to the profile file path.\",\n      \"\",\n      \"5. **Update the matrix front-matter** (`updated: YYYY-MM-DD`).\",\n      \"\",\n      \"6. **Create the `software:map` issue** with\",\n      \"   `Depends on: #<matrix-issue>`. Its body references the profile\",\n      \"   path, the matrix file path, the BCM document root\",\n      \"   (`<BCM_DOC_ROOT>`), the capability map file\",\n      \"   (`<BCM_CAPABILITY_MAP>` if it exists), and the unmapped-feature\",\n      \"   threshold (`<UNMAPPED_THRESHOLD>`). The map phase always runs —\",\n      \"   every profile is mapped back to the capability model regardless\",\n      \"   of whether any adjacent products were surfaced.\",\n      \"\",\n      \"7. **Commit any profile updates first — do not touch the\",\n      \"   matrix yet.** If step 4 surfaced edits to the per-product\",\n      \"   profile file (e.g. notes added to `## Risks / Open\",\n      \"   Questions` about column drift), stage and commit those\",\n      \"   profile changes in a focused commit. **Do not push yet,**\",\n      \"   and **do not** include the matrix file in this commit.\",\n      \"\",\n      \"8. **Defer the feature-matrix row insert to a final pre-push\",\n      \"   commit.** Per the `shared-editing-safety` rule's\",\n      \"   **Defer Shared-Index Commit to Final Pre-Push Step**\",\n      \"   subsection, the feature matrix is the canonical example of\",\n      \"   a **shared index file** — multiple software-profile\",\n      \"   sessions racing to append rows for different products is\",\n      \"   the exact contention this rule exists to mitigate. Apply\",\n      \"   the deferred sequence:\",\n      \"\",\n      \"   ```bash\",\n      \"   git fetch origin\",\n      \"   git pull --rebase origin <default-branch>\",\n      \"   ```\",\n      \"\",\n      \"   Re-read `<MATRIX_FILE>` from the now-up-to-date working\",\n      \"   tree, re-compute the deterministic insert position for the\",\n      \"   current product's rows (another session may have appended\",\n      \"   rows for a different product, or extended the segment\",\n      \"   columns, in the meantime), insert the rows in sort order,\",\n      \"   and commit the matrix edit in its **own focused commit**\",\n      \"   whose only file is `<MATRIX_FILE>`. Run the commit-path\",\n      \"   verification step (`git show HEAD:<MATRIX_FILE>` + grep\",\n      \"   count on the product slug as the unique marker) against\",\n      \"   that commit before pushing.\",\n      \"\",\n      \"9. **Push and close.** Push the branch, then close the matrix issue\",\n      `   ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 4: Map (`software:map`)\",\n      \"\",\n      \"**Goal:** Map each feature on the profile back to the owning\",\n      \"capability in the BCM capability model, write the mapping onto the\",\n      \"profile, and enqueue `bcm:outline` follow-ups for features that do\",\n      \"not match any existing capability.\",\n      \"\",\n      \"**Budget:** No new web searches. Read the profile, matrix, and BCM\",\n      \"tree; write the mapping section onto the profile; open\",\n      \"`bcm:outline` issues for the gaps.\",\n      \"\",\n      \"### Capability Mapping Format\",\n      \"\",\n      \"The mapping lives in the `## Capability Mapping` section of the\",\n      \"profile file. It is a table with one row per feature and explicit\",\n      \"evidence for each mapping decision:\",\n      \"\",\n      \"```markdown\",\n      \"## Capability Mapping\",\n      \"\",\n      \"_Mapped against `<BCM_CAPABILITY_MAP>` on YYYY-MM-DD._\",\n      \"\",\n      \"| feature | capability (id · name) | tier | confidence | notes |\",\n      \"|---------|-----------------------|------|------------|-------|\",\n      \"| <feature> | <bcm-id> · <capability name> | L1/L2/L3 | high/medium/low | <evidence or rationale> |\",\n      \"| <feature> | _unmapped_ | — | — | Candidate for new BCM sub-capability. Tracked in #<bcm-outline-issue> |\",\n      \"```\",\n      \"\",\n      \"Confidence levels:\",\n      \"\",\n      \"- **high** — the feature's jobs-to-be-done clearly match the\",\n      \"  capability's definition and business object.\",\n      \"- **medium** — the feature plausibly maps to the capability, but the\",\n      \"  match is partial (e.g. the feature covers only one facet of the\",\n      \"  capability, or the capability's definition is broader than the\",\n      \"  feature).\",\n      \"- **low** — the feature overlaps the capability only tangentially.\",\n      \"  Prefer `_unmapped_` over a low-confidence match when the feature\",\n      \"  is a genuine capability gap rather than a near-miss.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Load the BCM tree.** Read `<BCM_CAPABILITY_MAP>` if it exists,\",\n      \"   otherwise walk `<BCM_DOC_ROOT>/` for capability-model documents.\",\n      \"   Build an in-session index of `{ id, name, tier, business_object }`\",\n      \"   entries. If the tree is empty (no BCM documents yet), note the\",\n      \"   gap in the profile's `## Risks / Open Questions`, skip the\",\n      \"   per-feature mapping, and mark **every** feature as a candidate\",\n      \"   for a new sub-capability — subject to `<UNMAPPED_THRESHOLD>`.\",\n      \"\",\n      \"2. **Read the profile file** and extract the `## Features` bullets.\",\n      \"   Each bullet is one row in the mapping table.\",\n      \"\",\n      \"3. **Map each feature to the best-fit capability.** Preferred\",\n      \"   algorithm:\",\n      \"   - Match against the capability's **business object** first (the\",\n      \"     thing the capability acts on).\",\n      \"   - Then match against the capability's **definition** and\",\n      \"     jobs-to-be-done.\",\n      \"   - Tie-break in favor of the most specific (deepest tier)\",\n      \"     capability — an L3 match beats an L2 match that covers it.\",\n      \"\",\n      \"4. **Record low-confidence mappings explicitly** — never hide a weak\",\n      \"   match behind a high-confidence label. If the best available\",\n      \"   match is low-confidence, mark the feature `_unmapped_` instead\",\n      \"   and describe the near-miss in the `notes` column.\",\n      \"\",\n      \"5. **Count unmapped features.** If the count meets or exceeds\",\n      \"   `<UNMAPPED_THRESHOLD>` (default `1`), open one `bcm:outline`\",\n      \"   issue per unmapped feature. The issue must carry:\",\n      \"\",\n      \"   - `type:bcm-document`\",\n      \"   - `bcm:outline`\",\n      `   - \\`priority:${labelsForPhase(issueDefaults, \"bcm:outline\").priority}\\``,\n      `   - \\`status:${labelsForPhase(issueDefaults, \"bcm:outline\").status}\\``,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"   The issue body must include:\",\n      \"   - A **discovery source** line naming this software profile\",\n      \"     (`Discovered while mapping: <product name>`)\",\n      \"   - A link to the software profile path\",\n      \"     (`Software profile: <PROFILES_DIR>/<PRODUCT_SLUG>.md`)\",\n      \"   - The feature name, its one-line description from the profile,\",\n      \"     and a candidate capability name framed as a noun (BIZBOK-aligned)\",\n      \"   - Enough identifying metadata that the `bcm-writer` agent can\",\n      \"     begin the outline phase without revisiting this software\",\n      \"     profile\",\n      \"\",\n      \"6. **Avoid duplicate `bcm:outline` issues.** Before opening one,\",\n      \"   scan `<BCM_DOC_ROOT>/` for an existing capability that covers\",\n      \"   the feature (in case the tree grew between the matrix and map\",\n      \"   phases) and scan open issues carrying `bcm:outline` so this\",\n      \"   phase never re-queues a capability that is already being\",\n      \"   outlined. If a match is found, reuse it as a cross-reference in\",\n      \"   the mapping table instead of opening a new issue.\",\n      \"\",\n      \"7. **Write the `## Capability Mapping` section** back onto the\",\n      \"   profile file, replacing the `_Pending capability mapping — filled\",\n      \"   in Phase 4._` placeholder. Preserve every other section of the\",\n      \"   profile verbatim — this phase only rewrites the mapping section.\",\n      \"\",\n      \"8. **Create the `software:followup` issue** with\",\n      \"   `Depends on: #<map-issue>`. Its body references the profile path\",\n      \"   and lists any adjacent products the profile's Follow-up\",\n      \"   Candidates section identified. Skip creating the followup issue\",\n      \"   only when the profile lists zero adjacent products, zero\",\n      \"   primary-attribution people, and the vendor already has a\",\n      \"   company profile — note the skip in the map issue's closing\",\n      \"   comment.\",\n      \"\",\n      \"9. **Assume the peer is present.** This phase assumes the\",\n      \"   `bcm-writer` bundle is enabled in the consuming project. If the\",\n      \"   bundle has been disabled, flag the map issue with\",\n      \"   `status:needs-attention` and list the unmapped features that\",\n      \"   could not be routed — never invent an alternative label\",\n      \"   taxonomy.\",\n      \"\",\n      \"10. **Commit and push** the updated profile. Close the map issue\",\n      `    ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 5: Followup (`software:followup`)\",\n      \"\",\n      \"**Goal:** Create downstream research issues for the adjacent products,\",\n      \"vendor company, and primary-attribution people surfaced in the\",\n      \"profile. Adjacent products stay inside this pipeline; the vendor\",\n      \"company is handed off to the `company-profile` bundle, and founders /\",\n      \"product leaders / principal creators are handed off to the\",\n      \"`people-profile` bundle.\",\n      \"\",\n      \"**Budget:** No new research. Read the profile, enqueue issues, close\",\n      \"the phase. Markdown cross-references in the profile are preserved —\",\n      \"issue creation is **additive** on top of the existing cross-reference\",\n      \"behavior.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the profile file** referenced in the issue body.\",\n      \"\",\n      \"2. **Enqueue software-research issues** for each entry under\",\n      \"   `Follow-up Candidates > Adjacent products to evaluate`. Each new\",\n      \"   issue follows the same 4-phase pipeline — start it in the\",\n      \"   `software:research` phase with `type:software-profile`,\",\n      `   \\`priority:${labelsForPhase(issueDefaults, \"software:research\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"software:research\").status}\\`.`,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"3. **Enqueue a `company:research` issue for the vendor company** if\",\n      \"   no matching profile already exists under `<COMPANY_PROFILES_DIR>/`.\",\n      \"   The vendor (the company that builds or maintains the product)\",\n      \"   **always qualifies** for a downstream company profile — there is\",\n      \"   no restraint filter here, only the duplicate check. The issue\",\n      \"   must carry:\",\n      \"\",\n      \"   - `type:company-profile`\",\n      \"   - `company:research`\",\n      `   - \\`priority:${labelsForPhase(issueDefaults, \"company:research\").priority}\\``,\n      `   - \\`status:${labelsForPhase(issueDefaults, \"company:research\").status}\\``,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"   The issue body must include:\",\n      \"   - A **discovery source** line naming this software profile\",\n      \"     (`Discovered while profiling: <product name>`)\",\n      \"   - A link to the software profile path (`Software profile: <PROFILES_DIR>/<PRODUCT_SLUG>.md`)\",\n      \"   - Enough identifying metadata — vendor company name and primary\",\n      \"     domain/website — that the `company-profile-analyst` agent can\",\n      \"     begin research without revisiting this software profile\",\n      \"\",\n      \"4. **Enqueue a `people:research` issue per primary-attribution\",\n      \"   person** surfaced in the profile. Only enqueue people who have\",\n      \"   **primary attribution** for the product (see restraint guidance\",\n      \"   below) and whose name does not already match a profile under\",\n      \"   `<PEOPLE_PROFILES_DIR>/`. The issue must carry:\",\n      \"\",\n      \"   - `type:people-profile`\",\n      \"   - `people:research`\",\n      `   - \\`priority:${labelsForPhase(issueDefaults, \"people:research\").priority}\\``,\n      `   - \\`status:${labelsForPhase(issueDefaults, \"people:research\").status}\\``,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"   The issue body must include:\",\n      \"   - A **discovery source** line naming this software profile\",\n      \"     (`Discovered while profiling: <product name>`)\",\n      \"   - A link to the software profile path (`Software profile: <PROFILES_DIR>/<PRODUCT_SLUG>.md`)\",\n      \"   - Enough identifying metadata — full name, role/title, and the\",\n      \"     employing company (usually the vendor) — that the\",\n      \"     `people-profile-analyst` agent can begin research without\",\n      \"     revisiting this software profile\",\n      \"\",\n      \"5. **Avoid duplicates.** Before opening a `company:research` or\",\n      \"   `people:research` issue, verify no existing profile or open\",\n      \"   research issue already covers the candidate:\",\n      \"\",\n      \"   - Vendor: check `<COMPANY_PROFILES_DIR>/` for a matching profile\",\n      \"     file (by derived slug or by searching the directory for the\",\n      \"     company's name). If a profile exists, reuse it as a cross-\",\n      \"     reference only — **do not** open a new `company:research` issue.\",\n      \"   - People: check `<PEOPLE_PROFILES_DIR>/` the same way. If a profile\",\n      \"     exists, reuse it as a cross-reference only — **do not** open a\",\n      \"     new `people:research` issue.\",\n      \"   - Also scan open issues carrying the matching `company:research`\",\n      \"     or `people:research` label so this phase never re-opens research\",\n      \"     that is already queued.\",\n      \"\",\n      \"6. **Exercise restraint — people only.** The vendor company always\",\n      \"   qualifies (duplicate check aside). For people, only enqueue\",\n      \"   downstream research when the person has **primary attribution**\",\n      \"   for the product:\",\n      \"\",\n      \"   - Founders, co-founders, and the current CEO of the vendor\",\n      \"   - Principal creators, lead maintainers, or the original author\",\n      \"     of the product (for open-source or single-creator software)\",\n      \"   - The head of product or the lead PM when the profile clearly\",\n      \"     identifies them as driving the product's direction\",\n      \"\",\n      \"   Do **not** open a `people:research` issue for every name on the\",\n      \"   vendor's about page, every engineer quoted in a blog post, every\",\n      \"   investor, or every advisor. When in doubt, leave the candidate\",\n      \"   as a markdown cross-reference in the profile and skip the\",\n      \"   downstream issue.\",\n      \"\",\n      \"7. **Assume the peers are present.** This pipeline assumes the\",\n      \"   `company-profile` and `people-profile` bundles are enabled in the\",\n      \"   consuming project. If a consuming project has disabled one of\",\n      \"   them, flag the followup issue with `status:needs-attention` and\",\n      \"   list the candidates that could not be routed — never invent an\",\n      \"   alternative label taxonomy.\",\n      \"\",\n      \"8. **Cross-link** — update the profile's `## Follow-up Candidates`\",\n      \"   section so each entry (adjacent product, vendor, or person)\",\n      \"   references either the linked profile path (for existing profiles)\",\n      \"   or the newly-created downstream issue number (for candidates that\",\n      \"   were enqueued for research).\",\n      \"\",\n      \"9. **Commit and push** (if the profile was updated). Close the\",\n      `   followup issue ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Output Boundaries\",\n      \"\",\n      \"This agent writes **only** to:\",\n      \"\",\n      \"- `<NOTES_DIR>/` — research-notes files (Phase 1)\",\n      \"- `<PROFILES_DIR>/` — software profiles (Phase 2, updated in later\",\n      \"  phases including the `## Capability Mapping` section in Phase 4)\",\n      \"- `<MATRIX_FILE>` — shared feature matrix (Phase 3)\",\n      \"\",\n      \"In Phase 4, this agent **creates `bcm:outline` issues** for every\",\n      \"unmapped feature that meets the `<UNMAPPED_THRESHOLD>` so the\",\n      \"`bcm-writer` bundle can author the new sub-capability. It never\",\n      \"authors BCM capability-model documents itself.\",\n      \"\",\n      \"In Phase 5, this agent also **creates `company:research` and\",\n      \"`people:research` issues** for the vendor company and primary-\",\n      \"attribution people surfaced in the profile that are not already\",\n      \"tracked under `<COMPANY_PROFILES_DIR>/` or `<PEOPLE_PROFILES_DIR>/`.\",\n      \"It never writes the downstream profiles themselves — those are the\",\n      \"responsibility of the `company-profile-analyst` and\",\n      \"`people-profile-analyst` agents, which pick up the issues this\",\n      \"pipeline creates.\",\n      \"\",\n      \"The pipeline produces **software profiles, notes, matrix rows, and capability mappings**.\",\n      \"Deeper research on adjacent products is delegated to new cycles of\",\n      \"this same pipeline via `software:research` issues. New BCM\",\n      \"sub-capabilities for unmapped features are delegated to the\",\n      \"`bcm-writer` bundle via `bcm:outline` issues. Deeper research on\",\n      \"the vendor company and primary-attribution people is delegated to\",\n      \"the `company-profile` and `people-profile` bundles via\",\n      \"`company:research` and `people:research` issues. This agent never\",\n      \"writes BCM documents, company profiles, person profiles, formal\",\n      \"requirement documents, or comparative long-form analyses itself.\",\n      \"Keep this boundary clean so the software-profile pipeline stays\",\n      \"generic.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Rules\",\n      \"\",\n      \"- **One product per session.** Never profile two products back-to-back.\",\n      \"- **Persist before closing.** Every phase must write its output file\",\n      \"  before closing its issue.\",\n      \"- **Cite everything.** Profile claims without source citations do not\",\n      \"  belong in the deliverable.\",\n      \"- **No invented weights.** Segment weights come from\",\n      `  \\`${paths.docsRoot}/project-context.md\\` or an explicit issue-body override. If`,\n      \"  neither is available, fall back to the single-segment default and\",\n      \"  flag the gap — never guess.\",\n      \"- **Delegate, don't duplicate.** Unmapped capabilities are handed off\",\n      \"  to the `bcm-writer` bundle via `bcm:outline` issues in Phase 4.\",\n      \"  The vendor company and primary-attribution people surfaced during\",\n      \"  profiling are handed off to the `company-profile` and\",\n      \"  `people-profile` bundles via `company:research` and\",\n      \"  `people:research` issues in Phase 5 — never inlined as BCM\",\n      \"  documents, company profiles, or person profiles in this pipeline.\",\n      \"- **Check before enqueueing.** Before opening a `bcm:outline`,\",\n      \"  `company:research`, or `people:research` issue, verify no existing\",\n      \"  document or open issue already covers the candidate. Reuse\",\n      \"  existing BCM documents and profiles as cross-references rather\",\n      \"  than re-queuing work.\",\n      \"- **Respect the threshold.** Phase 4 opens `bcm:outline` issues only\",\n      \"  when the count of unmapped features on a single profile meets or\",\n      \"  exceeds `<UNMAPPED_THRESHOLD>`. The default is `1` — one unmapped\",\n      \"  feature triggers one outline issue. Raise the threshold in the\",\n      \"  invoking issue body or in the consuming project's\",\n      \"  `agentConfig.rules` when the default is too noisy.\",\n      \"- **Restrain the queue — people only.** The vendor company always\",\n      \"  qualifies (duplicate check aside). For people, only enqueue\",\n      \"  research for those with **primary attribution** — founders, the\",\n      \"  current CEO, principal creators, lead maintainers, or the head of\",\n      \"  product. Do not open issues for every name on the vendor's about\",\n      \"  page, every investor, or every advisor.\",\n      \"- **Produce profiles, matrix rows, and capability mappings — not\",\n      \"  BCM documents, requirement documents, or evaluation documents.**\",\n      \"  Do not open `type:requirement` or formal evaluation issues from\",\n      \"  this pipeline, and never author BCM capability-model documents\",\n      \"  inline. Follow-up work is scoped through `software:research`,\",\n      \"  `bcm:outline`, `company:research`, and `people:research` only.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off a software profile cycle. */\nfunction buildProfileSoftwareSkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"profile-software\",\n    description:\n      \"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.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"software-profile-analyst\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Profile Software\",\n      \"\",\n      \"Kick off a software-profile pipeline. Creates a `software:research`\",\n      \"issue carrying the product name, type, and framing, then dispatches\",\n      \"Phase 1 (Research) in the software-profile-analyst agent.\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/profile-software <product-name>\",\n      \"\",\n      \"Optional extensions in the issue body:\",\n      \"- `type: <competitor | adjacent | incumbent | enabler |\",\n      \"   infrastructure | ecosystem-tool>` — override the default type\",\n      \"   inference\",\n      \"- `website: <url>` — canonical website if not obvious from the name\",\n      \"- `framing: <text>` — why this profile was requested and what to learn\",\n      \"- `slug: <kebab-case>` — override the derived product slug\",\n      \"- `weights: <table>` — override the segment-importance weights for\",\n      \"  this profile cycle (otherwise loaded from\",\n      `  \\`${paths.docsRoot}/project-context.md\\`)`,\n      \"- `unmapped_threshold: <n>` — override the Phase 4 threshold for\",\n      \"  opening `bcm:outline` issues (default `1` — one unmapped feature\",\n      \"  triggers one outline issue)\",\n      \"- `sources: <list>` — additional authorized sources beyond public web\",\n      \"\",\n      \"## Default Paths\",\n      \"\",\n      `If the project has no override in \\`${paths.docsRoot}/project-context.md\\` or`,\n      \"`agentConfig.rules`, outputs land under:\",\n      \"\",\n      `- \\`${paths.softwareRoot}/notes/<slug>.notes.md\\``,\n      `- \\`${paths.softwareRoot}/profiles/<slug>.md\\``,\n      `- \\`${paths.softwareRoot}/feature-matrix.md\\` (shared across all products)`,\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `software:research` issue with `type:software-profile`,\",\n      `   \\`priority:${labelsForPhase(issueDefaults, \"software:research\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"software:research\").status}\\`. Body must include the`,\n      \"   product name, selected type, framing, and any overrides.\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 1 (Research) of the software-profile-analyst\",\n      \"   agent.\",\n      \"3. Phase 1 creates the `software:profile` issue. Phase 2 creates\",\n      \"   the `software:matrix` issue. Phase 3 creates the `software:map`\",\n      \"   issue. Phase 4 creates the `software:followup` issue (unless the\",\n      \"   profile surfaced zero follow-ups). Each downstream issue\",\n      \"   declares its `Depends on:` predecessor.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- A research-notes file under the project's notes directory\",\n      \"- A single software profile under the profiles directory, including\",\n      \"  a `## Capability Mapping` section written in Phase 4\",\n      \"- One or more rows appended to the shared feature-matrix file,\",\n      \"  scored against the configured segment weights\",\n      \"- `bcm:outline` issues for each unmapped feature above the\",\n      \"  configured threshold (handed off to the `bcm-writer` bundle)\",\n      \"- Optional follow-up `software:research` issues for adjacent\",\n      \"  products surfaced in the profile\",\n      \"- `company:research` issue for the vendor company (handed off to\",\n      \"  the `company-profile` bundle)\",\n      \"- `people:research` issues for primary-attribution founders, CEOs,\",\n      \"  or principal creators (handed off to the `people-profile`\",\n      \"  bundle)\",\n      \"- This pipeline produces **software profiles, notes, matrix rows,\",\n      \"  and capability mappings** — it does not write BCM documents,\",\n      \"  company profiles, person profiles, or formal requirement\",\n      \"  documents itself.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/**\n * Skill that kicks off a standalone `software:map` session. Useful for\n * profiles that were written before the map phase existed, or when the\n * BCM tree has grown enough that a previously-mapped profile should be\n * re-mapped against the updated capability model.\n */\nfunction buildMapSoftwareSkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"map-software\",\n    description:\n      \"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.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"software-profile-analyst\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Map Software\",\n      \"\",\n      \"Kick off a standalone `software:map` session for a product that\",\n      \"already has a profile file and matrix rows on disk. Creates a\",\n      \"`software:map` issue carrying the profile path and dispatches Phase\",\n      \"4 (Map) in the software-profile-analyst agent.\",\n      \"\",\n      \"Use this skill when:\",\n      \"\",\n      \"- A profile was written before the map phase existed and is still\",\n      \"  carrying the `_Pending capability mapping — filled in Phase 4._`\",\n      \"  placeholder.\",\n      \"- The BCM tree has grown enough that a previously-mapped profile\",\n      \"  should be re-mapped against the updated capability model.\",\n      \"- A profile's features were edited after the map phase ran and the\",\n      \"  mapping table is now out of date.\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/map-software <product-slug-or-profile-path>\",\n      \"\",\n      \"Optional extensions in the issue body:\",\n      \"- `unmapped_threshold: <n>` — override the threshold for opening\",\n      \"  `bcm:outline` issues (default `1`)\",\n      \"- `bcm_doc_root: <path>` — override the BCM document root\",\n      \"  (otherwise the configulator default of\",\n      `  \\`${paths.bcmRoot}\\`)`,\n      \"- `capability_map: <path>` — override the capability-map file\",\n      \"  (otherwise `<BCM_DOC_ROOT>/capability-map.md`)\",\n      \"\",\n      \"## Default Paths\",\n      \"\",\n      `If the project has no override in \\`${paths.docsRoot}/project-context.md\\` or`,\n      \"`agentConfig.rules`, the mapping reads from:\",\n      \"\",\n      `- \\`${paths.bcmRoot}/\\` — BCM capability-model documents`,\n      `- \\`${paths.bcmRoot}/capability-map.md\\` — capability map`,\n      \"\",\n      `and writes back to \\`${paths.softwareRoot}/profiles/<slug>.md\\` under the`,\n      \"`## Capability Mapping` section only. No other section of the\",\n      \"profile is rewritten.\",\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `software:map` issue with `type:software-profile`,\",\n      `   \\`priority:${labelsForPhase(issueDefaults, \"software:map\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"software:map\").status}\\`. Body must include the`,\n      \"   profile path and any overrides.\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 4 (Map) of the software-profile-analyst agent.\",\n      \"3. Phase 4 writes the `## Capability Mapping` section, enqueues\",\n      \"   `bcm:outline` issues for unmapped features above the threshold,\",\n      \"   and — when the profile lists adjacent products or\",\n      \"   primary-attribution people — creates the `software:followup`\",\n      \"   issue.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- An updated `## Capability Mapping` section on the target profile\",\n      \"- `bcm:outline` issues for each unmapped feature above the\",\n      \"  configured threshold (handed off to the `bcm-writer` bundle)\",\n      \"- An optional `software:followup` issue when the profile surfaced\",\n      \"  adjacent products, a vendor company without an existing profile,\",\n      \"  or primary-attribution people\",\n      \"- This skill does not run Phase 1–3 — it assumes the profile and\",\n      \"  matrix rows already exist on disk.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/**\n * Build the software-profile bundle with the supplied resolved paths.\n *\n * Every reference to a canonical agent path (docs root, bcm root)\n * inside the rule / skill / sub-agent content strings is an\n * interpolation of the supplied `paths` struct, so a consumer override\n * of `AgentConfigOptions.paths` propagates to the rendered output.\n *\n * Software-profile bundle — enabled by default.\n *\n * Consuming projects can disable it with\n * `excludeBundles: [\"software-profile\"]`. `appliesWhen` always returns\n * `true` per the operating-system directive that bundles assume peers\n * are present — in Phase 4 this bundle hands work off to `bcm-writer`\n * (via `bcm:outline`) for unmapped features, and in Phase 5 it hands\n * off to `company-profile` (via `company:research`) and `people-profile`\n * (via `people:research`).\n *\n * Ships a sub-agent (`software-profile-analyst`), two user-invocable\n * skills (`/profile-software` and `/map-software`), and\n * `type:software-profile` plus `software:*` phase labels.\n */\nexport function buildSoftwareProfileBundle(\n  paths: ResolvedAgentPaths = DEFAULT_AGENT_PATHS,\n  issueDefaults: ResolvedIssueDefaults = DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n  tier: AgentModel = AGENT_MODEL.BALANCED,\n): AgentRuleBundle {\n  return {\n    name: \"software-profile\",\n    description:\n      \"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.\",\n    appliesWhen: () => true,\n    rules: [\n      {\n        name: \"software-profile-workflow\",\n        description:\n          \"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.\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Software Profile Workflow\",\n          \"\",\n          \"Use `/profile-software <product-name>` to kick off a software\",\n          \"research, profiling, feature-matrix, and capability-mapping\",\n          \"pipeline. The pipeline runs in up to 5 phases — research,\",\n          \"profile, matrix, map, followup — each tracked by its own GitHub\",\n          \"issue labeled `software:research`, `software:profile`,\",\n          \"`software:matrix`, `software:map`, or `software:followup`. All\",\n          \"issues carry `type:software-profile`.\",\n          \"\",\n          \"The pipeline produces **software profiles, research notes, rows\",\n          \"in a shared feature matrix, and capability mappings onto the\",\n          \"BCM tree**. Features are ranked against segment-importance\",\n          `weights declared in \\`${paths.docsRoot}/project-context.md\\``,\n          \"under a `## Segment Weights` section. Features that do not map\",\n          \"to any existing capability in the BCM tree are flagged during\",\n          \"the map phase as candidates for new BCM sub-capabilities and\",\n          \"handed off to the `bcm-writer` bundle via `bcm:outline` issues\",\n          \"(subject to a configurable threshold). Deeper research on\",\n          \"adjacent products surfaced in a profile is delegated to new\",\n          \"cycles of this same pipeline via `software:followup` issues.\",\n          \"Deeper research on the vendor company and primary-attribution\",\n          \"founders/product leaders is delegated to the `company-profile`\",\n          \"and `people-profile` bundles via `company:research` and\",\n          \"`people:research` issues opened during Phase 5 (Followup).\",\n          \"\",\n          \"Use `/map-software <product-slug>` to kick off a standalone\",\n          \"`software:map` session for a profile that already exists on\",\n          \"disk — for example, when the BCM tree has grown enough that a\",\n          \"previously-mapped profile should be re-mapped.\",\n          \"\",\n          \"See the `software-profile-analyst` agent definition for full\",\n          \"workflow details, default paths, the software-type taxonomy,\",\n          \"the segment-weights convention, the capability-mapping format,\",\n          \"and phase-by-phase instructions.\",\n        ].join(\"\\n\"),\n        platforms: {\n          cursor: { exclude: true },\n        },\n        tags: [\"workflow\"],\n      },\n    ],\n    skills: [\n      buildProfileSoftwareSkill(paths, issueDefaults),\n      buildMapSoftwareSkill(paths, issueDefaults),\n    ],\n    subAgents: [\n      buildSoftwareProfileAnalystSubAgent(paths, issueDefaults, tier),\n    ],\n    labels: [\n      {\n        name: \"type:software-profile\",\n        color: \"0E8A16\",\n        description:\n          \"Produces a software profile, research notes, feature-matrix rows, or capability mappings\",\n      },\n      {\n        name: \"software:research\",\n        color: \"C5DEF5\",\n        description:\n          \"Phase 1: gather public sources about a software product into a research-notes file\",\n      },\n      {\n        name: \"software:profile\",\n        color: \"BFDADC\",\n        description:\n          \"Phase 2: write the structured software profile from research notes\",\n      },\n      {\n        name: \"software:matrix\",\n        color: \"D4C5F9\",\n        description:\n          \"Phase 3: extract feature rows into the shared feature matrix and score them against segment weights\",\n      },\n      {\n        name: \"software:map\",\n        color: \"A2EEEF\",\n        description:\n          \"Phase 4: map features to the BCM model and enqueue bcm:outline issues for unmapped features\",\n      },\n      {\n        name: \"software:followup\",\n        color: \"FBCA04\",\n        description:\n          \"Phase 5: enqueue follow-up research for adjacent products, vendor company, and key people\",\n      },\n    ],\n  };\n}\n\n/**\n * Default-paths instance of the software-profile bundle, preserved\n * for backward compatibility with consumers that import the const\n * directly. The factory above is the canonical entry point when a\n * consumer supplies `AgentConfigOptions.paths`.\n */\nexport const softwareProfileBundle: AgentRuleBundle =\n  buildSoftwareProfileBundle();\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { renderClaimVerificationSection } from \"./claim-verification\";\nimport {\n  ISSUE_CLOSE_RULE_REFERENCE,\n  ISSUE_CLOSE_SECTION_TITLE,\n  renderIssueClosePolicySection,\n} from \"./issue-close\";\nimport {\n  DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n  ResolvedIssueDefaults,\n  labelsForPhase,\n} from \"./issue-defaults\";\nimport { renderIssueTypeAssignmentStep } from \"./issue-type\";\nimport { renderOriginStampSection } from \"./origin-label\";\nimport { DEFAULT_AGENT_PATHS, ResolvedAgentPaths } from \"./paths\";\nimport { PROJECT_CONTEXT_READER_SECTION } from \"./project-context\";\nimport {\n  AGENT_MODEL,\n  AGENT_RULE_SCOPE,\n  AgentSkill,\n  AgentSubAgent,\n} from \"../types\";\n\n/**\n * Verbatim comparison-grid template shipped to the consuming project\n * alongside the `/compare-standards` skill. Emitted as\n * `_references/templates/_template-comparison-grid.md` under the skill\n * directory so the compare-phase handler resolves it locally without\n * reaching back into configulator.\n *\n * The template is domain-neutral: it captures the structural shape of a\n * cross-version comparison (version timeline, resource/module maturity\n * progression, breaking changes, migration paths, adoption, regulatory\n * landscape) without hardcoding any specific standard, resource name,\n * regulator, or domain vocabulary. Concrete column values are filled in\n * by the compare phase based on the version pages it synthesizes.\n */\nconst TEMPLATE_COMPARISON_GRID = `---\ntitle: \"<Standard Name>\"\ndescription: \"Overview and cross-version comparison of <Standard Name>.\"\n---\n\n| Field | Value |\n|-------|-------|\n| **Standard** | <standard name> |\n| **Governance body** | <organization> |\n| **Status** | <active / maintenance / superseded> |\n| **Last reviewed** | YYYY-MM-DD |\n\n## Overview\n\n<2–3 paragraphs providing context on the standard, its governance,\nits purpose, and why it matters to the consuming project.>\n\n## Version Timeline\n\n| Version | Publication Date | Status | Key Milestone |\n|---------|------------------|--------|---------------|\n| <v1> | <date> | <normative / trial-use / draft / deprecated> | <milestone> |\n| <v2> | <date> | <status> | <milestone> |\n| <v3> | <date> | <status> | <milestone> |\n\n## Version Comparison\n\n### Module / Resource Maturity Progression\n\nColumns are versions; rows are the logical modules, resources, or\nsub-specifications the standard defines. Maturity values use the\nstandard's own maturity vocabulary (e.g. \\`Normative\\`, \\`Trial Use\\`,\n\\`Draft\\`, \\`Deprecated\\`).\n\n| Module / Resource | <v1> | <v2> | <v3> |\n|-------------------|------|------|------|\n| <name> | <maturity> | <maturity> | <maturity> |\n\n### Breaking Changes Between Versions\n\n| Transition | Breaking Changes | Migration Complexity |\n|------------|------------------|----------------------|\n| <v1> → <v2> | <summary> | <low / medium / high> |\n| <v2> → <v3> | <summary> | <low / medium / high> |\n\n## Migration Paths\n\n### <v1> → <v2>\n\n<Key considerations, tooling available, common pitfalls.>\n\n### <v2> → <v3>\n\n<Key considerations, tooling available, common pitfalls.>\n\n## Regulatory / Conformance Landscape\n\n| Requirement Source | Required Version | Effective Date | Scope |\n|--------------------|------------------|----------------|-------|\n| <regulator or certification body> | <version> | <date> | <what it applies to> |\n\nIf no regulatory drivers exist for this standard, replace this table\nwith \\`Not applicable — no regulatory mandates cite this standard.\\`\n\n## Adoption by Version\n\n| Version | Adoption Level | Primary Users |\n|---------|----------------|---------------|\n| <version> | <widespread / growing / limited / emerging> | <who uses it> |\n\n## Project Relevance\n\n<How the version landscape relates to the consuming project's\ninteroperability needs. Which version(s) must the project support?\nWhat multi-version strategy makes sense? What migration tooling or\nextension work is implied?>\n\n### Recommended Primary Version\n\n<Which version and why.>\n\n### Multi-Version Strategy\n\n<How the project will handle clients, partners, or data sources on\ndifferent versions.>\n\n### Migration Support\n\n<What migration capabilities the project will offer or depend on.>\n\n## Domain Entity Coverage by Version\n\nSummarize which domain entities (Business Objects from capability\nmodels, Key Resources from business-model canvases) are covered by\nthe standard's resources across versions. If no capability models\nor canvases exist yet for the consuming project's domain, replace\nthis section with \\`Pending — domain entity mapping will be completed\nwhen capability models are written.\\`\n\n| Domain Entity | <v1> | <v2> | <v3> | Source Document |\n|---------------|------|------|------|-----------------|\n| <entity> | <resource + maturity> | <resource + maturity> | <resource + maturity> | <relative path> |\n\n## Sources\n\n1. [<Title>](<URL>) — <brief description>\n2. ...\n\n## Revision History\n\n| Date | Author | Changes |\n|------|--------|---------|\n| YYYY-MM-DD | <author> | Initial cross-version comparison |\n`;\n\n/**\n * Reference files emitted alongside the `/compare-standards` SKILL.md.\n * Currently just the comparison-grid template; kept as a\n * `ReadonlyArray` so future reference material (e.g. a migration-\n * complexity rubric) can be added without changing the bundle shape.\n */\nconst STANDARDS_COMPARE_REFERENCE_FILES: ReadonlyArray<{\n  readonly path: string;\n  readonly content: string;\n}> = [\n  {\n    path: \"_references/templates/_template-comparison-grid.md\",\n    content: TEMPLATE_COMPARISON_GRID,\n  },\n];\n\n/**\n * Sub-agent that runs version-aware interoperability standards\n * research, cross-version comparisons, extension/profile analysis,\n * and standards-body organization profiling.\n *\n * The prompt is deliberately domain-neutral. Concrete standard names,\n * version identifiers, resource vocabulary, extension mechanisms,\n * regulators, and industry context come from the invoking issue body,\n * `docs/src/content/docs/project-context.md`, or the consuming\n * project's `agentConfig.rules` — not from the bundle.\n */\nfunction buildStandardsResearchAnalystSubAgent(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSubAgent {\n  return {\n    name: \"standards-research-analyst\",\n    description:\n      \"Authors version-aware interoperability standards research through a 5-phase pipeline (scope → research → compare → extension → organizations). Researches one standard version per session, synthesizes cross-version comparisons, profiles extensions/profiles/implementation guides, and profiles standards-body organizations. Hands off canonical company and people profiles to the company-profile and people-profile bundles via company:research and people:research issues. One phase per session, tracked by standards:* GitHub issue labels with filesystem-based durability between phases.\",\n    model: AGENT_MODEL.POWERFUL,\n    maxTurns: 80,\n    platforms: { cursor: { exclude: true } },\n    prompt: [\n      \"# Standards Research Analyst Agent\",\n      \"\",\n      \"You run a structured interoperability-standards research pipeline:\",\n      \"scope a research campaign for one standard, research each version\",\n      \"independently, synthesize a cross-version comparison, profile known\",\n      \"extensions and implementation guides, and profile the standards-body\",\n      \"organizations that govern and influence the standard. Each phase runs\",\n      \"as its **own agent session**, triggered by a GitHub issue with a\",\n      \"`standards:*` phase label. You handle exactly **one phase per\",\n      \"session** — read the issue to determine which phase to execute.\",\n      \"\",\n      \"This agent is **domain-neutral**. It makes no assumptions about\",\n      \"which interoperability standards matter, which industries they serve,\",\n      \"or what the consuming project's regulatory landscape looks like. All\",\n      \"concrete vocabulary — standard names, version identifiers, resource\",\n      \"taxonomies, extension mechanisms, regulators, and governance bodies —\",\n      \"comes from the invoking issue body,\",\n      `\\`${paths.docsRoot}/project-context.md\\`, or the consuming`,\n      \"project's configuration.\",\n      \"\",\n      \"Follow your project's shared agent conventions (`AGENTS.md`,\",\n      \"`CLAUDE.md`, or equivalent) for all commit, branch, and PR rules.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...PROJECT_CONTEXT_READER_SECTION,\n      \"## Design Principles\",\n      \"\",\n      \"1. **Version-centric.** Each research session focuses on **one**\",\n      \"   standard version. Cross-version comparison is a separate phase\",\n      \"   that synthesizes multiple version pages; never fold comparison\",\n      \"   content into a single version page.\",\n      \"2. **Standards-body awareness.** Standards are shaped by the\",\n      \"   organizations that author, maintain, certify, and regulate them.\",\n      \"   Profiling those organizations is part of the research, not an\",\n      \"   afterthought — the organizations phase exists for this reason.\",\n      \"3. **Adoption-driven.** Document not just what a standard specifies\",\n      \"   but who uses it, how widely it is adopted, what regulatory\",\n      \"   mandates reference it, and what drives or blocks adoption.\",\n      \"4. **Feed the consuming project.** Every finding connects back to\",\n      \"   the consuming project's interoperability needs as declared in\",\n      `   \\`${paths.docsRoot}/project-context.md\\`. Version research`,\n      \"   surfaces which resources, modules, or operations the project must\",\n      \"   support; extension analysis surfaces where the standard does not\",\n      \"   cover the project's domain entities.\",\n      \"5. **Filesystem durability.** Every phase persists its output to a\",\n      \"   file on disk before closing its issue. Downstream phases read\",\n      \"   those files — never rely on session memory.\",\n      \"6. **Issue graph = state machine.** Phase ordering is encoded with\",\n      \"   `Depends on: #N` links between phase issues. Phases run in the\",\n      \"   declared order; comparison runs only after all targeted versions\",\n      \"   are researched.\",\n      \"7. **Generic over specific.** No hardcoded standard names, version\",\n      \"   identifiers, regulators, or industry categories. Use placeholders\",\n      \"   that the invoking issue or consuming project fills in.\",\n      \"8. **Research, not authoring.** This pipeline produces research\",\n      \"   notes, comparison grids, extension analyses, and organization\",\n      \"   profiles. It never writes requirement documents, capability\",\n      \"   models, or canonical profile pages — those are the responsibility\",\n      \"   of the `requirements-writer`, `bcm-writer`, `company-profile`,\",\n      \"   and `people-profile` bundles. Surfaced work is delegated to those\",\n      \"   bundles via issues.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## State Machine Overview\",\n      \"\",\n      \"Standards research flows through **5 phases**:\",\n      \"\",\n      \"```\",\n      \"┌──────────┐   ┌──────────┐   ┌──────────┐   ┌───────────┐   ┌──────────────┐\",\n      \"│ 1. SCOPE │──▶│ 2. RESEA-│   │ 3. COMP- │   │ 4. EXTEN- │   │ 5. ORGANIZA- │\",\n      \"│  Plan    │   │    RCH   │   │    ARE   │   │    SION   │   │     TIONS    │\",\n      \"│  campaign│   │ One      │   │ Versions │   │ Profile   │   │ Profile the  │\",\n      \"│  for a   │   │ version  │   │ side by  │   │ extensions│   │ standards-   │\",\n      \"│  standard│   │ at a     │   │ side;    │   │ / IGs /   │   │ body orgs    │\",\n      \"│          │   │ time;    │   │ migration│   │ profiles  │   │ that govern  │\",\n      \"│          │   │ status,  │   │ paths    │   │ layered on│   │ the standard │\",\n      \"│          │   │ changes, │   │          │   │ the base  │   │              │\",\n      \"│          │   │ adoption │   │          │   │ spec      │   │              │\",\n      \"└──────────┘   └──────────┘   └──────────┘   └───────────┘   └──────────────┘\",\n      \"```\",\n      \"\",\n      \"**Issue labels encode the phase:**\",\n      \"\",\n      \"| Label | Phase | Session work |\",\n      \"|-------|-------|-------------|\",\n      \"| `standards:scope` | 1. Scope | Plan the research campaign for one standard. Write a query plan. Create `standards:research` issues (one per version), the `standards:compare` issue (blocked on research), and `standards:organizations` issues for known governance bodies. No web searches. |\",\n      \"| `standards:research` | 2. Research | Research one version and populate the version page with status, key changes, resources/modules, adoption data, and governance touch-points. 6–10 targeted web searches. |\",\n      \"| `standards:compare` | 3. Compare | Synthesize all researched versions into a cross-version comparison on the standard's overview page. No web searches — pure synthesis from version pages. |\",\n      \"| `standards:extension` | 4. Extension | Analyze extension needs for one domain entity whose base-spec mapping is Partial or Gap. Check community profiles, IGs, and registries. Produce an extension proposal and hand off an ADR to the requirements pipeline. 4–8 targeted web searches. |\",\n      \"| `standards:organizations` | 5. Organizations | Research one standards-body organization's role in the standard. Write a standards-org page. Hand off canonical company and people profiles to the `company-profile` and `people-profile` bundles. 4–8 targeted web searches. |\",\n      \"\",\n      \"All issues also carry `type:standards-research` and a `status:*` label.\",\n      \"\",\n      \"**Issue count for a complete standard:** 1 scope + N research + 1\",\n      \"compare + E extension + M organizations = **2 + N + E + M sessions**.\",\n      \"\",\n      \"**Shortened paths:**\",\n      \"- Research a single version (no full campaign scope) → **1 session**.\",\n      \"- Compare already-researched versions → **1 session**.\",\n      \"- Profile one standards-body organization in isolation → **1 session**.\",\n      \"- Analyze one extension need triggered by a downstream BCM or canvas\",\n      \"  document → **1 session**.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Configurable Paths\",\n      \"\",\n      \"The pipeline uses these placeholders. Consuming projects override the\",\n      \"defaults by passing paths in the skill invocations or by extending\",\n      \"this rule in their own `agentConfig.rules`.\",\n      \"\",\n      \"| Placeholder | Meaning | Default |\",\n      \"|-------------|---------|---------|\",\n      `| \\`<STANDARDS_ROOT>\\` | Root folder for all standards-research documents | \\`${paths.docsRoot}/standards-research/\\` |`,\n      \"| `<STANDARD_DIR>` | Per-standard directory containing the overview, version pages, extensions, and organizations subfolders | `<STANDARDS_ROOT>/<STANDARD_SLUG>/` |\",\n      \"| `<OVERVIEW_PAGE>` | Cross-version overview / comparison grid page | `<STANDARD_DIR>/index.md` |\",\n      \"| `<VERSION_PAGE>` | One-version research page | `<STANDARD_DIR>/<VERSION_SLUG>.md` |\",\n      \"| `<EXTENSIONS_DIR>` | Extension / profile / IG analyses for one standard | `<STANDARD_DIR>/extensions/` |\",\n      \"| `<ORGANIZATIONS_DIR>` | Standards-body organization pages for one standard | `<STANDARD_DIR>/organizations/` |\",\n      `| \\`<SCOPE_DIR>\\` | Query plans written during Phase 1 | \\`${paths.researchRoot}/standards/\\` |`,\n      \"| `<STANDARD_SLUG>` | Short kebab-case slug identifying the standard | derived from the scope issue |\",\n      \"| `<VERSION_SLUG>` | Short kebab-case slug identifying one version | derived from the research issue |\",\n      \"\",\n      `If \\`${paths.docsRoot}/project-context.md\\` specifies a different`,\n      \"standards-research tree, prefer that. Otherwise fall back to the\",\n      \"defaults above.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Agent Loop\",\n      \"\",\n      \"Run this loop exactly once per session. Never start a second issue.\",\n      \"\",\n      \"1. Claim one open `type:standards-research` issue using phase\",\n      \"   priority: `standards:scope` > `standards:research` >\",\n      \"   `standards:compare` > `standards:extension` >\",\n      \"   `standards:organizations`. Within a phase, prefer the oldest\",\n      \"   ready issue (FIFO).\",\n      \"2. Transition `status:ready` → `status:in-progress` and create the\",\n      \"   branch per your project's branch-naming convention.\",\n      \"3. Execute the phase handler that matches the issue's `standards:*`\",\n      \"   label.\",\n      \"4. Commit, push, open a PR (if applicable), and close the issue per\",\n      `   your project's PR workflow — see the **${ISSUE_CLOSE_SECTION_TITLE}**`,\n      \"   section below before you close anything yourself.\",\n      \"   Stamp every PR you open with the `origin:agent` label — see the\",\n      \"   **Origin label** section below.\",\n      \"\",\n      \"---\",\n      \"\",\n      ...renderClaimVerificationSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderOriginStampSection(),\n      \"\",\n      \"---\",\n      \"\",\n      ...renderIssueClosePolicySection(),\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 1: Scope (`standards:scope`)\",\n      \"\",\n      \"**Goal:** Plan the research campaign for a standard — identify which\",\n      \"versions to research, which organizations govern it, and write a\",\n      \"query plan downstream phases will consume.\",\n      \"\",\n      \"**Budget:** No web searches. Reading the consuming project's docs\",\n      \"and existing standards-research pages only. One scope-report file,\",\n      \"plus the downstream research, compare, and organizations issues.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the scope issue body.** Extract:\",\n      \"   - The standard name and `<STANDARD_SLUG>`\",\n      \"   - The list of versions to research (or a request to enumerate\",\n      \"     them during scope)\",\n      \"   - Authorized input paths — prior industry, customer, or\",\n      \"     regulatory research that reference the standard\",\n      \"   - Optional: excluded versions, a target recommendation version,\",\n      \"     or an existing overview page to augment\",\n      \"\",\n      \"2. **Read existing standards-research pages** under\",\n      \"   `<STANDARD_DIR>`. A scope-phase issue may land on top of a\",\n      \"   partially populated tree — stub version pages, a prior overview,\",\n      \"   or organization pages from earlier work. Treat these as inputs,\",\n      \"   not work to redo.\",\n      \"\",\n      \"3. **Read related project context.** Check\",\n      `   \\`${paths.docsRoot}/project-context.md\\` for declared`,\n      \"   interoperability needs, regulatory obligations, and industry\",\n      \"   scope. Check industry-research, customer-research, and\",\n      \"   requirements trees for prior references to the standard.\",\n      \"\",\n      \"4. **Write the query plan** to\",\n      \"   `<SCOPE_DIR>/standards-<STANDARD_SLUG>.query-plan.md`:\",\n      \"\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"Query Plan: <Standard Name>\"',\n      \"   date: YYYY-MM-DD\",\n      \"   parent_issue: <N>\",\n      \"   status: active\",\n      \"   standard: <STANDARD_SLUG>\",\n      \"   ---\",\n      \"\",\n      \"   ## Context\",\n      \"   <1–2 paragraphs on why this standard matters to the consuming\",\n      \"   project and what gaps this research campaign fills.>\",\n      \"\",\n      \"   ## Versions to Research\",\n      \"\",\n      \"   ### Version: <version>\",\n      \"   - **Status:** <stub exists / needs research / complete>\",\n      \"   - **Target page:** <VERSION_PAGE>\",\n      \"   - **Key questions:** <ordered list>\",\n      \"   - **Suggested queries:** <6–10 queries the research phase can\",\n      \"     use as starting points>\",\n      \"\",\n      \"   ## Comparison Topics\",\n      \"   - **Target page:** <OVERVIEW_PAGE>\",\n      \"   - **Comparison dimensions:** <ordered list — version timeline,\",\n      \"     resource maturity, breaking changes, migration paths, adoption,\",\n      \"     regulatory landscape>\",\n      \"\",\n      \"   ## Organizations to Research\",\n      \"   - **Target directory:** <ORGANIZATIONS_DIR>\",\n      \"   - **Key organizations to investigate:** <list — specification\",\n      \"     authors, certification bodies, regulators, notable\",\n      \"     implementers>\",\n      \"   ```\",\n      \"\",\n      \"5. **Create one `standards:research` issue per target version** with\",\n      \"   `Depends on: #<scope-issue>`. Each issue body references the\",\n      \"   query plan, the target version page, and the suggested queries.\",\n      \"\",\n      \"6. **Create the `standards:compare` issue** blocked on **all**\",\n      \"   research issues (`Depends on: #<each research issue>`). Its body\",\n      \"   references the overview page and the comparison dimensions.\",\n      \"\",\n      \"7. **Create one `standards:organizations` issue per known\",\n      \"   governance body** with `Depends on: #<scope-issue>`. These run\",\n      \"   in parallel with research issues — they do not depend on\",\n      \"   research completing.\",\n      \"\",\n      \"8. **Commit and push** the query plan. Close the scope issue\",\n      `   ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 2: Research (`standards:research`)\",\n      \"\",\n      \"**Goal:** Research one version of the standard and populate the\",\n      \"version page with status, key changes, resource/module coverage,\",\n      \"adoption data, and governance touch-points.\",\n      \"\",\n      \"**Budget:** 6–10 targeted web searches. Writing one version page,\",\n      \"creating downstream handoff issues when new organizations or people\",\n      \"are surfaced.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the query plan** at\",\n      \"   `<SCOPE_DIR>/standards-<STANDARD_SLUG>.query-plan.md` for the\",\n      \"   per-version research questions and suggested queries.\",\n      \"\",\n      \"2. **Read the existing version page** at `<VERSION_PAGE>`. Scope\",\n      \"   may have left a stub — fill it in; do not overwrite a populated\",\n      \"   page without carrying forward its content.\",\n      \"\",\n      \"3. **Execute 6–10 web searches** covering:\",\n      \"   - Official specification status and publication timeline\",\n      \"   - Key resources, modules, or sub-specifications introduced\",\n      \"   - Breaking changes from the prior version\",\n      \"   - Implementation guides, profiles, and extension mechanisms\",\n      \"   - Adoption statistics, major implementers, and conformance tools\",\n      \"   - Regulatory mandates or certification requirements that cite\",\n      \"     this version\",\n      \"   - Known limitations and common implementation challenges\",\n      \"\",\n      \"   If a search returns low-quality results, try one reformulated\",\n      \"   query before moving on. Never exceed the 10-search cap.\",\n      \"\",\n      \"4. **Populate the version page** following this structure:\",\n      \"\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"<Standard Name> <Version>\"',\n      '   description: \"Research on <Standard Name> <Version> — status, key changes, resources, and adoption.\"',\n      \"   standard: <STANDARD_SLUG>\",\n      \"   version: <version>\",\n      \"   ---\",\n      \"\",\n      \"   ## Status\",\n      \"   - **Official name:** <name>\",\n      \"   - **Specification status:** <normative / trial-use / draft / ballot>\",\n      \"   - **Publication date:** <date>\",\n      \"   - **Governance timeline:** <brief milestone list>\",\n      \"   - **Current maintenance:** <active / maintenance / superseded>\",\n      \"\",\n      \"   ## Key Changes from <Previous Version>\",\n      \"   <Focus on what matters for implementers, not an exhaustive\",\n      \"   changelog.>\",\n      \"\",\n      \"   ### New Resources / Modules\",\n      \"   | Resource / Module | Category | Description |\",\n      \"   |-------------------|----------|-------------|\",\n      \"\",\n      \"   ### Modified Resources / Modules\",\n      \"   | Resource / Module | Change Type | Description |\",\n      \"   |-------------------|-------------|-------------|\",\n      \"\",\n      \"   ### Removed or Deprecated\",\n      \"   | Resource / Module | Reason |\",\n      \"   |-------------------|--------|\",\n      \"\",\n      \"   ## Resource / Module Maturity\",\n      \"   | Maturity Level | Count | Examples |\",\n      \"   |----------------|-------|----------|\",\n      \"\",\n      \"   ## Implementation Guides and Profiles\",\n      \"   | Guide / Profile | Publisher | Status | Purpose |\",\n      \"   |-----------------|-----------|--------|---------|\",\n      \"\",\n      \"   ## Adoption\",\n      \"\",\n      \"   ### Regulatory / Certification Mandates\",\n      \"   | Source | Requirement | Effective Date | Scope |\",\n      \"   |--------|-------------|----------------|-------|\",\n      \"\",\n      \"   ### Market Adoption\",\n      \"   | System | Support Level | Notes |\",\n      \"   |--------|---------------|-------|\",\n      \"\",\n      \"   ## Known Limitations\",\n      \"   <Common challenges implementers face with this version.>\",\n      \"\",\n      \"   ## Project Relevance\",\n      \"   <How this version relates to the consuming project's\",\n      \"   interoperability needs. Which resources and operations are\",\n      \"   required? What migration considerations exist?>\",\n      \"\",\n      \"   ### Domain Entity Mapping\",\n      \"   Map the standard's resources in this version to domain entities\",\n      \"   (Business Objects discovered in capability models or Key\",\n      \"   Resources from business-model canvases). If no capability models\",\n      '   or canvases exist yet, note \"Pending — no capability model yet\"',\n      \"   and skip the mapping. The `bcm-writer` connect phase fills in\",\n      \"   the reverse mapping when capability models are authored.\",\n      \"\",\n      \"   | Resource | Domain Entity | Source Document | Industry |\",\n      \"   |----------|---------------|-----------------|----------|\",\n      \"\",\n      \"   ## Organizations of Interest\",\n      \"   | Organization | Role | Why Notable | Priority |\",\n      \"   |--------------|------|-------------|----------|\",\n      \"\",\n      \"   ## People of Interest\",\n      \"   | Name | Role | Organization | Why Notable |\",\n      \"   |------|------|--------------|-------------|\",\n      \"\",\n      \"   ## Sources\",\n      \"   1. [<Title>](<URL>) — <description>\",\n      \"   ```\",\n      \"\",\n      \"5. **Create `company:research` issues** for every entry in\",\n      \"   *Organizations of Interest* that does not already have a\",\n      \"   canonical company profile or an open `company:research` issue.\",\n      \"   The `company-profile` bundle owns the downstream profile; this\",\n      \"   agent only hands off. Each issue must carry:\",\n      \"\",\n      \"   - `type:company-profile`\",\n      \"   - `company:research`\",\n      `   - \\`priority:${labelsForPhase(issueDefaults, \"company:research\").priority}\\``,\n      `   - \\`status:${labelsForPhase(issueDefaults, \"company:research\").status}\\``,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"6. **Create `people:research` issues** for every entry in *People of\",\n      \"   Interest* that does not already have a canonical person profile\",\n      \"   or an open `people:research` issue. The `people-profile` bundle\",\n      \"   owns the downstream profile; this agent only hands off. Each\",\n      \"   issue must carry:\",\n      \"\",\n      \"   - `type:people-profile`\",\n      \"   - `people:research`\",\n      `   - \\`priority:${labelsForPhase(issueDefaults, \"people:research\").priority}\\``,\n      `   - \\`status:${labelsForPhase(issueDefaults, \"people:research\").status}\\``,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"7. **Verify all handoffs were created** before committing. For each\",\n      \"   entity in both tables, confirm an existing profile or a fresh\",\n      \"   handoff issue exists. Do not commit with missing handoffs.\",\n      \"\",\n      \"8. **Commit and push** the version page. Close the research issue\",\n      `   ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 3: Compare (`standards:compare`)\",\n      \"\",\n      \"**Goal:** Synthesize all researched versions into a cross-version\",\n      \"comparison on the standard's overview page. Document migration paths,\",\n      \"adoption, and regulatory landscape across versions.\",\n      \"\",\n      \"**Budget:** No web searches — pure synthesis from the existing\",\n      \"version pages. Writes the overview page only.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Verify all target versions are researched.** Before proceeding,\",\n      \"   confirm no `standards:research` issues for this standard are\",\n      \"   still open. If any remain open, block this issue on them and\",\n      \"   stop — do not produce an incomplete comparison.\",\n      \"\",\n      \"2. **Read every version page** under `<STANDARD_DIR>`.\",\n      \"\",\n      \"3. **Read the comparison-grid template** at\",\n      \"   `.claude/skills/compare-standards/_references/templates/_template-comparison-grid.md`.\",\n      \"   The template is authoritative — copy its structure verbatim into\",\n      \"   the overview page, then populate each section from the version\",\n      \"   pages.\",\n      \"\",\n      \"4. **Write the overview page** at `<OVERVIEW_PAGE>`. Follow\",\n      \"   the section-index-page contract in the\",\n      \"   `shared-editing-safety` rule: the body opens with a\",\n      \"   1–2 paragraph contextual summary of the standard and its\",\n      \"   versions, and the version pages, modules, and extensions\",\n      \"   sections below double as the grouped, linked listing of\",\n      \"   every child page in the standard's folder. No body\",\n      \"   `# Heading` — the frontmatter `title:` already renders as\",\n      \"   the page H1. Required sections to fill:\",\n      \"   - **Version Timeline** — publication dates, status, milestones\",\n      \"   - **Module / Resource Maturity Progression** — matrix with\",\n      \"     modules as rows and versions as columns, using the standard's\",\n      \"     own maturity vocabulary\",\n      \"   - **Breaking Changes Between Versions** — one row per adjacent\",\n      \"     transition\",\n      \"   - **Migration Paths** — one subsection per adjacent transition\",\n      \"     with key considerations, tooling, and common pitfalls\",\n      \"   - **Regulatory / Conformance Landscape** — which\",\n      \"     regulations or certifications mandate which version\",\n      \"   - **Adoption by Version** — widespread / growing / limited /\",\n      \"     emerging, with primary users\",\n      \"   - **Project Relevance** — recommended primary version,\",\n      \"     multi-version strategy, migration support\",\n      \"   - **Domain Entity Coverage by Version** — BCM or canvas entity\",\n      '     coverage across versions, or \"Pending — domain entity mapping',\n      '     will be completed when capability models are written\"',\n      \"\",\n      \"   Every factual claim in the overview must trace to a version page\",\n      \"   (via a relative markdown link) or to the query plan. No new web\",\n      \"   research.\",\n      \"\",\n      \"5. **Create `standards:extension` issues** for any domain entity\",\n      \"   whose coverage matrix shows a **Partial** or **Gap** fit. Each\",\n      \"   extension issue cites the overview page, the closest resource\",\n      \"   (if any), and the BCM or canvas document that identified the\",\n      \"   entity. This handoff is optional — if no domain entities show\",\n      \"   gaps, skip it.\",\n      \"\",\n      \"6. **Commit and push** the overview page. Close the compare issue\",\n      `   ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 4: Extension (`standards:extension`)\",\n      \"\",\n      \"**Goal:** Analyze extension needs for **one** domain entity whose\",\n      \"base-spec mapping is Partial or Gap. Determine the appropriate\",\n      \"extension mechanism, check for existing community work, and hand off\",\n      \"an ADR to the requirements pipeline for human decision.\",\n      \"\",\n      \"This phase is **domain-neutral by design**. It applies to any\",\n      \"interoperability standard that provides extension mechanisms —\",\n      \"profiles, extensions, constrained resources, implementation guides,\",\n      \"logical models, or equivalent. Concrete extension vocabulary comes\",\n      \"from the standard itself, not from this bundle.\",\n      \"\",\n      \"**Budget:** 4–8 targeted web searches (community profiles,\",\n      \"implementation guides, extension registries, working-group activity).\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the issue context.** Identify the domain entity, the BCM\",\n      \"   or canvas document that flagged the gap, the closest base-spec\",\n      \"   resource (if any), and what's missing.\",\n      \"\",\n      \"2. **Read the target version page** under `<STANDARD_DIR>` to\",\n      \"   understand the current resource landscape for the version\",\n      \"   targeted by this extension.\",\n      \"\",\n      \"3. **Read the BCM or canvas document** that flagged the gap to\",\n      \"   understand the full domain-entity definition, its attributes, and\",\n      \"   how capabilities consume it.\",\n      \"\",\n      \"4. **Search for existing community work** (4–8 web searches):\",\n      \"   - Published profiles or implementation guides for this entity\",\n      \"   - Extension registries or catalogues maintained by the standards\",\n      \"     body\",\n      \"   - Working-group or community activity in the relevant domain\",\n      \"   - Published logical models or draft proposals\",\n      \"\",\n      \"5. **Analyze the gap** and determine the recommended extension\",\n      \"   approach. Typical approaches (the exact vocabulary depends on\",\n      \"   the standard):\",\n      \"\",\n      \"   | Approach | When to use | Complexity |\",\n      \"   |----------|-------------|------------|\",\n      \"   | **Profile / constrained resource** | Existing resource fits but needs constraints, slicing, or required elements | Low |\",\n      \"   | **Extension element** | Existing resource needs additional data elements not in the base spec | Medium |\",\n      \"   | **Profile + Extension** | Resource partially fits but needs both constraints and new elements | Medium |\",\n      \"   | **Implementation Guide** | A collection of profiles/extensions for a domain use case | High |\",\n      \"   | **Logical model** | No existing resource covers the domain; need to define structure from scratch | High |\",\n      \"\",\n      \"6. **Write the extension analysis** to\",\n      \"   `<EXTENSIONS_DIR>/<entity-slug>.md`:\",\n      \"\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"Extension Analysis: <Domain Entity>\"',\n      '   description: \"Analysis of <Standard Name> extension needs for the <Domain Entity> domain entity.\"',\n      \"   standard: <STANDARD_SLUG>\",\n      \"   version: <version>\",\n      \"   extension-type: profile | extension | profile-extension | ig | logical-model\",\n      '   domain-entity: \"<Domain Entity>\"',\n      \"   closest-resource: \\\"<resource or 'None'>\\\"\",\n      '   industry: \"<industry>\"',\n      \"   ---\",\n      \"\",\n      \"   | Field | Value |\",\n      \"   |-------|-------|\",\n      \"   | **Domain Entity** | <name> |\",\n      \"   | **Industry** | <industry> |\",\n      \"   | **Source BCM / Canvas Document** | <relative path> |\",\n      '   | **Closest Resource** | <resource or \"None\"> |',\n      \"   | **Fit Assessment** | Partial / Gap |\",\n      \"   | **Recommended Approach** | <approach> |\",\n      \"\",\n      \"   ## Gap Analysis\",\n      \"   ### What the Domain Entity Requires\",\n      \"   | Attribute | Description | Data Type | Required? |\",\n      \"   |-----------|-------------|-----------|-----------|\",\n      \"\",\n      \"   ### What the Standard Provides (Closest Resource)\",\n      \"   | Element | Covers Attribute | Fit | Notes |\",\n      \"   |---------|------------------|-----|-------|\",\n      \"\",\n      \"   ### Gap Summary\",\n      \"   | Missing Attribute | Why It's Needed | Extension Mechanism |\",\n      \"   |-------------------|-----------------|---------------------|\",\n      \"\",\n      \"   ## Existing Community Work\",\n      \"   | Resource | Type | Publisher | Status | Relevance |\",\n      \"   |----------|------|-----------|--------|-----------|\",\n      \"\",\n      \"   If no community work exists, replace the table with\",\n      \"   `No existing community profiles or implementation guides found`\",\n      \"   `for this domain entity.`\",\n      \"\",\n      \"   ## Recommended Approach\",\n      \"   **Approach:** <approach>\",\n      \"   **Rationale:** <why this approach fits the gap>\",\n      \"\",\n      \"   ## Project Implementation Considerations\",\n      \"   - **Effort estimate:** <low / medium / high>\",\n      \"   - **Multi-version impact:** <does this extension work across\",\n      \"     versions?>\",\n      \"   - **Conformance testing:** <how to validate implementations>\",\n      \"   - **Community contribution:** <should the consuming project\",\n      \"     contribute this to the standard's community?>\",\n      \"\",\n      \"   ## Traceability\",\n      \"   - **Domain entity source:** [<BCM / canvas doc>](<relative path>)\",\n      \"   - **Standard version:** [<version page>](<relative path>)\",\n      \"   - **Related regulations:** <relative links> (if applicable)\",\n      \"\",\n      \"   ## Sources\",\n      \"   1. [<Title>](<URL>) — <description>\",\n      \"\",\n      \"   ## Revision History\",\n      \"   | Date | Author | Changes |\",\n      \"   |------|--------|---------|\",\n      \"   | YYYY-MM-DD | <author> | Initial extension analysis |\",\n      \"   ```\",\n      \"\",\n      \"7. **Hand off a `Proposed` ADR** for the extension-approach\",\n      \"   decision. The ADR captures the structural decision and\",\n      \"   alternatives for human review. Create a `req:write` issue\",\n      \"   (consumed by the `requirements-writer` bundle) carrying:\",\n      \"   - The ADR category (`architectural-decisions`)\",\n      \"   - A link to this extension analysis\",\n      \"   - A one-line recommendation and the alternatives to weigh\",\n      \"\",\n      \"   The issue-author is the agent; the decision-authority is the\",\n      \"   human who resolves the `Proposed` ADR.\",\n      \"\",\n      \"8. **Create `<EXTENSIONS_DIR>`** if it does not yet exist.\",\n      \"\",\n      \"9. **Commit and push** the extension analysis. Close the extension\",\n      `   issue ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Phase 5: Organizations (`standards:organizations`)\",\n      \"\",\n      \"**Goal:** Research **one** standards-body organization's role in the\",\n      \"standard and write a standards-organization page under\",\n      \"`<ORGANIZATIONS_DIR>`. Hand off canonical company and people profiles\",\n      \"to the `company-profile` and `people-profile` bundles.\",\n      \"\",\n      \"**Budget:** 4–8 targeted web searches.\",\n      \"\",\n      \"### Steps\",\n      \"\",\n      \"1. **Read the query plan** for context on this organization's role.\",\n      \"\",\n      \"2. **Check for existing coverage.** Look under\",\n      \"   `<ORGANIZATIONS_DIR>` for an existing page for this organization.\",\n      \"   Also check the consuming project's company-profile tree for an\",\n      \"   existing canonical profile.\",\n      \"\",\n      \"3. **Execute 4–8 targeted web searches** covering:\",\n      \"   - Organization overview, mission, and legal structure\",\n      \"   - Role in the standard's development and governance\",\n      \"   - Working groups, projects, or initiatives\",\n      \"   - Recent standards-related activity\",\n      \"   - Leadership team and notable contributors\",\n      \"   - Membership model and participation requirements\",\n      \"   - Public positions on standard versions and adoption\",\n      \"   - Relationship to regulatory bodies (if applicable)\",\n      \"\",\n      \"4. **Write the standards-organization page** to\",\n      \"   `<ORGANIZATIONS_DIR>/<org-slug>.md`:\",\n      \"\",\n      \"   ```markdown\",\n      \"   ---\",\n      '   title: \"<Organization Name>\"',\n      '   description: \"<Organization Name>\\'s role in <Standard Name> development and governance.\"',\n      \"   standard: <STANDARD_SLUG>\",\n      \"   ---\",\n      \"\",\n      \"   ## Overview\",\n      \"   <2–3 paragraphs about the organization and its relationship to\",\n      \"   the standard.>\",\n      \"\",\n      \"   ## Role in <Standard Name>\",\n      \"   - **Governance role:** <specification author / working-group\",\n      \"     host / certification body / regulator / major implementer>\",\n      \"   - **Working groups:** <relevant groups or projects>\",\n      \"   - **Key contributions:** <what they've contributed>\",\n      \"\",\n      \"   ## Key Initiatives\",\n      \"   | Initiative | Status | Relevance |\",\n      \"   |------------|--------|-----------|\",\n      \"\",\n      \"   ## Leadership\",\n      \"   | Person | Title | Role in Standard | Profile |\",\n      \"   |--------|-------|------------------|---------|\",\n      \"\",\n      \"   ## Regulatory Influence\",\n      \"   <If applicable, how this organization influences or enforces\",\n      \"   standard adoption through regulation. Otherwise replace with\",\n      \"   `Not applicable — organization has no regulatory role.`>\",\n      \"\",\n      \"   ## Project Relevance\",\n      \"   <How this organization's work affects the consuming project's\",\n      \"   implementation. Certification requirements? Implementation\",\n      \"   guides to follow? Working groups to engage with?>\",\n      \"\",\n      \"   ## Sources\",\n      \"   1. [<Title>](<URL>) — <description>\",\n      \"   ```\",\n      \"\",\n      \"5. **Hand off the canonical company profile** by creating a\",\n      \"   `company:research` issue if no canonical profile exists and no\",\n      \"   open `company:research` issue is already tracking this\",\n      \"   organization. The `company-profile` bundle owns the downstream\",\n      \"   profile. The issue must carry:\",\n      \"\",\n      \"   - `type:company-profile`\",\n      \"   - `company:research`\",\n      `   - \\`priority:${labelsForPhase(issueDefaults, \"company:research\").priority}\\``,\n      `   - \\`status:${labelsForPhase(issueDefaults, \"company:research\").status}\\``,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"6. **Hand off canonical people profiles** by creating one\",\n      \"   `people:research` issue per leadership entry that does not\",\n      \"   already have a canonical profile or an open `people:research`\",\n      \"   issue. The `people-profile` bundle owns the downstream profiles.\",\n      \"   Each issue must carry:\",\n      \"\",\n      \"   - `type:people-profile`\",\n      \"   - `people:research`\",\n      `   - \\`priority:${labelsForPhase(issueDefaults, \"people:research\").priority}\\``,\n      `   - \\`status:${labelsForPhase(issueDefaults, \"people:research\").status}\\``,\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"\",\n      \"7. **Commit and push** the organization page. Close the\",\n      `   organizations issue ${ISSUE_CLOSE_RULE_REFERENCE}.`,\n      \"\",\n      \"---\",\n      \"\",\n      \"## Coordination with Other Agents\",\n      \"\",\n      \"### Upstream: research-pipeline, industry-discovery\",\n      \"\",\n      \"Industry, customer, or research-pipeline deliverables may reference\",\n      \"interoperability standards without scoping them. A `research:scope`\",\n      \"issue can hand off a request for standards research by asking a\",\n      \"human to open a `standards:scope` issue for the relevant standard.\",\n      \"This agent never auto-creates `standards:scope` issues — scope is a\",\n      \"human-authored starting point for the campaign.\",\n      \"\",\n      \"### Downstream: company-profile bundle\",\n      \"\",\n      \"This agent creates `company:research` issues for standards-body\",\n      \"organizations and major implementers surfaced during research\",\n      \"(Phase 2) or profiled in Phase 5. The `company-profile` bundle's\",\n      \"Phase 1 (research) consumes those issues and produces the canonical\",\n      \"profile. This agent never writes canonical company profiles itself.\",\n      \"\",\n      \"### Downstream: people-profile bundle\",\n      \"\",\n      \"This agent creates `people:research` issues for notable individuals\",\n      \"surfaced during research (Phase 2) or profiled in Phase 5. The\",\n      \"`people-profile` bundle's Phase 1 (research) consumes those issues\",\n      \"and produces the canonical profile. This agent never writes canonical\",\n      \"people profiles itself.\",\n      \"\",\n      \"### Downstream: requirements-writer bundle\",\n      \"\",\n      \"Phase 4 (Extension) hands off a `Proposed` ADR to the\",\n      \"`requirements-writer` bundle via a `req:write` issue (category\",\n      \"`architectural-decisions`). The ADR captures the extension-approach\",\n      \"decision and its alternatives for human review. This agent never\",\n      \"writes ADR or requirement documents itself.\",\n      \"\",\n      \"### Downstream: bcm-writer bundle\",\n      \"\",\n      \"Phase 2 (Research) populates a `Domain Entity Mapping` table on each\",\n      \"version page. When the `bcm-writer` connect phase runs against a\",\n      \"BCM document, it fills in the reverse mapping from Business Objects\",\n      \"to resources in this standard. This agent never authors capability\",\n      \"models itself.\",\n      \"\",\n      \"### File Boundaries\",\n      \"\",\n      \"- **Reads:**\",\n      \"  - `<STANDARDS_ROOT>/` — prior version, overview, extension, and\",\n      \"    organization pages\",\n      \"  - `<SCOPE_DIR>/` — query plans\",\n      `  - \\`${paths.docsRoot}/\\` — project context, industry-research,`,\n      \"    customer-research, and requirements trees for framing context\",\n      \"- **Writes:**\",\n      \"  - `<SCOPE_DIR>/standards-<STANDARD_SLUG>.query-plan.md` (Phase 1)\",\n      \"  - `<VERSION_PAGE>` (Phase 2)\",\n      \"  - `<OVERVIEW_PAGE>` (Phase 3)\",\n      \"  - `<EXTENSIONS_DIR>/<entity-slug>.md` (Phase 4)\",\n      \"  - `<ORGANIZATIONS_DIR>/<org-slug>.md` (Phase 5)\",\n      \"- **Never writes to:**\",\n      \"  - Any canonical company-profile or people-profile path (the\",\n      \"    `company-profile` and `people-profile` bundles own those)\",\n      \"  - `<BCM_DOC_ROOT>/` (the `bcm-writer` bundle owns this)\",\n      \"  - `<REQUIREMENTS_ROOT>/` (the `requirements-writer` bundle owns\",\n      \"    this)\",\n      \"  - `<BUSINESS_MODELS_ROOT>/` (the `business-models` bundle owns\",\n      \"    this)\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Blocked Issues\",\n      \"\",\n      \"Follow your project's shared Blocked Issues procedure. Additional\",\n      \"block reasons specific to standards research:\",\n      \"\",\n      \"- **Specification behind a paywall or login.** The agent cannot\",\n      \"  access the authoritative content.\",\n      \"- **Version in active ballot.** Rapidly changing draft content that\",\n      \"  would be out-of-date before the PR merges.\",\n      \"- **Compare issue arrived before research completed.** Phase 3\",\n      \"  blocks on all target-version research issues.\",\n      \"- **Extension gap references a missing BCM or canvas.** Phase 4\",\n      \"  blocks on the upstream BCM or canvas issue.\",\n      \"- **Organization role ambiguous.** The agent cannot determine\",\n      \"  whether the organization is a specification author, certification\",\n      \"  body, regulator, or major implementer without a human decision.\",\n      \"\",\n      \"---\",\n      \"\",\n      \"## Rules\",\n      \"\",\n      \"- **One phase per session.** Never run two phases back-to-back in a\",\n      \"  single session.\",\n      \"- **One version per research session.** Never research multiple\",\n      \"  versions at once — Phase 2 is scoped to exactly one version.\",\n      \"- **Persist before closing.** Every phase must write its output\",\n      \"  file before closing its issue.\",\n      \"- **Search budgets are caps, not targets.** Do not exceed 10\",\n      \"  searches in research or 8 in organizations / extension. Do not\",\n      \"  run any searches in scope or compare.\",\n      \"- **Distinguish normative from trial-use.** Always note the\",\n      \"  maturity level of resources and specification content.\",\n      \"- **Version accuracy.** Be precise about which version introduced\",\n      \"  each change. Do not conflate adjacent versions or published vs.\",\n      \"  draft content.\",\n      \"- **Handoffs before commits.** Before committing a research or\",\n      \"  organizations page, verify every surfaced organization and person\",\n      \"  has either a canonical profile on disk or a fresh handoff issue.\",\n      \"- **No fabrication.** Every claim in a version page, comparison,\",\n      \"  extension analysis, or organization page must trace to a cited\",\n      \"  source. Do not populate from general knowledge alone.\",\n      \"- **Relative links only.** Cross-references between docs use\",\n      \"  relative markdown paths, never absolute `https://github.com/...`\",\n      \"  URLs.\",\n      \"- **Never cross agent boundaries.** Do not write canonical company\",\n      \"  or people profiles, ADRs, requirement documents, or capability\",\n      \"  models. Hand off surfaced work via `company:research`,\",\n      \"  `people:research`, `req:write`, or `bcm:outline` issues.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off the scope phase of a standards-research campaign. */\nfunction buildScopeStandardsResearchSkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"scope-standards-research\",\n    description:\n      \"Kick off the scope phase of an interoperability-standards research campaign. Creates a standards:scope issue for the supplied standard and dispatches Phase 1 of the standards-research-analyst, which writes a query plan and creates downstream standards:research, standards:compare, and standards:organizations issues.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"standards-research-analyst\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Scope Standards Research\",\n      \"\",\n      \"Kick off an interoperability-standards research campaign. Creates a\",\n      \"`standards:scope` issue carrying the standard identifier and any\",\n      \"targeted versions, and dispatches Phase 1 (Scope) in the\",\n      \"standards-research-analyst agent.\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/scope-standards-research <standard-slug>\",\n      \"\",\n      \"Optional extensions in the issue body:\",\n      \"- `standard_name: <human-readable name>` — defaults to the slug\",\n      \"  prettified\",\n      \"- `versions: <list>` — explicit version list to research (otherwise\",\n      \"  the scope phase enumerates them)\",\n      \"- `organizations: <list>` — known governance bodies to profile\",\n      \"- `sources: <list>` — additional authorized input paths (prior\",\n      \"  industry, customer, or regulatory research that references the\",\n      \"  standard)\",\n      \"- `exclude_versions: <list>` — versions to skip\",\n      \"\",\n      \"## Default Paths\",\n      \"\",\n      \"If the project has no override in\",\n      `\\`${paths.docsRoot}/project-context.md\\` or \\`agentConfig.rules\\`,`,\n      \"outputs land under:\",\n      \"\",\n      `- Query plan: \\`${paths.researchRoot}/standards/standards-<standard-slug>.query-plan.md\\``,\n      `- Version pages (Phase 2): \\`${paths.docsRoot}/standards-research/<standard-slug>/<version>.md\\``,\n      `- Overview page (Phase 3): \\`${paths.docsRoot}/standards-research/<standard-slug>/index.md\\``,\n      `- Extension analyses (Phase 4): \\`${paths.docsRoot}/standards-research/<standard-slug>/extensions/<entity-slug>.md\\``,\n      `- Organization pages (Phase 5): \\`${paths.docsRoot}/standards-research/<standard-slug>/organizations/<org-slug>.md\\``,\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `standards:scope` issue with `type:standards-research`,\",\n      `   \\`priority:${labelsForPhase(issueDefaults, \"standards:scope\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"standards:scope\").status}\\`. The body must include the`,\n      \"   standard slug, the list of target versions (or a request to\",\n      \"   enumerate), and any known governance bodies.\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 1 (Scope) of the standards-research-analyst agent.\",\n      \"3. Phase 1 writes the query plan and creates one `standards:research`\",\n      \"   issue per target version, one `standards:compare` issue (blocked\",\n      \"   on the research issues), and one `standards:organizations` issue\",\n      \"   per known governance body.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- A query plan under the project's scope directory, listing per-\",\n      \"  version research questions and suggested queries.\",\n      \"- One `standards:research` issue per target version.\",\n      \"- One `standards:compare` issue blocked on all research issues.\",\n      \"- One `standards:organizations` issue per known governance body.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off the research phase for one version. */\nfunction buildResearchStandardSkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"research-standard\",\n    description:\n      \"Kick off the research phase for one version of an interoperability standard. Creates a standards:research issue for the supplied standard and version and dispatches Phase 2 of the standards-research-analyst, which populates the version page with status, key changes, resources, adoption, and governance touch-points.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"standards-research-analyst\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Research Standard Version\",\n      \"\",\n      \"Author a version page for one version of an interoperability\",\n      \"standard. Creates a `standards:research` issue and dispatches\",\n      \"Phase 2 (Research) in the standards-research-analyst agent.\",\n      \"\",\n      \"Most campaigns do not invoke this skill directly — Phase 1 (Scope)\",\n      \"creates research issues automatically from the query plan. Use this\",\n      \"skill when:\",\n      \"\",\n      \"- A single version needs refreshed research without a full campaign\",\n      \"- A new version was published after the last scope run and needs\",\n      \"  to be folded into the standard's tree\",\n      \"- The scope phase deferred a version and the blocker is now\",\n      \"  resolved\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/research-standard <standard-slug>:<version-slug>\",\n      \"\",\n      \"Optional extensions in the issue body:\",\n      \"- `query_plan: <path>` — prior scope-phase query plan (optional\",\n      \"  when invoked manually)\",\n      \"- `sources: <list>` — additional authorized input paths\",\n      \"\",\n      \"## Default Paths\",\n      \"\",\n      \"If the project has no override in\",\n      `\\`${paths.docsRoot}/project-context.md\\` or \\`agentConfig.rules\\`,`,\n      \"the version page lands at:\",\n      \"\",\n      `\\`${paths.docsRoot}/standards-research/<standard-slug>/<version-slug>.md\\``,\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `standards:research` issue with\",\n      `   \\`type:standards-research\\`, \\`priority:${labelsForPhase(issueDefaults, \"standards:research\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"standards:research\").status}\\`.`,\n      \"   The body must include the standard slug and the version slug.\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 2 (Research) of the standards-research-analyst\",\n      \"   agent. The agent runs 6–10 targeted web searches and populates\",\n      \"   the version page.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- A populated version page with status, key changes, resource /\",\n      \"  module maturity, implementation guides, adoption, regulatory\",\n      \"  mandates, organizations of interest, people of interest, and a\",\n      \"  cited sources section.\",\n      \"- One `company:research` issue per organization surfaced that does\",\n      \"  not already have a canonical profile.\",\n      \"- One `people:research` issue per person surfaced that does not\",\n      \"  already have a canonical profile.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off the compare phase across researched versions. */\nfunction buildCompareStandardsSkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"compare-standards\",\n    description:\n      \"Kick off the compare phase across researched versions of an interoperability standard. Creates a standards:compare issue for the supplied standard and dispatches Phase 3 of the standards-research-analyst, which synthesizes the overview page using the ship-with comparison-grid template.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"standards-research-analyst\",\n    platforms: { cursor: { exclude: true } },\n    referenceFiles: STANDARDS_COMPARE_REFERENCE_FILES,\n    instructions: [\n      \"# Compare Standard Versions\",\n      \"\",\n      \"Synthesize a cross-version comparison for an interoperability\",\n      \"standard whose version pages are already researched. Creates a\",\n      \"`standards:compare` issue and dispatches Phase 3 (Compare) in the\",\n      \"standards-research-analyst agent.\",\n      \"\",\n      \"Most campaigns do not invoke this skill directly — Phase 1 (Scope)\",\n      \"creates the compare issue blocked on the research issues it spawns.\",\n      \"Use this skill when:\",\n      \"\",\n      \"- New version research landed and the overview page needs a\",\n      \"  refresh\",\n      \"- The compare phase was deferred and all target versions are now\",\n      \"  researched\",\n      \"- A human authored the version pages and only needs the overview\",\n      \"  synthesized\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/compare-standards <standard-slug>\",\n      \"\",\n      \"## Comparison-Grid Template\",\n      \"\",\n      \"This skill ships a verbatim comparison-grid template at\",\n      \"`.claude/skills/compare-standards/_references/templates/_template-comparison-grid.md`.\",\n      \"The Phase 3 handler reads that file as its authoritative structure —\",\n      \"every overview page copies the template and fills version timeline,\",\n      \"maturity progression, breaking changes, migration paths, regulatory\",\n      \"landscape, adoption, and project-relevance sections.\",\n      \"\",\n      \"## Default Paths\",\n      \"\",\n      \"If the project has no override in\",\n      `\\`${paths.docsRoot}/project-context.md\\` or \\`agentConfig.rules\\`,`,\n      \"the overview page lands at:\",\n      \"\",\n      `\\`${paths.docsRoot}/standards-research/<standard-slug>/index.md\\``,\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `standards:compare` issue with\",\n      `   \\`type:standards-research\\`, \\`priority:${labelsForPhase(issueDefaults, \"standards:compare\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"standards:compare\").status}\\`.`,\n      \"   Body must include the standard slug and the list of version\",\n      \"   pages under comparison.\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 3 (Compare) of the standards-research-analyst\",\n      \"   agent. No web searches — pure synthesis from the version pages.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- A populated overview page with version timeline, module /\",\n      \"  resource maturity progression, breaking changes, migration paths,\",\n      \"  regulatory landscape, adoption by version, and project-relevance\",\n      \"  recommendations.\",\n      \"- Optional `standards:extension` issues for any domain entity whose\",\n      \"  coverage matrix shows a Partial or Gap fit.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off the extension phase for one domain entity. */\nfunction buildExtensionStandardSkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"extension-standard\",\n    description:\n      \"Kick off the extension phase for one domain entity against an interoperability standard. Creates a standards:extension issue for the supplied standard and domain entity and dispatches Phase 4 of the standards-research-analyst, which analyzes the gap and hands off a Proposed ADR to the requirements pipeline.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"standards-research-analyst\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Analyze Standard Extension\",\n      \"\",\n      \"Analyze the extension mechanism needed to cover one domain entity\",\n      \"whose mapping against an interoperability standard's base\",\n      \"specification is Partial or Gap. Creates a `standards:extension`\",\n      \"issue and dispatches Phase 4 (Extension) in the\",\n      \"standards-research-analyst agent.\",\n      \"\",\n      \"Most campaigns do not invoke this skill directly — it is triggered\",\n      \"by the `bcm-writer` connect phase, the `business-models` canvas\",\n      \"phase, or the standards compare phase (Phase 3). Use this skill\",\n      \"when:\",\n      \"\",\n      \"- A human identified a domain-entity gap and wants the analysis\",\n      \"  authored ahead of the upstream BCM or canvas work\",\n      \"- The upstream agent deferred extension analysis and the gap is\",\n      \"  now well-enough defined to be analyzed\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/extension-standard <standard-slug>:<entity-slug>\",\n      \"\",\n      \"Required extensions in the issue body:\",\n      \"- `domain_entity: <name>` — human-readable entity name\",\n      \"- `closest_resource: <name or 'None'>` — closest base-spec resource\",\n      \"- `source_document: <path>` — BCM or canvas document that flagged\",\n      \"  the gap\",\n      \"- `version: <version-slug>` — target version of the standard\",\n      \"\",\n      \"## Default Paths\",\n      \"\",\n      \"If the project has no override in\",\n      `\\`${paths.docsRoot}/project-context.md\\` or \\`agentConfig.rules\\`,`,\n      \"the extension analysis lands at:\",\n      \"\",\n      `\\`${paths.docsRoot}/standards-research/<standard-slug>/extensions/<entity-slug>.md\\``,\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `standards:extension` issue with\",\n      `   \\`type:standards-research\\`, \\`priority:${labelsForPhase(issueDefaults, \"standards:extension\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"standards:extension\").status}\\`.`,\n      \"   The body must include the standard slug, the entity slug, the\",\n      \"   closest resource, and a link to the source BCM or canvas\",\n      \"   document.\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 4 (Extension) of the standards-research-analyst\",\n      \"   agent. The agent runs 4–8 targeted web searches against\",\n      \"   community registries, implementation guides, and working-group\",\n      \"   activity.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- A populated extension analysis with gap analysis, existing\",\n      \"  community work, recommended approach, rationale, project\",\n      \"  implementation considerations, and a traceability section.\",\n      \"- One `req:write` issue (consumed by the `requirements-writer`\",\n      \"  bundle) handing off a `Proposed` ADR for the extension-approach\",\n      \"  decision.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/** Skill that kicks off the organizations phase for one standards-body. */\nfunction buildOrganizationsStandardSkill(\n  paths: ResolvedAgentPaths,\n  issueDefaults: ResolvedIssueDefaults,\n): AgentSkill {\n  return {\n    name: \"organizations-standard\",\n    description:\n      \"Kick off the organizations phase for one standards-body organization. Creates a standards:organizations issue for the supplied standard and organization and dispatches Phase 5 of the standards-research-analyst, which writes a standards-organization page and hands off canonical company and people profiles to the company-profile and people-profile bundles.\",\n    disableModelInvocation: true,\n    userInvocable: true,\n    context: \"fork\",\n    agent: \"standards-research-analyst\",\n    platforms: { cursor: { exclude: true } },\n    instructions: [\n      \"# Profile Standards Organization\",\n      \"\",\n      \"Research and profile one standards-body organization's role in an\",\n      \"interoperability standard. Creates a `standards:organizations`\",\n      \"issue and dispatches Phase 5 (Organizations) in the\",\n      \"standards-research-analyst agent.\",\n      \"\",\n      \"Most campaigns do not invoke this skill directly — Phase 1 (Scope)\",\n      \"creates one organizations issue per known governance body. Use\",\n      \"this skill when:\",\n      \"\",\n      \"- A new organization surfaced in research needs its own page\",\n      \"- An existing organization page needs a refresh\",\n      \"- A human wants to profile a governance body outside a full\",\n      \"  campaign\",\n      \"\",\n      \"## Usage\",\n      \"\",\n      \"/organizations-standard <standard-slug>:<org-slug>\",\n      \"\",\n      \"Required extensions in the issue body:\",\n      \"- `organization_name: <name>` — human-readable organization name\",\n      \"- `governance_role: <role>` — specification author / certification\",\n      \"  body / regulator / major implementer\",\n      \"\",\n      \"## Default Paths\",\n      \"\",\n      \"If the project has no override in\",\n      `\\`${paths.docsRoot}/project-context.md\\` or \\`agentConfig.rules\\`,`,\n      \"the organization page lands at:\",\n      \"\",\n      `\\`${paths.docsRoot}/standards-research/<standard-slug>/organizations/<org-slug>.md\\``,\n      \"\",\n      \"## Steps\",\n      \"\",\n      \"1. Create a `standards:organizations` issue with\",\n      `   \\`type:standards-research\\`, \\`priority:${labelsForPhase(issueDefaults, \"standards:organizations\").priority}\\`, and \\`status:${labelsForPhase(issueDefaults, \"standards:organizations\").status}\\`.`,\n      \"   Body must include the standard slug, the organization slug, and\",\n      \"   the organization's governance role.\",\n      \"\",\n      ...renderIssueTypeAssignmentStep(),\n      \"2. Execute Phase 5 (Organizations) of the\",\n      \"   standards-research-analyst agent. The agent runs 4–8 targeted\",\n      \"   web searches.\",\n      \"\",\n      \"## Output\",\n      \"\",\n      \"- A populated standards-organization page with overview, role in\",\n      \"  the standard, key initiatives, leadership, regulatory influence,\",\n      \"  project relevance, and a cited sources section.\",\n      \"- One `company:research` issue (consumed by the `company-profile`\",\n      \"  bundle) for the canonical organization profile, when no profile\",\n      \"  exists yet.\",\n      \"- One `people:research` issue (consumed by the `people-profile`\",\n      \"  bundle) per leadership entry that does not already have a\",\n      \"  canonical profile.\",\n    ].join(\"\\n\"),\n  };\n}\n\n/**\n * Build the standards-research bundle with the supplied resolved paths.\n *\n * Every reference to a canonical agent path (docs root, research root,\n * etc.) inside the rule / skill / sub-agent content strings is an\n * interpolation of the supplied `paths` struct, so a consumer override\n * of `AgentConfigOptions.paths` propagates to the rendered output.\n *\n * Consuming projects can disable it with\n * `excludeBundles: [\"standards-research\"]`. `appliesWhen` always\n * returns `true` per the workflow-bundle peer-present assumption.\n *\n * Ships a sub-agent (`standards-research-analyst`), five user-invocable\n * skills (`/scope-standards-research`, `/research-standard`,\n * `/compare-standards`, `/extension-standard`,\n * `/organizations-standard`), a comparison-grid template (emitted\n * alongside the compare skill), and `type:standards-research` plus\n * `standards:*` phase labels.\n *\n * The bundle sits downstream of `research-pipeline` and\n * `industry-discovery` (which surface the need for standards research)\n * and hands off canonical profiles to `company-profile` and\n * `people-profile`, extension ADRs to `requirements-writer`, and\n * domain-entity mappings to `bcm-writer`.\n */\nexport function buildStandardsResearchBundle(\n  paths: ResolvedAgentPaths = DEFAULT_AGENT_PATHS,\n  issueDefaults: ResolvedIssueDefaults = DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n): AgentRuleBundle {\n  return {\n    name: \"standards-research\",\n    description:\n      \"Interoperability-standards research pipeline: scope, research, compare, extension, organizations. 5 phases with standards:* phase labels. Version-aware research, cross-version comparison, extension/profile profiling, and standards-body organization profiling. Hands off canonical profiles to company-profile and people-profile via company:research and people:research issues, extension ADRs to requirements-writer via req:write, and domain-entity mappings to bcm-writer. Enabled by default; domain-neutral; filesystem-durable between phases.\",\n    appliesWhen: () => true,\n    rules: [\n      {\n        name: \"standards-research-workflow\",\n        description:\n          \"Describes the 5-phase standards-research pipeline, the standards:* label taxonomy, and the handoff boundaries with company-profile, people-profile, requirements-writer, and bcm-writer.\",\n        scope: AGENT_RULE_SCOPE.ALWAYS,\n        content: [\n          \"# Standards Research Workflow\",\n          \"\",\n          \"Use `/scope-standards-research <standard-slug>` to kick off an\",\n          \"interoperability-standards research campaign. The pipeline runs\",\n          \"in 5 phases — scope, research, compare, extension, organizations\",\n          \"— each tracked by its own GitHub issue labeled\",\n          \"`standards:scope`, `standards:research`, `standards:compare`,\",\n          \"`standards:extension`, or `standards:organizations`. All issues\",\n          \"carry `type:standards-research`.\",\n          \"\",\n          \"Four additional user-invocable skills drive the downstream\",\n          \"phases directly when the default pipeline needs to be entered\",\n          \"mid-stream:\",\n          \"\",\n          \"- `/research-standard <standard>:<version>` — author one\",\n          \"  version page (normally created by the scope phase\",\n          \"  automatically).\",\n          \"- `/compare-standards <standard>` — synthesize the\",\n          \"  cross-version overview page (normally created by the scope\",\n          \"  phase automatically, blocked on the research issues).\",\n          \"- `/extension-standard <standard>:<entity>` — analyze an\",\n          \"  extension gap for one domain entity and hand off a Proposed\",\n          \"  ADR to the `requirements-writer` bundle.\",\n          \"- `/organizations-standard <standard>:<org>` — profile one\",\n          \"  standards-body organization and hand off canonical company\",\n          \"  and people profiles to the `company-profile` and\",\n          \"  `people-profile` bundles.\",\n          \"\",\n          \"The bundle produces **research notes, comparison grids,\",\n          \"extension analyses, and standards-organization pages**. It\",\n          \"never writes canonical company profiles, people profiles,\",\n          \"requirement documents, capability models, or business-model\",\n          \"canvases — surfaced work is delegated to the `company-profile`,\",\n          \"`people-profile`, `requirements-writer`, and `bcm-writer`\",\n          \"bundles via `company:research`, `people:research`, `req:write`,\",\n          \"and `bcm:outline` issues respectively.\",\n          \"\",\n          \"Consumer-specific standards catalogues (which standards to\",\n          \"research, which versions to target, which governance bodies\",\n          \"to profile) are supplied per-project via\",\n          `\\`${paths.docsRoot}/project-context.md\\` or the invoking`,\n          \"issue body. The bundle is domain-neutral — no standards are\",\n          \"hardcoded.\",\n          \"\",\n          \"See the `standards-research-analyst` agent definition for full\",\n          \"workflow details, default paths, configurable placeholders,\",\n          \"and phase-by-phase instructions.\",\n        ].join(\"\\n\"),\n        platforms: {\n          cursor: { exclude: true },\n        },\n        tags: [\"workflow\"],\n      },\n    ],\n    skills: [\n      buildScopeStandardsResearchSkill(paths, issueDefaults),\n      buildResearchStandardSkill(paths, issueDefaults),\n      buildCompareStandardsSkill(paths, issueDefaults),\n      buildExtensionStandardSkill(paths, issueDefaults),\n      buildOrganizationsStandardSkill(paths, issueDefaults),\n    ],\n    subAgents: [buildStandardsResearchAnalystSubAgent(paths, issueDefaults)],\n    labels: [\n      {\n        name: \"type:standards-research\",\n        color: \"5319E7\",\n        description:\n          \"Researches an interoperability standard: versions, comparison, extension, or org profile\",\n      },\n      {\n        name: \"standards:scope\",\n        color: \"C5DEF5\",\n        description:\n          \"Phase 1: plan a standard's research campaign; write query plan; create downstream issues\",\n      },\n      {\n        name: \"standards:research\",\n        color: \"BFDADC\",\n        description:\n          \"Phase 2: research one version (status, key changes, resources, adoption, governance)\",\n      },\n      {\n        name: \"standards:compare\",\n        color: \"D4C5F9\",\n        description:\n          \"Phase 3: synthesize cross-version comparison: timeline, maturity, breaking changes, migration\",\n      },\n      {\n        name: \"standards:extension\",\n        color: \"FBCA04\",\n        description:\n          \"Phase 4: analyze extension for one Partial/Gap entity; hand off Proposed ADR to requirements\",\n      },\n      {\n        name: \"standards:organizations\",\n        color: \"0E8A16\",\n        description:\n          \"Phase 5: profile one standards-body organization; hand off company/people profile issues\",\n      },\n    ],\n  };\n}\n\n/**\n * Default-paths instance of the standards-research bundle, preserved\n * for backward compatibility with consumers that import the const\n * directly. The factory above is the canonical entry point when a\n * consumer supplies `AgentConfigOptions.paths`.\n */\nexport const standardsResearchBundle: AgentRuleBundle =\n  buildStandardsResearchBundle();\n","import { Project } from \"projen/lib\";\nimport { TurboRepo } from \"../../turbo/turbo-repo\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\nimport { DEFAULT_BUILD_POLICY, ResolvedBuildPolicy } from \"./build-policy\";\nimport { hasComponent } from \"./utils\";\n\n/**\n * Renders the caching bullet of the task-pipeline section.\n *\n * The bundle used to state \"Uses remote caching (requires AWS\n * credentials)\" for every consumer. That is false wherever\n * `remoteCacheOptions` is not configured — those projects cache\n * locally and need no credentials.\n */\nfunction renderCachingBullet(policy: ResolvedBuildPolicy): string {\n  if (policy.remoteCacheEnabled && policy.awsProfileName) {\n    return `- Uses remote caching (requires AWS credentials on the \\`${policy.awsProfileName}\\` profile)`;\n  }\n\n  return \"- Local caching only — no remote cache is configured, so no AWS credentials are required\";\n}\n\n/**\n * Builds the Turborepo bundle — auto-detected when the TurboRepo\n * component is present.\n *\n * When `buildPolicy` is omitted the bundle ships the zero-remote-cache\n * defaults ({@link DEFAULT_BUILD_POLICY}).\n */\nexport function buildTurborepoBundle(\n  buildPolicy: ResolvedBuildPolicy = DEFAULT_BUILD_POLICY,\n): AgentRuleBundle {\n  return {\n    name: \"turborepo\",\n    description: \"Turborepo workspace rules and task pipeline conventions\",\n    appliesWhen: (project: Project) => hasComponent(project, TurboRepo),\n    rules: [\n      {\n        name: \"turborepo-conventions\",\n        description: \"Turborepo build system and task pipeline conventions\",\n        scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n        filePatterns: [\"turbo.json\", \"package.json\"],\n        content: [\n          \"# Turborepo Conventions\",\n          \"\",\n          \"## Build System\",\n          \"\",\n          \"- **Build**: `pnpm build:all` (uses Turborepo)\",\n          \"- **Test**: `pnpm test` or `pnpm test:watch`\",\n          \"- **Lint**: `pnpm eslint`\",\n          \"\",\n          \"## Task Pipeline\",\n          \"\",\n          renderCachingBullet(buildPolicy),\n          \"- Only rebuilds changed packages\",\n          \"- Cache key based on file hashes and dependency graph\",\n          \"- Configured in `turbo.json`\",\n          \"\",\n          \"## Workspace Rules\",\n          \"\",\n          \"- Source files: `src/` directory\",\n          \"- Tests: Co-located with source files (`.spec.ts` or `.test.ts`)\",\n          \"- Exports: Use `index.ts` files for clean public APIs\",\n          \"- Configuration: Managed by Projen (edit `.projenrc.ts` or `projenrc/*.ts`)\",\n        ].join(\"\\n\"),\n        tags: [\"workflow\"],\n      },\n    ],\n    claudePermissions: {\n      allow: [\"Bash(npx turbo:*)\"],\n    },\n  };\n}\n\n/**\n * Turborepo bundle built with the default (no remote cache) build\n * policy. Preserved for backward compatibility with tests and\n * consumers that import the const directly. Prefer\n * `buildTurborepoBundle(buildPolicy)` when the consuming project's\n * Turborepo configuration is in scope.\n */\nexport const turborepoBundle: AgentRuleBundle = buildTurborepoBundle();\n","import { Project } from \"projen/lib\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\nimport { findProjectsWithFile, hasFile } from \"./utils\";\n\n/**\n * TypeScript bundle — auto-detected when a tsconfig is present.\n */\nexport const typescriptBundle: AgentRuleBundle = {\n  name: \"typescript\",\n  description:\n    \"TypeScript conventions, type safety, naming, JSDoc, member ordering\",\n  appliesWhen: (project: Project) => hasFile(project, \"tsconfig.json\"),\n  findApplicableProjects: (project: Project) =>\n    findProjectsWithFile(project, \"tsconfig.json\"),\n  rules: [\n    {\n      name: \"typescript-conventions\",\n      description: \"TypeScript coding conventions and style guide\",\n      scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n      filePatterns: [\"**/*.ts\", \"**/*.tsx\"],\n      content: [\n        \"# TypeScript Conventions\",\n        \"\",\n        \"## Type Safety\",\n        \"\",\n        \"- Use **strict TypeScript** with all strict checks enabled\",\n        \"- Always use explicit types; avoid `any` unless absolutely necessary\",\n        \"- Use `readonly` for immutable properties\",\n        \"- Prefer interfaces over types for object shapes\",\n        \"- Use proper TypeScript types from libraries\",\n        \"\",\n        \"## Code Organization\",\n        \"\",\n        \"- Follow the member ordering rule:\",\n        \"  1. Public static fields/methods\",\n        \"  2. Protected static fields/methods\",\n        \"  3. Private static fields/methods\",\n        \"  4. Instance fields\",\n        \"  5. Constructor\",\n        \"  6. Methods\",\n        \"\",\n        \"## Documentation\",\n        \"\",\n        \"- **Keep JSDoc minimal** so that the code remains human-readable. Use brief summaries only.\",\n        \"- Use JSDoc for:\",\n        \"  - Public classes and interfaces (short description)\",\n        \"  - Public methods and properties (brief purpose; parameter and return when not obvious)\",\n        \"  - Configuration options (one-line description)\",\n        \"- **Extended documentation** belongs in **markdown** files. Link from JSDoc via `@see` or an inline link.\",\n        \"\",\n        \"## Naming Conventions\",\n        \"\",\n        \"- **Classes**: PascalCase (e.g., `TypeScriptProject`, `StaticHosting`)\",\n        \"- **Interfaces**: PascalCase, often with `Props` suffix for configuration (e.g., `StaticHostingProps`)\",\n        \"- **Functions/Methods**: camelCase (e.g., `configureProject`)\",\n        \"- **Constants**: UPPER_SNAKE_CASE (e.g., `VERSION`, `AWS_STAGE_TYPE`)\",\n        \"- **Files**: kebab-case for multi-word files (e.g., `aws-deployment-config.ts`)\",\n        \"- **Component file naming**: kebab-case filename must mirror the PascalCase class name (e.g., `ResetTask` → `reset-task.ts`)\",\n        \"- **Private members**: No prefix needed (TypeScript handles visibility)\",\n        \"\",\n        \"## Array Type Syntax\",\n        \"\",\n        \"- Prefer `Array<T>` over `T[]` for readability\",\n        \"- For nested generics this is especially important: `Array<Array<string>>` is clearer than `string[][]`\",\n        \"\",\n        \"## Enum Preference\",\n        \"\",\n        \"- Prefer `as const` objects over TypeScript `enum` declarations\",\n        \"- `as const` objects are more flexible: they support computed values, work with `keyof typeof`, and tree-shake better\",\n        \"- Example:\",\n        \"  ```typescript\",\n        \"  // Prefer this:\",\n        \"  const Status = { Active: 'active', Inactive: 'inactive' } as const;\",\n        \"  type Status = (typeof Status)[keyof typeof Status];\",\n        \"\",\n        \"  // Over this:\",\n        \"  enum Status { Active = 'active', Inactive = 'inactive' }\",\n        \"  ```\",\n      ].join(\"\\n\"),\n      tags: [\"coding\"],\n    },\n  ],\n  claudePermissions: {\n    allow: [\"Bash(npx tsc:*)\"],\n  },\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\n\n/**\n * Default master switch for the upstream-configulator-docs convention.\n * When no config is supplied, the convention ships **enabled** so every\n * project that consumes `@codedrifters/configulator` carries guidance on\n * how to read configulator's upstream docs and how to file feature\n * requests against `codedrifters/packages` instead of working around\n * gaps in downstream rule overrides.\n *\n * Non-CodeDrifters consumers that do not want to point downstream agents\n * at the `codedrifters/packages` repo can opt out by setting\n * `AgentConfigOptions.upstreamConfigulator.enabled = false`.\n *\n * @see UpstreamConfigulatorConfig\n */\nexport const DEFAULT_UPSTREAM_CONFIGULATOR_ENABLED = true;\n\n/**\n * Concise summary rule body — renders into the consumer's top-level\n * `CLAUDE.md` so brevity matters. Cites the upstream repo, the docs\n * root, the most useful `gh` recipes, and the upstream-issue-first\n * preference, then defers to `upstream-configulator-docs-detail` for\n * the long-form reference.\n */\nconst UPSTREAM_CONFIGULATOR_DOCS_SUMMARY = [\n  \"# Upstream Configulator Docs\",\n  \"\",\n  \"This project consumes `@codedrifters/configulator` from the upstream repository **`codedrifters/packages`**. When you need to understand a configulator behaviour, project type, bundle, or rule, read the upstream docs first — the configulator package in this checkout is generated, not authoritative.\",\n  \"\",\n  \"## Where the docs live\",\n  \"\",\n  \"- **Repository:** `codedrifters/packages`\",\n  \"- **Docs root:** `docs/src/content/docs/`\",\n  \"- **Canonical absolute base URL:**\",\n  \"  <https://github.com/codedrifters/packages/tree/main/docs/src/content/docs/>\",\n  \"\",\n  \"Always link to upstream docs from this repo's CLAUDE.md or `.claude/rules/` using **absolute** GitHub URLs — relative links only work inside a single repo's tree, not across repos.\",\n  \"\",\n  \"## Reading the docs without cloning\",\n  \"\",\n  \"Use the `gh` CLI to read upstream docs from inside this checkout — no clone of `codedrifters/packages` required:\",\n  \"\",\n  \"```sh\",\n  \"# Read one doc by path:\",\n  \"gh api repos/codedrifters/packages/contents/docs/src/content/docs/<path> \\\\\",\n  \"  --jq '.content' | base64 -d\",\n  \"\",\n  \"# List a docs directory:\",\n  \"gh api repos/codedrifters/packages/contents/docs/src/content/docs/<dir> \\\\\",\n  \"  --jq '.[].path'\",\n  \"\",\n  \"# Search docs by keyword:\",\n  \"gh search code --repo codedrifters/packages --filename '*.md' '<query>'\",\n  \"```\",\n  \"\",\n  \"The Contents API returns base64-encoded payloads — `--jq '.content' | base64 -d` is the canonical decode recipe.\",\n  \"\",\n  \"## Upstream-issue-first preference\",\n  \"\",\n  \"When configulator is missing a feature, surfaces a bug, or behaves wrong, **file an issue against `codedrifters/packages`** rather than patching around it locally. Manual downstream overrides in `agentConfig.rules` or `agentConfig.ruleExtensions` are a last resort, not a first response — they fork divergence into every consumer that hits the same gap.\",\n  \"\",\n  \"Use the conventional issue recipe (mirrors the `Create Issue Workflow` in this project's CLAUDE.md):\",\n  \"\",\n  \"```sh\",\n  \"gh issue create --repo codedrifters/packages \\\\\",\n  \"  --title 'feat: <short description>' \\\\\",\n  \"  --label 'type:feat' \\\\\",\n  \"  --label 'priority:medium' \\\\\",\n  \"  --label 'status:ready' \\\\\",\n  \"  --body $'## Summary\\\\n\\\\n<1-3 sentences>\\\\n\\\\n## Details\\\\n\\\\n<context, acceptance criteria, or repro steps>'\",\n  \"```\",\n  \"\",\n  \"Pick the `type:*` and matching prefix that describes the work (`feat:`, `fix:`, `chore:`, `docs:`, `refactor:`). Set `priority:*` from the urgency and use `status:blocked` instead of `status:ready` if the issue depends on another open issue.\",\n  \"\",\n  \"Then set the new issue's **GitHub issue type** — a separate field from the `type:*` label, which `gh issue create` cannot set. Derive it from the title prefix (`epic:` → Epic, `feat:` → Feature, `fix:` → Bug, everything else → Task). The local `.claude/procedures/set-issue-type.sh` helper resolves owner/repo from the **current** checkout, so a cross-repo filing needs the `updateIssueIssueType` GraphQL flow with an explicit owner/repo:\",\n  \"\",\n  \"```sh\",\n  \"gh api graphql -f query='query($owner:String!,$repo:String!){repository(owner:$owner,name:$repo){issueTypes(first:50){nodes{id name}}}}' -f owner=codedrifters -f repo=packages\",\n  \"gh issue view <issue-number> --repo codedrifters/packages --json id --jq '.id'\",\n  \"gh api graphql -f query='mutation($issueId:ID!,$typeId:ID!){updateIssueIssueType(input:{issueId:$issueId,issueTypeId:$typeId}){issue{number issueType{name}}}}' -f issueId=<issue-node-id> -f typeId=<issue-type-node-id>\",\n  \"```\",\n  \"\",\n  \"See `.claude/rules/upstream-configulator-docs-detail.md` for the full reference — extended `gh` recipes, common pitfalls (rate limits, base64 decoding, search vs. browse), and a complete issue-creation walkthrough.\",\n].join(\"\\n\");\n\n/**\n * Detailed reference rule body — renders into\n * `.claude/rules/upstream-configulator-docs-detail.md` and only loads\n * when an agent is editing configulator-aware files (`.projenrc.ts`,\n * `projenrc/**`, `.claude/**`, `CLAUDE.md`). Carries the long-form\n * recipes, common pitfalls, and the full upstream-issue walkthrough.\n */\nconst UPSTREAM_CONFIGULATOR_DOCS_DETAIL = [\n  \"# Upstream Configulator Docs — Detail\",\n  \"\",\n  \"This project depends on `@codedrifters/configulator` for its Projen project types, agent bundles, and generated rules. Configulator itself is developed in the upstream repository **`codedrifters/packages`** — the source of record for project-type defaults, bundle behaviour, rule content, and the agent-config schema.\",\n  \"\",\n  \"When you are editing `.projenrc.ts`, `projenrc/**`, `.claude/**`, or `CLAUDE.md` and need to confirm how a configulator feature works, **read the upstream docs before editing**. Generated files in this checkout are not authoritative; the upstream markdown is.\",\n  \"\",\n  \"## 1. Where configulator's docs live\",\n  \"\",\n  \"- **Upstream repo:** `codedrifters/packages`\",\n  \"- **Docs root inside the repo:** `docs/src/content/docs/`\",\n  \"- **Canonical absolute base URL:**\",\n  \"  <https://github.com/codedrifters/packages/tree/main/docs/src/content/docs/>\",\n  \"\",\n  \"Always cite upstream docs with **absolute** `https://github.com/codedrifters/packages/...` URLs when linking from this consumer's CLAUDE.md or `.claude/rules/`. Relative `../docs/...` links only resolve inside a single repo's tree — they break the moment a downstream agent loads the rule from a different checkout.\",\n  \"\",\n  \"Common doc subtrees (browse the canonical base above for the live tree):\",\n  \"\",\n  \"- `docs/src/content/docs/agents/` — agent bundles, phase contracts, issue templates\",\n  \"- `docs/src/content/docs/components/` — Projen components and project types\",\n  \"- `docs/src/content/docs/requirements/` — requirement documents and ADRs\",\n  \"\",\n  \"## 2. Reading the docs via the GitHub API\",\n  \"\",\n  \"Use `gh` to fetch upstream docs without cloning `codedrifters/packages`. The recipes below run from inside any consumer's checkout.\",\n  \"\",\n  \"### Browse a single doc by path\",\n  \"\",\n  \"```sh\",\n  \"gh api repos/codedrifters/packages/contents/docs/src/content/docs/<path> \\\\\",\n  \"  --jq '.content' | base64 -d\",\n  \"```\",\n  \"\",\n  'The GitHub Contents API returns `{ content: \"<base64>\", encoding: \"base64\", ... }`. The `--jq \\'.content\\'` filter strips the JSON envelope and `base64 -d` decodes the payload to plain Markdown. On macOS the decode flag is `base64 -D` on older `base64` versions — use `base64 -d` (lowercase) on the GNU coreutils install that ships with most modern dev environments.',\n  \"\",\n  \"Example — fetch the agent issue-templates page:\",\n  \"\",\n  \"```sh\",\n  \"gh api repos/codedrifters/packages/contents/docs/src/content/docs/agents/issue-templates.md \\\\\",\n  \"  --jq '.content' | base64 -d\",\n  \"```\",\n  \"\",\n  \"### List a docs directory\",\n  \"\",\n  \"```sh\",\n  \"gh api repos/codedrifters/packages/contents/docs/src/content/docs/<dir> \\\\\",\n  \"  --jq '.[].path'\",\n  \"```\",\n  \"\",\n  \"Lists the immediate children (files and subdirectories) of `<dir>`. Use this to discover what's inside an agents/ or components/ subtree before browsing individual files.\",\n  \"\",\n  \"### Search docs by keyword\",\n  \"\",\n  \"```sh\",\n  \"gh search code --repo codedrifters/packages --filename '*.md' '<query>'\",\n  \"```\",\n  \"\",\n  \"`gh search code` hits the GitHub code-search index and is the right tool when you don't know which file to read. Scope by `--filename '*.md'` to keep results to documentation. Scope further with `--path 'docs/src/content/docs/<subtree>'` when you only care about one section.\",\n  \"\",\n  \"### Common pitfalls\",\n  \"\",\n  \"- **Forgot to base64-decode.** The Contents API never returns plain text — without `base64 -d` you get a base64 blob, not Markdown. Pipe through `base64 -d` every time.\",\n  \"- **Rate limits.** Unauthenticated `gh` calls share a tight per-IP quota. Authenticate with `gh auth login` before running these recipes; an authenticated token gets a 5,000-request hourly quota that is more than enough for interactive doc browsing.\",\n  \"- **Search vs. browse.** `gh search code` is best when you don't know the path. `gh api .../contents/...` is best when you do. Don't search for a path you already know — it's slower and the search index can lag behind the live file by a few minutes.\",\n  \"- **Branch defaults.** All recipes default to the repo's default branch (`main`). To read a doc from a feature branch, append `?ref=<branch>` to the contents-API path: `gh api 'repos/codedrifters/packages/contents/<path>?ref=<branch>' --jq '.content' | base64 -d`.\",\n  \"- **Large directories.** `gh api .../contents/<dir>` truncates responses over 1,000 entries. The `docs/src/content/docs/` subtrees are well under that limit today, but if you ever hit truncation, fall back to the Git Trees API: `gh api repos/codedrifters/packages/git/trees/main?recursive=1 --jq '.tree[] | select(.path | startswith(\\\"docs/src/content/docs/\\\")) | .path'`.\",\n  \"\",\n  \"## 3. Upstream-issue-first preference\",\n  \"\",\n  \"Configulator's rules, bundles, project types, and agent contracts ship for every consumer of the package. When you find a gap or a bug, the right fix is almost always upstream — patching around it locally forks divergence into this consumer and silently denies every other consumer the fix.\",\n  \"\",\n  \"**Default policy:** file an issue against `codedrifters/packages`. Reach for `agentConfig.rules` (new local rule) or `agentConfig.ruleExtensions` (append to a bundle rule) only when the upstream change is non-trivial and you need to unblock immediate work.\",\n  \"\",\n  \"### Canonical issue-creation recipe\",\n  \"\",\n  \"The recipe mirrors the `Create Issue Workflow` documented in this project's CLAUDE.md — same conventional-prefix titles, same `type:*` / `priority:*` / `status:*` label set, same body template — with `--repo codedrifters/packages` so it works from inside any consumer's checkout:\",\n  \"\",\n  \"```sh\",\n  \"gh issue create --repo codedrifters/packages \\\\\",\n  \"  --title '<type>: <short description>' \\\\\",\n  \"  --label '<type-label>' \\\\\",\n  \"  --label '<priority-label>' \\\\\",\n  \"  --label '<status-label>' \\\\\",\n  \"  --body $'## Summary\\\\n\\\\n<1-3 sentences describing the issue>\\\\n\\\\n## Details\\\\n\\\\n<acceptance criteria, repro steps, or context>'\",\n  \"```\",\n  \"\",\n  \"### Title prefix → type label\",\n  \"\",\n  \"Pick exactly one matching pair:\",\n  \"\",\n  \"| Title prefix | `type:*` label | Use for |\",\n  \"|--------------|----------------|---------|\",\n  \"| `feat:` | `type:feat` | New features or functionality |\",\n  \"| `fix:` | `type:fix` | Bug fixes |\",\n  \"| `chore:` | `type:chore` | Maintenance: deps, tooling, config |\",\n  \"| `docs:` | `type:docs` | Documentation-only work |\",\n  \"| `refactor:` | `type:refactor` | Code restructure, no behavior change |\",\n  \"| `release:` | `type:release` | Release preparation, version bumps |\",\n  \"| `hotfix:` | `type:hotfix` | Urgent production fixes |\",\n  \"| `epic:` | `type:feat` | Large initiatives spanning multiple child issues |\",\n  \"\",\n  \"### Priority and status labels\",\n  \"\",\n  \"- `priority:*` — pick exactly one of `priority:critical`, `priority:high`, `priority:medium`, `priority:low`, `priority:trivial`. Default to `priority:medium` when nothing in the request signals urgency. Use `priority:high` for blockers and `priority:critical` only for outages or release-blocking work.\",\n  \"- `status:*` — `status:ready` for self-contained issues, `status:blocked` when the issue declares `Depends on: #<n>` against another open issue.\",\n  \"\",\n  \"### GitHub issue type\",\n  \"\",\n  \"The GitHub **issue type** (Epic / Feature / Bug / Task) is a separate field from the `type:*` label, and `gh issue create` cannot set it. Derive it from the title prefix — `epic:` → Epic, `feat:` → Feature, `fix:` → Bug, everything else → Task — and apply it in a follow-up call. The bundled `.claude/procedures/set-issue-type.sh` helper resolves owner/repo from the **current** checkout, so a cross-repo filing against `codedrifters/packages` uses the `updateIssueIssueType` GraphQL flow with an explicit owner/repo instead:\",\n  \"\",\n  \"```sh\",\n  \"gh api graphql -f query='query($owner:String!,$repo:String!){repository(owner:$owner,name:$repo){issueTypes(first:50){nodes{id name}}}}' -f owner=codedrifters -f repo=packages\",\n  \"gh issue view <issue-number> --repo codedrifters/packages --json id --jq '.id'\",\n  \"gh api graphql -f query='mutation($issueId:ID!,$typeId:ID!){updateIssueIssueType(input:{issueId:$issueId,issueTypeId:$typeId}){issue{number issueType{name}}}}' -f issueId=<issue-node-id> -f typeId=<issue-type-node-id>\",\n  \"```\",\n  \"\",\n  \"### Worked example\",\n  \"\",\n  \"Suppose configulator's `software-profile-analyst` agent prompt is missing a step you need. Instead of forking the prompt locally:\",\n  \"\",\n  \"```sh\",\n  \"gh issue create --repo codedrifters/packages \\\\\",\n  \"  --title 'feat: software-profile-analyst should record vendor pricing tier' \\\\\",\n  \"  --label 'type:feat' \\\\\",\n  \"  --label 'priority:medium' \\\\\",\n  \"  --label 'status:ready' \\\\\",\n  \"  --body $'## Summary\\\\n\\\\nThe `software-profile-analyst` Phase 2 prompt does not capture the vendor pricing tier (free / paid / enterprise), which downstream consumers need for segment matching.\\\\n\\\\n## Details\\\\n\\\\n- Add a `Pricing tier` field to the profile template at `docs/src/content/docs/agents/software-profile-analyst.md`\\\\n- Update the Phase 2 instructions to require the field before commit\\\\n- Add a regression test in `bundles.test.ts`'\",\n  \"```\",\n  \"\",\n  \"The call above does **not** set the GitHub issue type — `gh issue create` cannot. Assign it immediately, in the same session, with the cross-repo GraphQL flow above (`feat:` title → **Feature**; every other prefix except `epic:` / `fix:` → **Task**). Skipping it leaves the upstream issue untyped, and nobody comes back for it later.\",\n  \"\",\n  \"After filing, reference the upstream issue from any local workaround so it can be reverted once the upstream fix lands:\",\n  \"\",\n  \"```typescript\",\n  \"// TODO(codedrifters/packages#<N>): remove this override once upstream lands the fix.\",\n  \"agentConfig: {\",\n  \"  ruleExtensions: {\",\n  \"    'software-profile-analyst': '## Local override\\\\n\\\\n- Capture pricing tier...',\",\n  \"  },\",\n  \"}\",\n  \"```\",\n  \"\",\n  \"### When a local override is the right call\",\n  \"\",\n  \"Reach for `agentConfig.rules` or `agentConfig.ruleExtensions` only when **all** of the following hold:\",\n  \"\",\n  \"- The need is genuinely consumer-specific (not a gap that affects every configulator user).\",\n  \"- An upstream fix would take longer than you can wait, **and** you have already filed the upstream issue with a `TODO(codedrifters/packages#<N>)` reference in the local override.\",\n  \"- The override is small enough that diverging from upstream for a few days is cheaper than blocking on the upstream change.\",\n  \"\",\n  \"Anything that fails one of those tests belongs upstream first. The `# Reference Documentation` rule in this project's CLAUDE.md says it explicitly: trust the project sources and ask for clarification — that protocol extends across repo boundaries to `codedrifters/packages` for anything configulator owns.\",\n].join(\"\\n\");\n\n/**\n * Upstream-configulator-docs bundle — always-on by default. Ships two\n * rules: an `ALWAYS`-scoped rule that renders into CLAUDE.md as a\n * top-level reminder that the project consumes\n * `@codedrifters/configulator` and where its upstream docs live, plus a\n * `FILE_PATTERN`-scoped detail rule that renders into\n * `.claude/rules/upstream-configulator-docs-detail.md` for agents\n * working on configulator-aware files.\n *\n * The bundle is gated by `AgentConfigOptions.upstreamConfigulator.enabled`\n * (default `true`). When the consumer flips it to `false`,\n * `AgentConfig.resolveRules` drops every rule whose name starts with\n * `upstream-configulator-docs` so non-CodeDrifters consumers that do\n * not want the upstream-pointer guidance opt out cleanly.\n */\nexport const upstreamConfigulatorDocsBundle: AgentRuleBundle = {\n  name: \"upstream-configulator-docs\",\n  description:\n    \"Pointers to @codedrifters/configulator's upstream docs and the upstream-issue protocol for missing features. Gated by AgentConfigOptions.upstreamConfigulator.enabled (default true).\",\n  appliesWhen: () => true,\n  rules: [\n    {\n      name: \"upstream-configulator-docs\",\n      description:\n        \"Top-level reminder that the project consumes @codedrifters/configulator and where the upstream docs live\",\n      scope: AGENT_RULE_SCOPE.ALWAYS,\n      content: UPSTREAM_CONFIGULATOR_DOCS_SUMMARY,\n      tags: [\"project\"],\n    },\n    {\n      name: \"upstream-configulator-docs-detail\",\n      description:\n        \"Detailed protocol for reading @codedrifters/configulator upstream docs and filing upstream issues\",\n      scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n      filePatterns: [\".projenrc.ts\", \"projenrc/**\", \".claude/**\", \"CLAUDE.md\"],\n      content: UPSTREAM_CONFIGULATOR_DOCS_DETAIL,\n      tags: [\"project\"],\n    },\n  ],\n};\n","import { Component } from \"projen\";\nimport { Jest, NodeProject } from \"projen/lib/javascript\";\nimport { TextFile } from \"projen/lib/textfile\";\nimport { PnpmWorkspace } from \"../pnpm\";\nimport { VERSION } from \"../versions\";\n\n/**\n * Options for the Vitest config (test block in vitest.config).\n *\n * @see https://vitest.dev/config/\n */\nexport interface VitestConfigOptions {\n  /**\n   * Glob patterns for test files.\n   *\n   * @default `[\"**\\/*.{test,spec}.?(c|m)[jt]s?(x)\"]`\n   */\n  readonly include?: string[];\n\n  /**\n   * Glob patterns to exclude from test files.\n   *\n   * @default [\"**\\/node_modules\\/**\", \"**\\/dist\\/**\", \"**\\/lib\\/**\", \"**\\/.?\\*\"]\n   */\n  readonly exclude?: string[];\n\n  /**\n   * Test environment.\n   *\n   * @default \"node\"\n   */\n  readonly environment?: \"node\" | \"jsdom\" | \"happy-dom\" | \"edge-runtime\";\n\n  /**\n   * Do not fail when no tests are found.\n   *\n   * @default true\n   */\n  readonly passWithNoTests?: boolean;\n\n  /**\n   * Enable coverage collection.\n   *\n   * @default true\n   */\n  readonly coverageEnabled?: boolean;\n\n  /**\n   * Coverage reports directory.\n   *\n   * @default \"coverage\"\n   */\n  readonly coverageDirectory?: string;\n\n  /**\n   * Glob patterns for the files coverage is measured against.\n   *\n   * Rendered as `coverage.include`, which Vitest 4 requires: it ships no\n   * default, and coverage with none set silently measures nothing — the\n   * report comes back empty and summarises as 100%. Vitest 3's `coverage.all`\n   * (removed in 4) is what used to cover this implicitly.\n   *\n   * Scoping this to the source root also keeps build output (`dist/`, `lib/`)\n   * out of the report, which Vitest 3 got from a default `coverage.exclude`\n   * list that version 4 reduces to `[]`.\n   *\n   * The default carries an explicit script-extension filter because Vitest 4\n   * also removed `coverage.extensions`: a bare `src/**` sweeps every matched\n   * file into AST remapping, and each non-script file (markdown, astro, ...)\n   * logs a PARSE_ERROR during the uncovered-files pass.\n   *\n   * @default [\"src/**\\/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}\"]\n   */\n  readonly coverageInclude?: string[];\n\n  /**\n   * Coverage reporters.\n   *\n   * @default [\"text\", \"lcov\"]\n   */\n  readonly coverageReporters?: string[];\n}\n\n/**\n * Options for the Vitest component.\n */\nexport interface VitestOptions {\n  /**\n   * Config file path.\n   *\n   * @default \"vitest.config.ts\"\n   */\n  readonly configFilePath?: string;\n\n  /**\n   * Vitest config (test block).\n   */\n  readonly config?: VitestConfigOptions;\n\n  /**\n   * Vitest version (overrides VERSION.VITEST_VERSION).\n   *\n   * Normally omitted: where the parent monorepo's pnpm catalog carries a\n   * `vitest` entry, the rendered specifier is `catalog:` and that entry\n   * decides the resolved version. Setting this pins the exact version\n   * instead, bypassing the catalog — prefer bumping the catalog entry.\n   *\n   * @default - the parent monorepo's catalog pin for `vitest`\n   */\n  readonly vitestVersion?: string;\n}\n\n/**\n * Vitest component for Node/TypeScript projects.\n *\n * Adds Vitest as the test runner: devDeps, vitest.config.ts, and test/watch tasks.\n * Incompatible with Jest; use jest: false when constructing the project.\n */\nexport class Vitest extends Component {\n  /**\n   * Find the Vitest component on a project.\n   */\n  public static of(project: NodeProject): Vitest | undefined {\n    const isVitest = (c: Component): c is Vitest => c instanceof Vitest;\n    return project.components.find(isVitest);\n  }\n\n  private readonly configFilePath: string;\n  private readonly include: string[];\n  private readonly exclude: string[];\n  private readonly environment: string;\n  private readonly passWithNoTests: boolean;\n  private readonly coverageEnabled: boolean;\n  private readonly coverageDirectory: string;\n  private readonly coverageReporters: string[];\n  private readonly coverageInclude: string[];\n\n  constructor(\n    public readonly project: NodeProject,\n    options: VitestOptions = {},\n  ) {\n    super(project);\n\n    this.configFilePath = options.configFilePath ?? \"vitest.config.ts\";\n    const config = options.config ?? {};\n    this.include = config.include ?? [\"**/*.{test,spec}.?(c|m)[jt]s?(x)\"];\n    this.exclude = config.exclude ?? [\n      \"**/node_modules/**\",\n      \"**/dist/**\",\n      \"**/lib/**\",\n      \"**/.?*\",\n    ];\n    this.environment = config.environment ?? \"node\";\n    this.passWithNoTests = config.passWithNoTests ?? true;\n    this.coverageEnabled = config.coverageEnabled ?? true;\n    this.coverageDirectory = config.coverageDirectory ?? \"coverage\";\n    this.coverageReporters = config.coverageReporters ?? [\"text\", \"lcov\"];\n    this.coverageInclude = config.coverageInclude ?? [\n      \"src/**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}\",\n    ];\n\n    /**\n     * Resolve the pin from the parent monorepo's pnpm catalog when it carries\n     * a `vitest` entry, so the catalog stays the single place the version\n     * moves. An explicit `vitestVersion` still wins — unlike `AwsCdkProject`,\n     * this component treats the option as a supported escape hatch rather\n     * than a conflict to reject, because consumers use it to step off the\n     * default pin without forking the catalog.\n     *\n     * With no catalog behind it, `catalog:` resolves to nothing and pnpm\n     * fails on a protocol error, so fall back to rendering the version\n     * literally.\n     */\n    const catalogVersion = PnpmWorkspace.of(project)?.defaultCatalog?.vitest;\n    const specifier =\n      options.vitestVersion === undefined && catalogVersion !== undefined\n        ? \"catalog:\"\n        : (options.vitestVersion ?? VERSION.VITEST_VERSION);\n\n    project.addDevDeps(`vitest@${specifier}`);\n    if (this.coverageEnabled) {\n      /**\n       * `@vitest/coverage-v8` declares an exact `vitest` peer dependency, so\n       * it tracks the same specifier rather than a range of its own.\n       */\n      project.addDevDeps(`@vitest/coverage-v8@${specifier}`);\n    }\n\n    const coveragePath = `/${this.coverageDirectory}/`;\n    project.gitignore.addPatterns(coveragePath);\n    project.npmignore?.exclude(coveragePath);\n\n    this.addTestTasks();\n    this.synthesizeConfig();\n  }\n\n  public override preSynthesize(): void {\n    super.preSynthesize();\n    for (const component of this.project.components) {\n      if (component instanceof Jest) {\n        throw new Error(\"Vitest cannot be used together with Jest\");\n      }\n    }\n  }\n\n  private addTestTasks(): void {\n    // No receiveArgs so CI/turbo build:all always get a single run (no watch).\n    // --update matches Jest's --updateSnapshot: updates snapshots when they mismatch.\n    this.project.testTask.exec(\"vitest run --update\");\n\n    if (!this.project.tasks.tryFind(\"test:watch\")) {\n      this.project.addTask(\"test:watch\", {\n        description: \"Run tests in watch mode\",\n        exec: \"vitest watch\",\n        receiveArgs: true,\n      });\n    }\n  }\n\n  private synthesizeConfig(): void {\n    this.project.tryRemoveFile(this.configFilePath);\n    new TextFile(this, this.configFilePath, {\n      lines: this.renderConfig(),\n    });\n  }\n\n  private renderConfig(): string[] {\n    return [\n      'import { defineConfig } from \"vitest/config\";',\n      \"\",\n      \"export default defineConfig({\",\n      \"  test: {\",\n      `    include: ${JSON.stringify(this.include)},`,\n      `    exclude: ${JSON.stringify(this.exclude)},`,\n      `    environment: \"${this.environment}\",`,\n      `    passWithNoTests: ${this.passWithNoTests},`,\n      \"    coverage: {\",\n      `      enabled: ${this.coverageEnabled},`,\n      `      provider: \"v8\",`,\n      `      reportsDirectory: \"${this.coverageDirectory}\",`,\n      `      reporter: ${JSON.stringify(this.coverageReporters)},`,\n      `      include: ${JSON.stringify(this.coverageInclude)},`,\n      \"    },\",\n      \"  },\",\n      \"});\",\n    ];\n  }\n}\n","export const VERSION = {\n  /**\n   * Version of `@microsoft/api-extractor` to pin for the docs-sync\n   * public-API drift detection runner. Used by the `ApiExtractor`\n   * component (wired into every `TypeScriptProject`) and the shared\n   * helper at `.claude/procedures/extract-api.sh`. See docs-sync\n   * epic child issue #513.\n   */\n  API_EXTRACTOR_VERSION: \"7.58.7\",\n\n  /**\n   * Version of Astro to pin for AstroProject scaffolding.\n   */\n  ASTRO_VERSION: \"7.3.2\",\n\n  /**\n   * CDK CLI for workflows and command line operations.\n   *\n   * CLI and lib are versioned separately, so this is the CLI version.\n   */\n  AWS_CDK_CLI_VERSION: \"2.1141.0\",\n\n  /**\n   * CDK Version to use for construct projects.\n   *\n   * CLI and lib are versioned separately, so this is the lib version.\n   */\n  AWS_CDK_LIB_VERSION: \"2.269.0\",\n\n  /**\n   * Version of the AWS Constructs library to use.\n   */\n  AWS_CONSTRUCTS_VERSION: \"10.8.1\",\n\n  /**\n   * Version of Node.js to use in CI workflows at github actions.\n   */\n  NODE_WORKFLOWS: \"24\",\n\n  /**\n   * Version of `pnpm/action-setup` to use in GitHub workflows.\n   * Tracks the version projen currently emits (see node_modules/projen/lib/javascript/node-project.js).\n   */\n  PNPM_ACTION_SETUP_VERSION: \"v6.0.5\",\n\n  /**\n   * Version of PNPM to use in workflows at github actions.\n   */\n  PNPM_VERSION: \"12.4.1\",\n\n  /**\n   * Version of Projen to use.\n   */\n  PROJEN_VERSION: \"0.103.23\",\n\n  /**\n   * Version of `actions/setup-node` to use in GitHub workflows.\n   * Tracks the version projen currently emits (see node_modules/projen/lib/github/workflows.js).\n   */\n  SETUP_NODE_ACTION_VERSION: \"v6\",\n\n  /**\n   * Version of sharp to pin for StarlightProject (required peer for\n   * Starlight's image optimization pipeline).\n   */\n  SHARP_VERSION: \"0.35.4\",\n\n  /**\n   * Version of `@astrojs/starlight` to pin for StarlightProject scaffolding.\n   */\n  STARLIGHT_VERSION: \"0.42.0\",\n\n  /**\n   * What version of the turborepo library should we use?\n   */\n  TURBO_VERSION: \"2.10.12\",\n\n  /**\n   * Version of `@types/node` to use across all packages (pnpm catalog).\n   */\n  TYPES_NODE_VERSION: \"26.5.1\",\n\n  /**\n   * What version of Vitest to use when testRunner is 'vitest'.\n   *\n   * Also pins `@vitest/coverage-v8`, whose `vitest` peer dependency is an\n   * exact match rather than a range — the two always move together. Both\n   * packages are seeded into the monorepo's pnpm catalog from this constant,\n   * so `Vitest` renders them as `catalog:` wherever that catalog exists.\n   */\n  VITEST_VERSION: \"5.0.0\",\n} as const;\n","import { Project } from \"projen/lib\";\nimport { Vitest } from \"../../vitest/vitest-component\";\nimport { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE } from \"../types\";\nimport { findProjectsWithComponent, hasComponent } from \"./utils\";\n\n/**\n * Vitest bundle — auto-detected when the Vitest component is present.\n */\nexport const vitestBundle: AgentRuleBundle = {\n  name: \"vitest\",\n  description: \"Vitest testing conventions, patterns, and file scoping\",\n  appliesWhen: (project: Project) => hasComponent(project, Vitest),\n  findApplicableProjects: (project: Project) =>\n    findProjectsWithComponent(project, Vitest),\n  rules: [\n    {\n      name: \"vitest-testing\",\n      description: \"Vitest testing conventions and patterns\",\n      scope: AGENT_RULE_SCOPE.FILE_PATTERN,\n      filePatterns: [\"**/*.test.ts\", \"**/*.spec.ts\"],\n      content: [\n        \"# Vitest Testing Patterns\",\n        \"\",\n        \"## Mandatory Requirements\",\n        \"\",\n        \"- **Tests MUST be created or updated whenever code functionality is added or changed**\",\n        \"- This applies to all code changes, including:\",\n        \"  - New features and functionality\",\n        \"  - Bug fixes\",\n        \"  - Refactoring that changes behavior\",\n        \"  - API changes\",\n        \"  - Configuration changes that affect functionality\",\n        \"- Tests should be written or updated as part of the same change that modifies the code\",\n        \"\",\n        \"## Test Structure\",\n        \"\",\n        \"- Use **Vitest** as the test runner\",\n        \"- Test files: `.spec.ts` or `.test.ts` (co-located with source)\",\n        \"- Use descriptive test names: `describe('ClassName', () => { it('should do something specific', () => {}) })`\",\n        \"- Prefer snapshot tests for complex object structures\",\n        \"- Mock external dependencies appropriately\",\n        \"\",\n        \"## Test Organization\",\n        \"\",\n        \"- Co-locate test files with source files\",\n        \"- Test files can use dev dependencies (ESLint rule override)\",\n        \"- Import from `vitest`: `import { describe, expect, it } from 'vitest'`\",\n        \"\",\n        \"## Example Test Structure\",\n        \"\",\n        \"```typescript\",\n        \"import { describe, expect, it } from 'vitest';\",\n        \"import { MyClass } from './my-class';\",\n        \"\",\n        \"describe('MyClass', () => {\",\n        \"  it('should do something specific', () => {\",\n        \"    // Test implementation\",\n        \"  });\",\n        \"});\",\n        \"```\",\n      ].join(\"\\n\"),\n      tags: [\"testing\"],\n    },\n  ],\n  claudePermissions: {\n    allow: [\"Bash(npx vitest:*)\"],\n  },\n};\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_RULE_SCOPE, AgentRule } from \"../types\";\nimport { ResolvedAgentPaths } from \"./paths\";\n\n/**\n * One row in the rendered agent registry table. Each phased-agent\n * bundle that previously shipped its own `<bundle>-workflow` rule\n * contributes exactly one entry here so the registry can answer\n * \"which agent handles X\" without rendering 18 prose summaries\n * into CLAUDE.md.\n */\nexport interface AgentRegistryEntry {\n  /** Bundle name as it appears in `buildBuiltInBundles`, e.g. `bcm-writer`. */\n  readonly bundle: string;\n  /** Primary user-invocable skill, with leading slash, e.g. `/write-bcm`. */\n  readonly skill: string;\n  /** Sub-agent name in `.claude/agents/`, e.g. `bcm-writer`. */\n  readonly agent: string;\n  /**\n   * Function that resolves the canonical output path for this\n   * bundle from the project's resolved agent-path roots. Returning\n   * an empty string signals \"no filesystem output path\" (used by\n   * pr-review). Path-aware so consumer overrides on\n   * `AgentConfigOptions.paths` propagate into the rendered table.\n   */\n  readonly resolveOutputPath: (paths: ResolvedAgentPaths) => string;\n  /**\n   * One-line purpose description. Lifted from the first prose\n   * sentence of the original `<bundle>-workflow` rule so consumers\n   * keep the same routing signal.\n   */\n  readonly purpose: string;\n  /**\n   * Name of the original `<bundle>-workflow` rule. Used by the\n   * registry helper to filter the resolved bundle list and assert\n   * (via the test suite) that no bundle still ships its workflow\n   * rule into the Claude platform output.\n   */\n  readonly workflowRuleName: string;\n}\n\n/**\n * Static registry of every phased-agent bundle that contributes a\n * routing row. Order is alphabetical by bundle name so the\n * rendered table is stable across runs and consumer-side diffs are\n * minimal. Adding a new phased-agent bundle requires appending one\n * row here and suppressing its `<bundle>-workflow` rule via\n * `platforms: { claude: { exclude: true } }`.\n */\nexport const AGENT_REGISTRY_ENTRIES: ReadonlyArray<AgentRegistryEntry> = [\n  {\n    bundle: \"agenda\",\n    skill: \"/draft-agenda\",\n    agent: \"agenda-analyst\",\n    resolveOutputPath: (p) => `${p.meetingsRoot}/`,\n    purpose:\n      \"Pre-meeting agenda authoring (2-phase: draft, finalize). Reuses the project's meeting-type taxonomy.\",\n    workflowRuleName: \"meeting-agenda-workflow\",\n  },\n  {\n    bundle: \"bcm-writer\",\n    skill: \"/write-bcm\",\n    agent: \"bcm-writer\",\n    resolveOutputPath: (p) => `${p.bcmRoot}/`,\n    purpose:\n      \"BCM capability-model documents (4-phase: outline, scaffold, context, connect). BIZBOK-aligned.\",\n    workflowRuleName: \"bcm-writer-workflow\",\n  },\n  {\n    bundle: \"business-models\",\n    skill: \"/scan-business-models\",\n    agent: \"business-models-analyst\",\n    resolveOutputPath: (p) => `${p.docsRoot}/industry-research/`,\n    purpose:\n      \"Osterwalder business-model canvases per industry segment (3-phase: scan, canvas, complete).\",\n    workflowRuleName: \"business-models-workflow\",\n  },\n  {\n    bundle: \"company-profile\",\n    skill: \"/profile-company\",\n    agent: \"company-profile-analyst\",\n    resolveOutputPath: (p) => `${p.companiesRoot}/`,\n    purpose:\n      \"Company profiles, notes, and segment competitive analyses (up to 6 phases incl. refresh).\",\n    workflowRuleName: \"company-profile-workflow\",\n  },\n  {\n    bundle: \"customer-profile\",\n    skill: \"/discover-customers\",\n    agent: \"customer-profile-analyst\",\n    resolveOutputPath: (p) => `${p.profilesRoot}/customers/`,\n    purpose:\n      \"Customer-archetype discovery, profiles, and competitor feature-mapping (3-phase).\",\n    workflowRuleName: \"customer-profile-workflow\",\n  },\n  {\n    bundle: \"docs-sync\",\n    skill: \"/docs-sync-pr\",\n    agent: \"docs-sync\",\n    resolveOutputPath: (p) => `${p.docsRoot}/`,\n    purpose:\n      \"Pre-PR drift detection and mechanical doc fixes (2-phase: scan, fix). Skeleton release.\",\n    workflowRuleName: \"docs-sync-workflow\",\n  },\n  {\n    bundle: \"industry-discovery\",\n    skill: \"/discover-industries\",\n    agent: \"industry-discovery-analyst\",\n    resolveOutputPath: (p) => `${p.industriesRoot}/`,\n    purpose:\n      \"Industry-vertical discovery, fit-evaluation, and research planning (3-phase).\",\n    workflowRuleName: \"industry-discovery-workflow\",\n  },\n  {\n    bundle: \"maintenance-audit\",\n    skill: \"/audit-docs\",\n    agent: \"maintenance-audit\",\n    resolveOutputPath: (p) => `${p.docsRoot}/`,\n    purpose:\n      \"Doc-registry audits with idempotent fixes (3-phase: scan, fix, verify). No new content.\",\n    workflowRuleName: \"maintenance-audit-workflow\",\n  },\n  {\n    bundle: \"meeting-analysis\",\n    skill: \"/process-meeting\",\n    agent: \"meeting-analyst\",\n    resolveOutputPath: (p) => `${p.meetingsRoot}/`,\n    purpose:\n      \"Post-meeting transcript processing (4-phase: extract, notes, draft, link).\",\n    workflowRuleName: \"meeting-processing-workflow\",\n  },\n  {\n    bundle: \"people-profile\",\n    skill: \"/profile-person\",\n    agent: \"people-profile-analyst\",\n    resolveOutputPath: (p) => `${p.peopleRoot}/`,\n    purpose:\n      \"Person profiles only (up to 4 phases incl. refresh). Hands off to company/software bundles.\",\n    workflowRuleName: \"people-profile-workflow\",\n  },\n  {\n    bundle: \"pr-review\",\n    skill: \"/review-pr\",\n    agent: \"pr-reviewer\",\n    resolveOutputPath: () => \"\",\n    purpose:\n      \"PR review, auto-merge gating, and human-in-the-loop feedback orchestration.\",\n    workflowRuleName: \"pr-review-workflow\",\n  },\n  {\n    bundle: \"regulatory-research\",\n    skill: \"/scan-regulatory-landscape\",\n    agent: \"regulatory-research-analyst\",\n    resolveOutputPath: (p) => `${p.docsRoot}/regulations/`,\n    purpose:\n      \"Regulation research, version pages, and impact analysis (3-phase). Documents, never interprets.\",\n    workflowRuleName: \"regulatory-research-workflow\",\n  },\n  {\n    bundle: \"requirements-analyst\",\n    skill: \"/scan-requirements\",\n    agent: \"requirements-analyst\",\n    resolveOutputPath: (p) => `${p.researchRequirementsRoot}/`,\n    purpose:\n      \"Requirements gap discovery + draft proposals (2-phase: scan, draft-trace). Hands off to writer.\",\n    workflowRuleName: \"requirements-analyst-workflow\",\n  },\n  {\n    bundle: \"requirements-reviewer\",\n    skill: \"/review-requirements\",\n    agent: \"requirements-reviewer\",\n    resolveOutputPath: (p) => `${p.requirementsRoot}/`,\n    purpose:\n      \"Requirements audit (12 checks) and narrow-edit deprecation. Never authors new requirement docs.\",\n    workflowRuleName: \"requirements-reviewer-workflow\",\n  },\n  {\n    bundle: \"requirements-writer\",\n    skill: \"/write-requirement\",\n    agent: \"requirements-writer\",\n    resolveOutputPath: (p) => `${p.requirementsRoot}/`,\n    purpose:\n      \"Formal requirement document authoring across the 11-category taxonomy + four-tier classification.\",\n    workflowRuleName: \"requirements-writer-workflow\",\n  },\n  {\n    bundle: \"research-pipeline\",\n    skill: \"/research\",\n    agent: \"research-analyst\",\n    resolveOutputPath: (p) => `${p.researchRoot}/`,\n    purpose:\n      \"Generic research micro-tasks (3-phase: scope, slice, verify). Notes-only output.\",\n    workflowRuleName: \"research-pipeline-workflow\",\n  },\n  {\n    bundle: \"software-profile\",\n    skill: \"/profile-software\",\n    agent: \"software-profile-analyst\",\n    resolveOutputPath: (p) => `${p.softwareRoot}/`,\n    purpose:\n      \"Software profiles, shared feature matrix, and BCM-tree capability mapping (up to 5 phases).\",\n    workflowRuleName: \"software-profile-workflow\",\n  },\n  {\n    bundle: \"standards-research\",\n    skill: \"/scope-standards-research\",\n    agent: \"standards-research-analyst\",\n    resolveOutputPath: (p) => `${p.docsRoot}/standards/`,\n    purpose:\n      \"Interoperability standards research (5-phase: scope, research, compare, extension, organizations).\",\n    workflowRuleName: \"standards-research-workflow\",\n  },\n];\n\n/**\n * The set of `<bundle>-workflow` rule names that the registry\n * subsumes. Used both to suppress those rules from the Claude\n * platform output and to assert in tests that no bundle still\n * ships its prose summary into CLAUDE.md.\n */\nexport const SUPPRESSED_WORKFLOW_RULE_NAMES: ReadonlyArray<string> =\n  AGENT_REGISTRY_ENTRIES.map((e) => e.workflowRuleName);\n\n/**\n * Returns `true` when the supplied rule name belongs to a\n * phased-agent `<bundle>-workflow` rule whose routing summary now\n * lives in the shared `agent-registry` rule.\n */\nexport function isSuppressedWorkflowRule(name: string): boolean {\n  return SUPPRESSED_WORKFLOW_RULE_NAMES.includes(name);\n}\n\n/**\n * Reverse map from a `<bundle>-workflow` rule name to its owning\n * bundle name. Used by the registry consolidation loop to detect\n * when a consumer has targeted a bundle with a\n * `features.customDocSections` entry — those bundles keep\n * rendering their workflow rule into CLAUDE.md so the consumer-\n * supplied prose has somewhere to live. Returns `undefined` for\n * any rule name that is not in the registry's suppression list.\n */\nexport function bundleNameForWorkflowRule(\n  ruleName: string,\n): string | undefined {\n  const entry = AGENT_REGISTRY_ENTRIES.find(\n    (e) => e.workflowRuleName === ruleName,\n  );\n  return entry?.bundle;\n}\n\n/**\n * Build the consolidated agent-registry rule for the supplied\n * resolved bundle list. The helper:\n *\n * 1. Filters `AGENT_REGISTRY_ENTRIES` to bundles that are actually\n *    active in the consumer's resolved bundle set (so a consumer\n *    that excludes `bcm-writer` doesn't see a row for it).\n * 2. Renders one alphabetically-sorted markdown table row per\n *    surviving entry, with skill / agent / bundle / output-path /\n *    purpose columns.\n * 3. Returns a single ALWAYS-scoped `agent-registry` rule whose\n *    body opens with a 2-3 sentence preamble explaining the\n *    routing model and pointing at `.claude/agents/<name>.md` for\n *    full prompts and the cross-cutting convention rules at the\n *    top of CLAUDE.md.\n *\n * Consumers with no phased-agent bundle active receive `undefined`\n * and the rule is dropped from the resolved set — there is no\n * routing to summarise.\n */\n/**\n * Build the ALWAYS-scoped `conventions-registry` rule from the\n * final, post-transform set of rules that will ship to the Claude\n * platform. The registry lists every `FILE_PATTERN`-scoped rule\n * (slug, comma-joined `filePatterns`, one-line description) so an\n * agent whose current file does not happen to match any rule's\n * `paths:` still has a discoverable routing table back into the\n * full convention set under `.claude/rules/`.\n *\n * The helper:\n *\n * 1. Walks every rule currently in the resolved rule map.\n * 2. Filters to `scope === AGENT_RULE_SCOPE.FILE_PATTERN` rules\n *    whose `platforms.claude.exclude` is not `true` — suppressed\n *    rules (e.g. `<bundle>-workflow` rules subsumed by\n *    `agent-registry`) never appear, and ALWAYS-scoped rules are\n *    omitted because they already render in CLAUDE.md.\n * 3. Renders one alphabetically-sorted markdown row per surviving\n *    rule. Each row's first cell links to `.claude/rules/<name>.md`\n *    so a reader can click through. The `Auto-loads when editing`\n *    cell shows up to three `filePatterns`, truncated with `, …`\n *    and pointing at the rule for the full list when there are\n *    more.\n *\n * Returns `undefined` when no FILE_PATTERN rules survive the\n * filter (e.g. a minimal consumer with no on-demand rules) so the\n * caller can drop the rule from the map without emitting an empty\n * table.\n */\nexport function buildConventionsRegistryRule(\n  rules: Iterable<AgentRule>,\n): AgentRule | undefined {\n  const entries: Array<AgentRule> = [];\n  for (const rule of rules) {\n    if (rule.scope !== AGENT_RULE_SCOPE.FILE_PATTERN) {\n      continue;\n    }\n    if (rule.platforms?.claude?.exclude === true) {\n      continue;\n    }\n    if (!rule.filePatterns || rule.filePatterns.length === 0) {\n      continue;\n    }\n    entries.push(rule);\n  }\n  if (entries.length === 0) {\n    return undefined;\n  }\n  entries.sort((a, b) => a.name.localeCompare(b.name));\n\n  const lines: Array<string> = [\n    \"# Conventions Registry\",\n    \"\",\n    \"Each row below is a `FILE_PATTERN`-scoped convention rule that\",\n    \"auto-loads on demand when the agent's current file matches one\",\n    \"of the listed paths. Full rule bodies live under\",\n    \"`.claude/rules/<slug>.md` so they only consume context when\",\n    \"they apply. Consult the matching rule before doing work in any\",\n    \"of the listed surfaces.\",\n    \"\",\n    \"| Rule | Auto-loads when editing | Purpose |\",\n    \"| --- | --- | --- |\",\n  ];\n\n  const MAX_PATTERNS_SHOWN = 3;\n  for (const rule of entries) {\n    const ruleLink = `[\\`${rule.name}\\`](.claude/rules/${rule.name}.md)`;\n    const patterns = rule.filePatterns ?? [];\n    let patternCell: string;\n    if (patterns.length <= MAX_PATTERNS_SHOWN) {\n      patternCell = patterns.map((p) => `\\`${p}\\``).join(\", \");\n    } else {\n      const shown = patterns\n        .slice(0, MAX_PATTERNS_SHOWN)\n        .map((p) => `\\`${p}\\``)\n        .join(\", \");\n      patternCell = `${shown}, … ([full list](.claude/rules/${rule.name}.md))`;\n    }\n    // Collapse any newlines or pipe characters in the description\n    // so a multi-line / pipe-bearing description does not break\n    // the markdown table row.\n    const purposeCell = rule.description\n      .replace(/\\s+/g, \" \")\n      .replace(/\\|/g, \"\\\\|\")\n      .trim();\n    lines.push(`| ${ruleLink} | ${patternCell} | ${purposeCell} |`);\n  }\n\n  return {\n    name: \"conventions-registry\",\n    description:\n      \"Routing table for every FILE_PATTERN-scoped convention rule. Lists each rule's slug, the file patterns that auto-trigger it, and a one-line purpose so agents whose current file does not match any rule's paths: can still discover the full convention set.\",\n    scope: AGENT_RULE_SCOPE.ALWAYS,\n    content: lines.join(\"\\n\"),\n    platforms: {\n      cursor: { exclude: true },\n    },\n    tags: [\"workflow\"],\n  };\n}\n\nexport function buildAgentRegistryRule(\n  bundles: ReadonlyArray<AgentRuleBundle>,\n  paths: ResolvedAgentPaths,\n): AgentRule | undefined {\n  const activeNames = new Set(bundles.map((b) => b.name));\n  const rows = AGENT_REGISTRY_ENTRIES.filter((e) =>\n    activeNames.has(e.bundle),\n  ).slice();\n  if (rows.length === 0) {\n    return undefined;\n  }\n  rows.sort((a, b) => a.bundle.localeCompare(b.bundle));\n\n  const lines: Array<string> = [\n    \"# Agent Registry\",\n    \"\",\n    \"Each row below is the routing summary for one phased-agent\",\n    \"bundle: the user-invocable skill, the sub-agent that handles\",\n    \"the work, the output path the agent writes to, and a one-line\",\n    \"purpose. Use the table to answer *which agent handles X* —\",\n    \"full agent prompts live in `.claude/agents/<name>.md` and only\",\n    \"load on delegation, so the table is the always-on routing\",\n    \"signal.\",\n    \"\",\n    \"Cross-cutting policies that apply to every agent below —\",\n    \"Progress File Convention, Shared-Editing Safety, Issue\",\n    \"Templates, Skill Evals — are documented as their own top-level\",\n    \"sections elsewhere in this file. The registry only captures\",\n    \"routing; it does not duplicate convention prose.\",\n    \"\",\n    \"| Skill | Agent | Bundle | Output path | Purpose |\",\n    \"| --- | --- | --- | --- | --- |\",\n  ];\n\n  for (const row of rows) {\n    const outputPath = row.resolveOutputPath(paths);\n    const pathCell = outputPath.length > 0 ? `\\`${outputPath}\\`` : \"—\";\n    lines.push(\n      `| \\`${row.skill}\\` | \\`${row.agent}\\` | \\`${row.bundle}\\` | ${pathCell} | ${row.purpose} |`,\n    );\n  }\n\n  return {\n    name: \"agent-registry\",\n    description:\n      \"Routing table mapping each phased-agent bundle to its primary skill, sub-agent, output path, and one-line purpose. Replaces the per-bundle workflow rules whose prose summaries duplicated the routing signal.\",\n    scope: AGENT_RULE_SCOPE.ALWAYS,\n    content: lines.join(\"\\n\"),\n    platforms: {\n      cursor: { exclude: true },\n    },\n    tags: [\"workflow\"],\n  };\n}\n","import {\n  AgentRuleBundle,\n  CustomDocSection,\n  SourceTierExamples,\n} from \"../agent-config-options\";\nimport { AgentRule } from \"../types\";\n\n/**\n * Tier metadata used by {@link renderSourceTierExamples} to locate the\n * matching heading inside the base bundle's \"Source Quality &\n * Verification\" rule.\n */\nconst SOURCE_TIER_HEADINGS: ReadonlyArray<{\n  readonly key: keyof SourceTierExamples;\n  readonly heading: string;\n}> = [\n  { key: \"t1\", heading: \"### T1 — Primary Living\" },\n  { key: \"t2\", heading: \"### T2 — Primary Snapshot\" },\n  { key: \"t3\", heading: \"### T3 — Secondary\" },\n  { key: \"t4\", heading: \"### T4 — Self-Reported / Marketing\" },\n];\n\n/**\n * Inject domain-specific source-tier examples into the content of the\n * base bundle's \"Source Quality & Verification\" rule.\n *\n * For every tier whose examples array is non-empty, a\n * `**Project-specific examples:**` line followed by a bullet list of\n * the supplied strings is appended immediately beneath the tier's\n * `### T<n> — ...` heading paragraph block. Tiers whose examples array\n * is missing or empty are left untouched.\n *\n * Returns the original `content` verbatim when the supplied config is\n * undefined or has no non-empty tier arrays, so callers can\n * unconditionally pipe content through this function.\n */\nexport function renderSourceTierExamples(\n  content: string,\n  examples: SourceTierExamples | undefined,\n): string {\n  if (!examples) {\n    return content;\n  }\n\n  const tierEntries = SOURCE_TIER_HEADINGS.flatMap(({ key, heading }) => {\n    const list = examples[key];\n    if (!list || list.length === 0) {\n      return [];\n    }\n    return [{ heading, list }];\n  });\n\n  if (tierEntries.length === 0) {\n    return content;\n  }\n\n  let updated = content;\n  for (const { heading, list } of tierEntries) {\n    const injection = [\n      \"\",\n      \"**Project-specific examples:**\",\n      \"\",\n      ...list.map((ex) => `- ${ex}`),\n    ].join(\"\\n\");\n    updated = insertAfterHeadingBlock(updated, heading, injection);\n  }\n\n  return updated;\n}\n\n/**\n * Apply every {@link CustomDocSection} that targets `bundle.name` to\n * the bundle's rules, returning a new bundle whose matched rules have\n * the section bodies appended after the configured `afterSection`\n * heading. Entries that reference a bundle name other than\n * `bundle.name`, or whose `afterSection` cannot be located in any\n * rule in the bundle, are silently dropped.\n *\n * Entries that target the same `afterSection` heading render in\n * supplied order — the first supplied entry appears immediately\n * beneath the target heading block, the second below that, and so on.\n * This is achieved by advancing the insertion anchor to each\n * just-injected section's `## <sectionTitle>` heading; the next\n * same-target entry then lands at the end of that newly-opened\n * section, which places it immediately after the previous entry\n * regardless of the original heading's level.\n *\n * Returns `bundle` unchanged when `sections` is empty or no entries\n * match, so callers can unconditionally pipe bundles through this\n * function without penalty.\n */\nexport function renderCustomDocSections(\n  bundle: AgentRuleBundle,\n  sections: ReadonlyArray<CustomDocSection>,\n): AgentRuleBundle {\n  const matching = sections.filter((s) => s.bundleName === bundle.name);\n  if (matching.length === 0) {\n    return bundle;\n  }\n\n  let rules: ReadonlyArray<AgentRule> = bundle.rules;\n  // Per-target (afterSection -> current anchor heading line) map so\n  // successive entries targeting the same heading chain onto the\n  // previous injection instead of landing in reverse order.\n  const currentAnchorByTarget = new Map<string, string>();\n\n  for (const section of matching) {\n    const injection = renderCustomDocSectionBlock(section);\n\n    // Pick the anchor heading to insert after: either the previous\n    // injection's own heading (for subsequent entries on the same\n    // target) or the user-supplied `afterSection` heading.\n    const seededAnchor = currentAnchorByTarget.get(section.afterSection);\n\n    let targetIndex = -1;\n    let targetHeading = \"\";\n    for (let i = 0; i < rules.length; i += 1) {\n      if (seededAnchor && rules[i].content.includes(seededAnchor)) {\n        targetIndex = i;\n        targetHeading = seededAnchor;\n        break;\n      }\n      if (!seededAnchor) {\n        const match = findHeadingForTitle(\n          rules[i].content,\n          section.afterSection,\n        );\n        if (match) {\n          targetIndex = i;\n          targetHeading = match;\n          break;\n        }\n      }\n    }\n    if (targetIndex === -1) {\n      continue;\n    }\n\n    const targetRule = rules[targetIndex];\n    const updatedRule: AgentRule = {\n      ...targetRule,\n      content: insertAfterHeadingBlock(\n        targetRule.content,\n        targetHeading,\n        injection,\n      ),\n    };\n    rules = [\n      ...rules.slice(0, targetIndex),\n      updatedRule,\n      ...rules.slice(targetIndex + 1),\n    ];\n\n    // The newly-injected `## <sectionTitle>` heading becomes the anchor\n    // the next same-target entry chains onto.\n    currentAnchorByTarget.set(\n      section.afterSection,\n      `## ${section.sectionTitle}`,\n    );\n  }\n\n  if (rules === bundle.rules) {\n    return bundle;\n  }\n\n  return { ...bundle, rules };\n}\n\n/**\n * Render a {@link CustomDocSection} into the markdown block that\n * `renderCustomDocSections` splices after the target heading block.\n * Exposed for tests that exercise the renderer directly without\n * touching a full bundle.\n */\nexport function renderCustomDocSectionBlock(section: CustomDocSection): string {\n  const body = section.body.replace(/[\\r\\n]+$/u, \"\");\n  return [\"\", `## ${section.sectionTitle}`, \"\", body].join(\"\\n\");\n}\n\n/**\n * Return the first full markdown heading line in `content` whose text\n * (after the `# ` prefix) equals `title`, regardless of heading level\n * (`#` through `######`). Matching is line-anchored so a mention of\n * the title in prose never counts. Returns `undefined` when no heading\n * in the document has the supplied title.\n */\nfunction findHeadingForTitle(\n  content: string,\n  title: string,\n): string | undefined {\n  const lines = content.split(\"\\n\");\n  for (const line of lines) {\n    const match = line.match(/^(#{1,6}) (.+)$/u);\n    if (match && match[2] === title) {\n      return line;\n    }\n  }\n  return undefined;\n}\n\n/**\n * Insert `injection` into `content` immediately after the end of the\n * section opened by `heading`. The section runs from the heading\n * itself through every subsequent line up to (but not including) the\n * next heading at the same or shallower level. Trailing blank lines\n * on the closing of the section are preserved in place and the\n * injection is spliced in before them so markdown spacing stays\n * consistent.\n *\n * If `heading` is not found, returns `content` unchanged.\n */\nfunction insertAfterHeadingBlock(\n  content: string,\n  heading: string,\n  injection: string,\n): string {\n  const lines = content.split(\"\\n\");\n  const headingIndex = lines.findIndex((line) => line === heading);\n  if (headingIndex === -1) {\n    return content;\n  }\n\n  const headingLevel = countLeadingHashes(heading);\n\n  // Scan forward from the heading to locate the end of the section —\n  // the line *before* the next heading at the same or shallower level,\n  // or the end of the document when no such heading exists.\n  let endIndex = lines.length - 1;\n  for (let i = headingIndex + 1; i < lines.length; i += 1) {\n    const nextLevel = countLeadingHashes(lines[i]);\n    if (nextLevel > 0 && nextLevel <= headingLevel) {\n      endIndex = i - 1;\n      break;\n    }\n  }\n\n  // Trim trailing blank lines off the section so the injection lands\n  // directly at the end of the section's content, not after a string\n  // of blank lines.\n  while (endIndex > headingIndex && lines[endIndex] === \"\") {\n    endIndex -= 1;\n  }\n\n  const injectionLines = injection.split(\"\\n\");\n  const next = [\n    ...lines.slice(0, endIndex + 1),\n    ...injectionLines,\n    ...lines.slice(endIndex + 1),\n  ];\n  return next.join(\"\\n\");\n}\n\n/**\n * Count the number of `#` characters at the start of a markdown\n * heading line. Returns `0` when the line is not a heading.\n */\nfunction countLeadingHashes(line: string): number {\n  const match = line.match(/^(#{1,6}) /u);\n  return match ? match[1].length : 0;\n}\n","import { FocusConfig } from \"../agent-config-options\";\n\nconst DEFAULT_FOCUS_FILE_PATH = \".claude/focus.json\";\nconst DEFAULT_SCHEMA_VERSION = 1;\n\n/**\n * Render the markdown subsection appended to the\n * `issue-label-conventions` rule when `AgentConfigOptions.focus` is\n * supplied. Returns an empty string when `focus` is undefined so\n * callers can unconditionally concatenate the result.\n *\n * The section documents three things for agents:\n *\n * 1. How to read `focus.json` at triage time\n * 2. How focus weight interacts with the `priority:*` taxonomy\n * 3. The agent-driven expansion contract (what agents may append)\n *\n * Configulator ships this rule content plus a JSON Schema that\n * validates the `focus.json` file; the file itself is authored and\n * curated in the consuming repo.\n */\nexport function renderFocusSection(focus: FocusConfig | undefined): string {\n  if (!focus) {\n    return \"\";\n  }\n\n  const focusFilePath = focus.focusFilePath ?? DEFAULT_FOCUS_FILE_PATH;\n  const schemaVersion = focus.schemaVersion ?? DEFAULT_SCHEMA_VERSION;\n\n  const lines: Array<string> = [\n    \"## Focus scoring\",\n    \"\",\n    \"This project runs a **focus-scoring engine** alongside the generic\",\n    \"`priority:*` inference above. Focus scoring boosts the priority of\",\n    \"issues that match the project's currently-declared focus areas —\",\n    \"named customers, segments, organizations, software products,\",\n    \"regulations, or people the project cares about right now.\",\n    \"\",\n    \"### Reading `focus.json`\",\n    \"\",\n    `The focus file lives at \\`${focusFilePath}\\` and conforms to schema`,\n    `version \\`${schemaVersion}\\`. Each entry declares a match predicate`,\n    \"(any combination of `labels`, `titleKeywords`, `bodyKeywords`) and\",\n    \"a positive integer `weight`. At triage time:\",\n    \"\",\n    `1. Read \\`${focusFilePath}\\`. If the file is missing or empty,`,\n    \"   skip focus scoring entirely — the generic priority heuristics\",\n    \"   apply unchanged.\",\n    \"2. For each focus area, test its match predicate against the\",\n    \"   issue's labels, title, and body. A match on **any** sub-field\",\n    \"   (labels / title keywords / body keywords) fires the area and\",\n    \"   contributes its `weight` to the issue's focus score.\",\n    \"3. Keyword matching is case-insensitive substring matching —\",\n    '   `titleKeywords: [\"Acme\"]` matches an issue titled',\n    \"   `feat: onboard acme corp`.\",\n    \"4. Sum all matched weights to produce the issue's **focus score**.\",\n    \"\",\n  ];\n\n  lines.push(\"### How focus score interacts with `priority:*`\");\n  lines.push(\"\");\n\n  if (focus.thresholds) {\n    const { high, medium } = focus.thresholds;\n    lines.push(`A focus score of \\`${high}\\` or more boosts the`);\n    const mediumBand =\n      high - medium === 1\n        ? `A focus score of \\`${medium}\\` keeps`\n        : `A focus score of \\`${medium}\\` up to \\`${high - 1}\\` keeps`;\n    lines.push(\n      \"issue to `priority:high`.\",\n      `${mediumBand} the issue at \\`priority:medium\\`. Scores below`,\n      `\\`${medium}\\` do **not** alter the priority that`,\n      \"the generic heuristics would otherwise infer.\",\n    );\n  } else {\n    lines.push(\n      \"This project has not declared explicit focus-score thresholds.\",\n      \"Treat any non-zero focus score as a soft signal to lift one\",\n      \"priority tier (never above `priority:high`) unless the generic\",\n      \"heuristics already pin a higher tier.\",\n    );\n  }\n  lines.push(\"\");\n  lines.push(\n    \"Focus scoring **never lowers** an issue's priority — the generic\",\n    \"heuristics set the floor, and focus weight can only lift it.\",\n    \"`priority:critical` is never set by focus scoring alone; the\",\n    \"generic heuristics own that tier.\",\n  );\n  lines.push(\"\");\n\n  lines.push(\"### Agent-driven expansion\");\n  lines.push(\"\");\n\n  if (focus.agentExpansionRules) {\n    const rules = focus.agentExpansionRules;\n    const allowedList = rules.allowedTypes.map((t) => `\\`${t}\\``).join(\", \");\n    const forbiddenList = rules.forbiddenTypes\n      .map((t) => `\\`${t}\\``)\n      .join(\", \");\n\n    lines.push(\n      `Agents may **append** new focus areas to \\`${focusFilePath}\\``,\n      \"when they discover a relevant entity during work, subject to\",\n      \"these guard-rails:\",\n    );\n    lines.push(\"\");\n    lines.push(\n      `- **Max weight.** Agent-appended entries must set \\`weight\\` to`,\n      `  \\`${rules.maxWeight}\\` or less. Higher weights require a human.`,\n    );\n    lines.push(\n      \"- **Allowed types.** Agents may only introduce entries whose\",\n      `  \\`type\\` is one of: ${allowedList || \"(none)\"}.`,\n    );\n    if (rules.forbiddenTypes.length > 0) {\n      lines.push(\n        \"- **Forbidden types.** Even inside `allowedTypes`, agents must\",\n        `  never introduce entries whose \\`type\\` is one of: ${forbiddenList}.`,\n      );\n    }\n    if (rules.maxKeywords !== undefined) {\n      lines.push(\n        \"- **Max keywords per match field.** Agent-appended entries\",\n        `  may list at most \\`${rules.maxKeywords}\\` items in each of`,\n        \"  `match.labels`, `match.titleKeywords`, and `match.bodyKeywords`.\",\n      );\n    }\n    lines.push(\n      '- **Provenance.** Agent-appended entries must set `source: \"agent\"`',\n      '  and `discoveredIn: \"#<issue>\"` referencing the issue that',\n      \"  surfaced the focus area.\",\n    );\n    lines.push(\n      \"- **Append-only.** Never modify or remove existing entries.\",\n      \"  Human curators own edits and deletions.\",\n    );\n  } else {\n    lines.push(\n      `Agents must **not** append to \\`${focusFilePath}\\`. This project`,\n      \"has not declared agent-expansion rules — all focus-area curation\",\n      \"is performed by humans. If you discover a relevant entity that\",\n      \"is not covered by an existing focus area, raise it in the issue\",\n      \"or PR discussion instead of editing the focus file.\",\n    );\n  }\n\n  return lines.join(\"\\n\");\n}\n","import {\n  ActionItemFilingConfig,\n  MeetingsConfig,\n} from \"../agent-config-options\";\n\nconst DEFAULT_AGENDA_TEMPLATE_ROOT = \"<meetingsRoot>/_agenda-templates\";\n\n/**\n * An `actionItemFiling` config renders a subsection only when it\n * overrides a bundle default — i.e. the split is explicitly disabled or\n * the consumer supplies extra classification cues. A config that just\n * re-affirms the defaults (enabled, no cues) renders nothing because the\n * baked-in agent prompt already documents that behaviour.\n */\nfunction actionItemFilingHasOverride(\n  filing: ActionItemFilingConfig | undefined,\n): filing is ActionItemFilingConfig {\n  if (!filing) {\n    return false;\n  }\n  return (\n    filing.enabled === false ||\n    (filing.humanOwnedCues ?? []).length > 0 ||\n    (filing.agentWorkableCues ?? []).length > 0\n  );\n}\n\n/**\n * Render the markdown subsections appended to the\n * `meeting-processing-workflow` rule when `AgentConfigOptions.meetings`\n * is supplied. Returns an empty string when the supplied config has\n * nothing to render (no meeting types and no meeting areas) so callers\n * can unconditionally concatenate the result.\n *\n * Two subsections are rendered, each gated on its own input array:\n *\n * 1. **Recognized meeting types** — rendered when `meetingTypes` is\n *    non-empty. Lists every declared type with its scope, kind,\n *    optional cadence, default duration, and agenda template path.\n *    Also documents the resolved `agendaTemplateRoot`.\n * 2. **Area → doc-root mapping** — rendered when `meetingAreas` is\n *    non-empty. Lists every declared area with its `id`, label, and\n *    docs-root-relative destination folder.\n *\n * Bundles consume the rendered string by appending it to their own\n * rule content. A caller that has no meeting types and no meeting\n * areas receives an empty string and can safely concatenate.\n */\nexport function renderMeetingTypesSection(\n  meetings: MeetingsConfig | undefined,\n): string {\n  if (!meetings) {\n    return \"\";\n  }\n\n  const types = meetings.meetingTypes ?? [];\n  const areas = meetings.meetingAreas ?? [];\n  const filingOverride = actionItemFilingHasOverride(meetings.actionItemFiling)\n    ? meetings.actionItemFiling\n    : undefined;\n\n  if (types.length === 0 && areas.length === 0 && !filingOverride) {\n    return \"\";\n  }\n\n  const sections: Array<string> = [];\n\n  if (types.length > 0) {\n    sections.push(renderMeetingTypes(types, meetings.agendaTemplateRoot));\n  }\n\n  if (areas.length > 0) {\n    sections.push(renderMeetingAreas(areas));\n  }\n\n  if (filingOverride) {\n    sections.push(renderActionItemFiling(filingOverride));\n  }\n\n  return sections.join(\"\\n\\n\");\n}\n\nfunction renderMeetingTypes(\n  types: ReadonlyArray<NonNullable<MeetingsConfig[\"meetingTypes\"]>[number]>,\n  agendaTemplateRoot: string | undefined,\n): string {\n  const resolvedRoot = agendaTemplateRoot ?? DEFAULT_AGENDA_TEMPLATE_ROOT;\n\n  const lines: Array<string> = [\n    \"## Recognized meeting types\",\n    \"\",\n    \"This project declares a meeting-type taxonomy through\",\n    \"`AgentConfigOptions.meetings.meetingTypes`. When classifying a\",\n    \"meeting transcript, pick the `id` from this list that best fits the\",\n    \"meeting; do **not** invent new type identifiers. The `Kind` column\",\n    \"maps each concrete `id` onto the generic meeting-kind taxonomy\",\n    \"(`planning` / `review` / `brainstorm` / `standup` / `external` /\",\n    \"`other`) documented in the **Meeting type handling** section —\",\n    \"apply the type-specific rules listed there based on this kind.\",\n    \"Agenda-template paths below are resolved relative to\",\n    `\\`${resolvedRoot}\\`.`,\n    \"\",\n    \"| ID | Label | Kind | Scope | Cadence | Default duration | Agenda template |\",\n    \"|----|-------|------|-------|---------|------------------|-----------------|\",\n  ];\n\n  for (const type of types) {\n    const kind = type.kind ? `\\`${type.kind}\\`` : \"—\";\n    const cadence = type.cadence ? `\\`${type.cadence}\\`` : \"—\";\n    const duration =\n      type.defaultDurationMinutes !== undefined\n        ? `${type.defaultDurationMinutes} min`\n        : \"—\";\n    const template = type.agendaTemplatePath\n      ? `\\`${type.agendaTemplatePath}\\``\n      : \"—\";\n    lines.push(\n      `| \\`${type.id}\\` | ${type.label} | ${kind} | \\`${type.scope}\\` | ${cadence} | ${duration} | ${template} |`,\n    );\n  }\n\n  return lines.join(\"\\n\");\n}\n\nfunction renderMeetingAreas(\n  areas: ReadonlyArray<NonNullable<MeetingsConfig[\"meetingAreas\"]>[number]>,\n): string {\n  const lines: Array<string> = [\n    \"## Area → doc-root mapping\",\n    \"\",\n    \"This project declares a meeting-area routing map through\",\n    \"`AgentConfigOptions.meetings.meetingAreas`. When a meeting note's\",\n    \"frontmatter carries an `areas:` list, route phase-4 direct edits\",\n    \"into the corresponding sub-trees of the docs root\",\n    \"(`AgentPathsConfig.docsRoot`). See the **Areas filtering** section\",\n    \"of the `meeting-analyst` agent for the full gating contract.\",\n    \"Meetings whose `areas` list is empty or does not match any\",\n    \"declared entry fall back to the default meetings root.\",\n    \"\",\n    \"| Area ID | Label | Doc-root sub-folder |\",\n    \"|---------|-------|---------------------|\",\n  ];\n\n  for (const area of areas) {\n    lines.push(`| \\`${area.id}\\` | ${area.label} | \\`${area.docRoot}\\` |`);\n  }\n\n  return lines.join(\"\\n\");\n}\n\nfunction renderActionItemFiling(filing: ActionItemFilingConfig): string {\n  const lines: Array<string> = [\n    \"## Action-item filing policy\",\n    \"\",\n    \"This project tunes the Phase 4 (Link) agent-workability split\",\n    \"through `AgentConfigOptions.meetings.actionItemFiling`. See the\",\n    \"**Action-item filing policy** section of the `meeting-analyst`\",\n    \"agent for the full baked-in test.\",\n    \"\",\n  ];\n\n  if (filing.enabled === false) {\n    lines.push(\n      \"- **Split disabled.** Phase 4 falls back to the legacy behaviour:\",\n      \"  file a follow-up issue for every action item that is not\",\n      \"  already covered by a requirement or ADR draft, including\",\n      \"  human-owned tasks. The notes `## Action Items` table is still\",\n      \"  written, but it is no longer the sole record for human\",\n      \"  follow-ups.\",\n    );\n  } else {\n    lines.push(\n      \"- **Split enabled** (default). Agent-workable doc deliverables are\",\n      \"  filed through their dedicated downstream channel; human-owned\",\n      \"  tasks are recorded only in the notes `## Action Items` table.\",\n    );\n  }\n\n  const humanCues = filing.humanOwnedCues ?? [];\n  if (humanCues.length > 0) {\n    lines.push(\n      \"\",\n      \"**Additional human-owned cues** (recorded notes-only, never\",\n      \"filed), in addition to the bundle's built-in list:\",\n      \"\",\n      ...humanCues.map((cue) => `- ${cue}`),\n    );\n  }\n\n  const agentCues = filing.agentWorkableCues ?? [];\n  if (agentCues.length > 0) {\n    lines.push(\n      \"\",\n      \"**Additional agent-workable cues** (filed through the matching\",\n      \"downstream channel), in addition to the bundle's built-in list:\",\n      \"\",\n      ...agentCues.map((cue) => `- ${cue}`),\n    );\n  }\n\n  return lines.join(\"\\n\");\n}\n","import { PriorityRule } from \"../agent-config-options\";\n\n/**\n * Render the markdown subsection appended to the\n * `issue-label-conventions` rule when `AgentConfigOptions.priorityRules`\n * is non-empty. Returns an empty string when the supplied array is\n * empty so callers can unconditionally concatenate the result.\n *\n * Precedence is **first match wins** — rules render in the order\n * supplied. The bundle's default inference heuristics act as the\n * fallback when no rule matches.\n */\nexport function renderPriorityRulesSection(\n  rules: ReadonlyArray<PriorityRule>,\n): string {\n  if (rules.length === 0) {\n    return \"\";\n  }\n\n  const lines: Array<string> = [\n    \"## Project-specific priority rules\",\n    \"\",\n    \"These rules are supplied by this project through\",\n    \"`AgentConfigOptions.priorityRules` and override the generic inference\",\n    \"heuristics above. Rules evaluate in the order listed; **first match\",\n    \"wins**. The bundle's default heuristics apply only when no rule below\",\n    \"matches.\",\n    \"\",\n  ];\n\n  rules.forEach((rule, index) => {\n    const matchDetails: Array<string> = [];\n\n    if (rule.match.labels && rule.match.labels.length > 0) {\n      const labelList = rule.match.labels.map((l) => `\\`${l}\\``).join(\", \");\n      matchDetails.push(`labels: ${labelList}`);\n    }\n    if (rule.match.titleRegex) {\n      matchDetails.push(`title regex: \\`${rule.match.titleRegex}\\``);\n    }\n    if (rule.match.bodyRegex) {\n      matchDetails.push(`body regex: \\`${rule.match.bodyRegex}\\``);\n    }\n    if (rule.match.issueNumbers && rule.match.issueNumbers.length > 0) {\n      const numberList = rule.match.issueNumbers.map((n) => `#${n}`).join(\", \");\n      matchDetails.push(`issue numbers: ${numberList}`);\n    }\n\n    const matchSummary =\n      matchDetails.length > 0 ? matchDetails.join(\"; \") : \"(no match fields)\";\n\n    lines.push(\n      `${index + 1}. **\\`priority:${rule.priority}\\`** when ${matchSummary} — ${rule.rationale}`,\n    );\n  });\n\n  return lines.join(\"\\n\");\n}\n","import { AgentRuleBundle } from \"../agent-config-options\";\nimport { AGENT_MODEL, AgentModel } from \"../types\";\nimport { agendaBundle } from \"./agenda\";\nimport { awsCdkBundle } from \"./aws-cdk\";\nimport {\n  buildBaseBundle,\n  DEFAULT_BASE_CONVENTIONS,\n  ResolvedBaseConventions,\n} from \"./base\";\nimport { buildBcmWriterBundle } from \"./bcm-writer\";\nimport { DEFAULT_BUILD_POLICY, ResolvedBuildPolicy } from \"./build-policy\";\nimport { buildBusinessModelsBundle } from \"./business-models\";\nimport { buildCompanyProfileBundle } from \"./company-profile\";\nimport { buildCustomerProfileBundle } from \"./customer-profile\";\nimport { buildDocsSyncBundle } from \"./docs-sync\";\nimport { buildGithubWorkflowBundle } from \"./github-workflow\";\nimport { buildIndustryDiscoveryBundle } from \"./industry-discovery\";\nimport {\n  DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n  ResolvedIssueDefaults,\n} from \"./issue-defaults\";\nimport { jestBundle } from \"./jest\";\nimport { buildMaintenanceAuditBundle } from \"./maintenance-audit\";\nimport { buildMeetingAnalysisBundle } from \"./meeting-analysis\";\nimport {\n  buildOrchestratorBundle,\n  DEFAULT_ORCHESTRATOR_CONVENTIONS,\n  ResolvedOrchestratorConventions,\n} from \"./orchestrator\";\nimport { DEFAULT_AGENT_PATHS, ResolvedAgentPaths } from \"./paths\";\nimport { buildPeopleProfileBundle } from \"./people-profile\";\nimport { pnpmBundle } from \"./pnpm\";\nimport { buildPrReviewBundle } from \"./pr-review\";\nimport {\n  ResolvedPrReviewPolicy,\n  resolvePrReviewPolicy,\n} from \"./pr-review-policy\";\nimport { projenBundle } from \"./projen\";\nimport { buildRegulatoryResearchBundle } from \"./regulatory-research\";\nimport { buildRequirementsAnalystBundle } from \"./requirements-analyst\";\nimport { buildRequirementsReviewerBundle } from \"./requirements-reviewer\";\nimport { buildRequirementsWriterBundle } from \"./requirements-writer\";\nimport { buildResearchPipelineBundle } from \"./research-pipeline\";\nimport { slackBundle } from \"./slack\";\nimport { buildSoftwareProfileBundle } from \"./software-profile\";\nimport { buildStandardsResearchBundle } from \"./standards-research\";\nimport { buildTurborepoBundle } from \"./turborepo\";\nimport { typescriptBundle } from \"./typescript\";\nimport { upstreamConfigulatorDocsBundle } from \"./upstream-configulator-docs\";\nimport { vitestBundle } from \"./vitest\";\n\nexport {\n  AGENT_REGISTRY_ENTRIES,\n  SUPPRESSED_WORKFLOW_RULE_NAMES,\n  buildAgentRegistryRule,\n  bundleNameForWorkflowRule,\n  isSuppressedWorkflowRule,\n  type AgentRegistryEntry,\n} from \"./agent-registry\";\nexport { agendaBundle } from \"./agenda\";\nexport { awsCdkBundle } from \"./aws-cdk\";\nexport {\n  baseBundle,\n  buildBaseBundle,\n  DEFAULT_BASE_CONVENTIONS,\n  type ResolvedBaseConventions,\n} from \"./base\";\nexport {\n  BUNDLE_OWNERSHIP,\n  CONVENTIONAL_COMMIT_TYPE_LABELS,\n  PHASE_LABEL_TYPE_MAP,\n  hasAnyDocsEmittingBundle,\n  hasAnyDownstreamIssueKindBundle,\n  isPhaseLabelOwnedByExcluded,\n  isScheduledTaskOwnedByExcluded,\n  isTypeLabelOwnedByExcluded,\n  renderPhaseTypeInvariantSection,\n  renderPhaseTypeInvariantShellHelpers,\n  resolveTypeLabelForLabels,\n  typeLabelForPhaseLabel,\n  type BundleOwnership,\n  type PhaseLabelTypeOutcome,\n  type PhaseLabelTypeResolution,\n} from \"./bundle-ownership\";\nexport { buildBcmWriterBundle, bcmWriterBundle } from \"./bcm-writer\";\nexport {\n  DEFAULT_BUILD_POLICY,\n  resolveBuildPolicy,\n  type ResolvedBuildPolicy,\n} from \"./build-policy\";\nexport {\n  buildBusinessModelsBundle,\n  businessModelsBundle,\n} from \"./business-models\";\nexport {\n  checkClosingKeywordsProcedure,\n  renderCheckClosingKeywordsScript,\n} from \"./closing-keywords\";\nexport {\n  buildCompanyProfileBundle,\n  companyProfileBundle,\n} from \"./company-profile\";\nexport {\n  buildCustomerProfileBundle,\n  customerProfileBundle,\n} from \"./customer-profile\";\nexport {\n  buildDocsSyncBundle,\n  checkDocSamplesProcedure,\n  checkLinksProcedure,\n  docsSyncBundle,\n  extractApiProcedure,\n  renderCheckDocSamplesProcedure,\n  renderCheckLinksProcedure,\n  renderExtractApiProcedure,\n  renderStripToolArtifactTagsProcedure,\n  stripToolArtifactTagsProcedure,\n} from \"./docs-sync\";\nexport {\n  buildGithubWorkflowBundle,\n  githubWorkflowBundle,\n} from \"./github-workflow\";\nexport {\n  buildIndustryDiscoveryBundle,\n  industryDiscoveryBundle,\n} from \"./industry-discovery\";\nexport { jestBundle } from \"./jest\";\nexport {\n  buildMaintenanceAuditBundle,\n  maintenanceAuditBundle,\n} from \"./maintenance-audit\";\nexport {\n  DEFAULT_ISSUE_PRIORITY,\n  DEFAULT_ISSUE_STATUS,\n  DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n  VALID_PRIORITY_VALUES,\n  VALID_STATUS_VALUES,\n  labelsForPhase,\n  resolveIssueDefaults,\n  validateIssueDefaultsConfig,\n  type IssueDefaultsPriority,\n  type IssueDefaultsStatus,\n  type ResolvedIssueDefaults,\n  type ResolvedIssueDefaultsEntry,\n} from \"./issue-defaults\";\nexport {\n  buildMeetingAnalysisBundle,\n  meetingAnalysisBundle,\n} from \"./meeting-analysis\";\nexport {\n  buildCheckBlockedProcedure,\n  buildOrchestratorBundle,\n  buildOrchestratorConventionsContent,\n  buildUnblockDependentsProcedure,\n  DEFAULT_ORCHESTRATOR_CONVENTIONS,\n  orchestratorBundle,\n  resolveOrchestratorAssets,\n  type ResolvedOrchestratorConventions,\n} from \"./orchestrator\";\nexport {\n  DEFAULT_AGENT_PATHS,\n  DEFAULT_REQUIREMENT_CATEGORY_DIRS,\n  resolveAgentPaths,\n  type ResolvedAgentPaths,\n  type ResolvedRequirementCategoryDirs,\n} from \"./paths\";\nexport {\n  buildPeopleProfileBundle,\n  peopleProfileBundle,\n} from \"./people-profile\";\nexport { pnpmBundle } from \"./pnpm\";\nexport {\n  DEFAULT_ISSUE_TEMPLATES_BUNDLE_PATH_PATTERNS,\n  DEFAULT_ISSUE_TEMPLATES_EMIT_CHECKER,\n  DEFAULT_ISSUE_TEMPLATES_EMIT_STARTER,\n  DEFAULT_ISSUE_TEMPLATES_ENABLED,\n  DEFAULT_ISSUE_TEMPLATES_PATH,\n  DEFAULT_ISSUE_TEMPLATES_REQUIRE_REFERENCE,\n  ISSUE_TEMPLATES_GENERATED_SUFFIX,\n  collectIssueTemplateRecipeStubs,\n  issueTemplatesChildGlob,\n  issueTemplatesGeneratedPath,\n  renderIssueTemplateLabelsCheckerScript,\n  renderIssueTemplatesBundleHook,\n  renderIssueTemplatesCheckerScript,\n  renderIssueTemplatesGeneratedPage,\n  renderIssueTemplatesRuleContent,\n  renderIssueTemplatesStarterPage,\n  resolveIssueTemplates,\n  validateIssueTemplatesConfig,\n  type IssueTemplateRecipeStub,\n  type ResolvedIssueTemplates,\n} from \"./issue-templates\";\nexport {\n  DEFAULT_GITHUB_ISSUE_TYPE,\n  GITHUB_ISSUE_TYPES,\n  GITHUB_ISSUE_TYPE_BY_TITLE_PREFIX,\n  SET_ISSUE_TYPE_HELPER_PATH,\n  githubIssueTypeForTitle,\n  renderGithubIssueTypeSection,\n  renderGithubIssueTypeSectionLines,\n  renderIssueTypeAssignmentBlanket,\n  renderIssueTypeAssignmentStep,\n  renderSetIssueTypeFallbackLines,\n  renderTitlePrefixTypeBullets,\n  type GithubIssueType,\n  type IssueTypeAssignmentStepOptions,\n} from \"./issue-type\";\nexport {\n  DEFAULT_PROGRESS_FILES_ENABLED,\n  DEFAULT_PROGRESS_FILES_FILENAME_PATTERN,\n  DEFAULT_PROGRESS_FILES_FORMAT,\n  DEFAULT_PROGRESS_FILES_STALE_AFTER_HOURS,\n  DEFAULT_PROGRESS_FILES_STATE_DIR,\n  PROGRESS_FILES_FORMAT_VALUES,\n  renderProgressFileName,\n  renderProgressFilePath,\n  renderProgressFilesBundleHook,\n  renderProgressFilesRuleContent,\n  resolveProgressFiles,\n  validateProgressFilesConfig,\n  type ResolvedProgressFiles,\n} from \"./progress-files\";\nexport { buildPrReviewBundle, prReviewBundle } from \"./pr-review\";\nexport {\n  DEFAULT_PATHS_EXEMPT_FROM_SIZE,\n  resolvePrReviewPolicy,\n  validatePrReviewPolicyConfig,\n  type ResolvedPrReviewPolicy,\n  type ResolvedPrReviewAutoMerge,\n} from \"./pr-review-policy\";\nexport { projenBundle } from \"./projen\";\nexport {\n  buildRegulatoryResearchBundle,\n  regulatoryResearchBundle,\n} from \"./regulatory-research\";\nexport {\n  renderCustomDocSectionBlock,\n  renderCustomDocSections,\n  renderSourceTierExamples,\n} from \"./features\";\nexport { renderFocusSection } from \"./focus\";\nexport { renderMeetingTypesSection } from \"./meeting-types\";\nexport { renderPriorityRulesSection } from \"./priority-rules\";\nexport {\n  DEFAULT_DISPATCH_MODEL,\n  DEFAULT_DISPATCH_TO_HOUSEKEEPING_RATIO,\n  DEFAULT_HOUSEKEEPING_MODEL,\n  DEFAULT_STATE_FILE_PATH,\n  classifyRun,\n  renderRunRatioSection,\n  renderRunRatioShellHelpers,\n  resolveRunRatio,\n  validateRunRatioConfig,\n  type ResolvedRunRatio,\n} from \"./run-ratio\";\nexport {\n  DEFAULT_AC_THRESHOLDS,\n  DEFAULT_BUNDLE_OVERRIDES,\n  DEFAULT_DECOMPOSITION_TEMPLATE,\n  DEFAULT_SOURCES_THRESHOLDS,\n  SCOPE_CLASS_VALUES,\n  classifyIssueScope,\n  renderScopeGateSection,\n  renderScopeGateShellHelpers,\n  resolveOverrideForLabels,\n  resolveScopeGate,\n  validateScopeGateConfig,\n  type EffectiveScopeThresholds,\n  type ResolvedScopeGate,\n  type ResolvedScopeGateBundleOverride,\n  type ScopeClass,\n} from \"./scope-gate\";\nexport {\n  DEFAULT_OFF_PEAK_CRON_EXAMPLE,\n  DEFAULT_SCHEDULED_TASKS_ROOT,\n  DEFAULT_SCHEDULED_TASK_ENTRIES,\n  SCHEDULED_TASK_MODEL_VALUES,\n  renderScheduledTaskSkillFile,\n  renderScheduledTasksSection,\n  resolveScheduledTasks,\n  validateScheduledTasksConfig,\n  type ResolvedScheduledTask,\n  type ResolvedScheduledTasks,\n  type ScheduledTaskModel,\n} from \"./scheduled-tasks\";\nexport {\n  AGENT_TIER_ROLES,\n  AGENT_TIER_VALUES,\n  DEFAULT_AGENT_TIERS,\n  UNKNOWN_TYPE_FALLBACK_TIER,\n  renderAgentTierCaseStatement,\n  renderAgentTierSection,\n  resolveAgentTiers,\n  validateAgentTierConfig,\n  type AgentTier,\n  type ResolvedAgentTier,\n} from \"./tiers\";\nexport {\n  DEFAULT_PARTIAL_UNBLOCK_COMMENT_TEMPLATE,\n  DEFAULT_UNBLOCK_COMMENT_TEMPLATE,\n  DEFAULT_UNBLOCK_DEPENDENTS_ENABLED,\n  renderUnblockDependentsScript,\n  renderUnblockDependentsSection,\n  resolveUnblockDependents,\n  validateUnblockDependentsConfig,\n  type ResolvedUnblockDependents,\n} from \"./unblock-dependents\";\nexport {\n  DEFAULT_SHARED_EDITING_CONFLICT_STRATEGY,\n  DEFAULT_SHARED_EDITING_EMIT_HELPER,\n  DEFAULT_SHARED_EDITING_ENABLED,\n  DEFAULT_SHARED_EDITING_VERIFY_COMMIT,\n  DEFAULT_SHARED_INDEX_PATHS,\n  SHARED_EDITING_CONFLICT_STRATEGY_VALUES,\n  renderSharedEditingBundleHook,\n  renderSharedEditingHelperScript,\n  renderSharedEditingRuleContent,\n  resolveSharedEditing,\n  validateSharedEditingConfig,\n  type ResolvedSharedEditing,\n} from \"./shared-editing\";\nexport {\n  DEFAULT_PRODUCT_CONTEXT_PATH,\n  DEFAULT_REQUIRE_PRODUCT_CONTEXT,\n  DEFAULT_SKILL_EVALS_EMIT_RUNNER,\n  DEFAULT_SKILL_EVALS_ENABLED,\n  DEFAULT_SKILL_EVALS_SKILLS_ROOT,\n  renderSkillEvalsBundleHook,\n  renderSkillEvalsRuleContent,\n  renderSkillEvalsRunnerScript,\n  resolveSkillEvals,\n  validateSkillEvalsConfig,\n  type ResolvedSkillEvals,\n} from \"./skill-evals\";\nexport {\n  DEFAULT_TEMPORAL_FRAMING_CADENCES,\n  DEFAULT_TEMPORAL_FRAMING_EMIT_CHECKER,\n  DEFAULT_TEMPORAL_FRAMING_ENABLED,\n  DEFAULT_TEMPORAL_FRAMING_PATHS,\n  TEMPORAL_FRAMING_CATEGORY_VALUES,\n  renderTemporalFramingCheckerScript,\n  renderTemporalFramingRuleContent,\n  resolveTemporalFraming,\n  validateTemporalFramingConfig,\n  type ResolvedTemporalFraming,\n  type TemporalFramingCategory,\n} from \"./temporal-framing\";\nexport {\n  buildRequirementsAnalystBundle,\n  requirementsAnalystBundle,\n} from \"./requirements-analyst\";\nexport {\n  buildRequirementsReviewerBundle,\n  requirementsReviewerBundle,\n} from \"./requirements-reviewer\";\nexport {\n  buildRequirementsWriterBundle,\n  nextRequirementIdProcedure,\n  REQUIREMENTS_WRITER_PATHS,\n  renderNextRequirementIdProcedure,\n  requirementsWriterBundle,\n} from \"./requirements-writer\";\nexport {\n  buildResearchPipelineBundle,\n  researchPipelineBundle,\n} from \"./research-pipeline\";\nexport { slackBundle } from \"./slack\";\nexport {\n  buildSoftwareProfileBundle,\n  softwareProfileBundle,\n} from \"./software-profile\";\nexport {\n  buildStandardsResearchBundle,\n  standardsResearchBundle,\n} from \"./standards-research\";\nexport { buildTurborepoBundle, turborepoBundle } from \"./turborepo\";\nexport { typescriptBundle } from \"./typescript\";\nexport {\n  DEFAULT_UPSTREAM_CONFIGULATOR_ENABLED,\n  upstreamConfigulatorDocsBundle,\n} from \"./upstream-configulator-docs\";\nexport { vitestBundle } from \"./vitest\";\n\n/**\n * Resolved settings for every **config-driven convention rule** — a\n * bundle rule whose body is derived from consumer configuration rather\n * than being fixed prose.\n *\n * These rules used to ship default content from their bundle and get\n * rewritten late in `AgentConfig.resolveRules()`, which silently\n * discarded any `ruleExtensions` append or same-name `rules` override\n * that had already been merged into the map. Passing the resolved\n * settings down to the bundle factories instead keeps the rule map a\n * pure composition surface: seed once, then extend / override / exclude\n * on top.\n */\nexport interface ResolvedRuleConventions {\n  /** Settings for the five convention rules the `base` bundle owns. */\n  readonly base: ResolvedBaseConventions;\n  /** Settings for the `orchestrator-conventions` rule. */\n  readonly orchestrator: ResolvedOrchestratorConventions;\n}\n\n/**\n * Convention settings applied when the consumer configures none of the\n * config-driven conventions.\n */\nexport const DEFAULT_RULE_CONVENTIONS: ResolvedRuleConventions = {\n  base: DEFAULT_BASE_CONVENTIONS,\n  orchestrator: DEFAULT_ORCHESTRATOR_CONVENTIONS,\n};\n\n/**\n * Build the full list of built-in rule bundles with the supplied\n * resolved agent paths. Every path-aware bundle accepts a\n * `ResolvedAgentPaths` and threads it through its rule / skill /\n * sub-agent content, so a consumer override of\n * `AgentConfigOptions.paths` propagates into the rendered output.\n *\n * Bundles that file downstream issues also accept a\n * `ResolvedIssueDefaults` second argument so per-phase-label\n * overrides supplied via `AgentConfigOptions.issueDefaults`\n * propagate into every filing site's `gh issue create` prose.\n * When the consumer supplies no override, the bundle defaults\n * (`status:ready` + `priority:medium`) ship unchanged.\n *\n * Bundles that describe the build (`turborepo`, `github-workflow`)\n * accept a `ResolvedBuildPolicy` so the rendered guidance matches the\n * consumer's Turborepo configuration — most importantly, the\n * AWS-authentication note is emitted only when a remote cache is\n * actually configured, and names that consumer's own profile.\n *\n * Order matters: base is first so its rules can be overridden by\n * more specific bundles. The base bundle's `appliesWhen` always\n * returns true; it is filtered by the `includeBaseRules` option\n * in AgentConfig.\n *\n * Bundles that own a **config-driven convention rule** (`base`,\n * `orchestrator`) accept their resolved convention settings via\n * `conventions` so each rule's content is final the moment it enters\n * the rule map. Seeding resolved content up front — instead of\n * rewriting the rule after the map is assembled — is what lets\n * `AgentConfigOptions.ruleExtensions` appends and consumer-supplied\n * same-name `rules` entries compose with a convention override rather\n * than being clobbered by it.\n *\n * Bundles that do not read any agent path (typescript, jest,\n * pnpm, etc.) stay as const exports and are referenced unchanged.\n */\nexport function buildBuiltInBundles(\n  paths: ResolvedAgentPaths = DEFAULT_AGENT_PATHS,\n  issueDefaults: ResolvedIssueDefaults = DEFAULT_RESOLVED_ISSUE_DEFAULTS,\n  defaultAgentTier: AgentModel = AGENT_MODEL.BALANCED,\n  bundleAgentTiers: ReadonlyMap<string, AgentModel> = new Map(),\n  prReviewPolicy: ResolvedPrReviewPolicy = resolvePrReviewPolicy(),\n  buildPolicy: ResolvedBuildPolicy = DEFAULT_BUILD_POLICY,\n  conventions: ResolvedRuleConventions = DEFAULT_RULE_CONVENTIONS,\n): ReadonlyArray<AgentRuleBundle> {\n  const tierFor = (bundle: string): AgentModel =>\n    bundleAgentTiers.get(bundle) ?? defaultAgentTier;\n\n  return [\n    buildBaseBundle(paths, conventions.base),\n    upstreamConfigulatorDocsBundle,\n    typescriptBundle,\n    vitestBundle,\n    jestBundle,\n    buildTurborepoBundle(buildPolicy),\n    pnpmBundle,\n    awsCdkBundle,\n    projenBundle,\n    buildGithubWorkflowBundle(buildPolicy),\n    slackBundle,\n    buildMeetingAnalysisBundle(tierFor(\"meeting-analysis\")),\n    agendaBundle,\n    buildOrchestratorBundle(conventions.orchestrator),\n    buildPrReviewBundle(prReviewPolicy),\n    buildRequirementsAnalystBundle(paths, issueDefaults),\n    buildRequirementsWriterBundle(paths, issueDefaults),\n    buildRequirementsReviewerBundle(paths, issueDefaults),\n    buildResearchPipelineBundle(paths, issueDefaults),\n    buildCompanyProfileBundle(paths, issueDefaults, tierFor(\"company-profile\")),\n    buildCustomerProfileBundle(\n      paths,\n      issueDefaults,\n      tierFor(\"customer-profile\"),\n    ),\n    buildPeopleProfileBundle(paths, issueDefaults, tierFor(\"people-profile\")),\n    buildSoftwareProfileBundle(\n      paths,\n      issueDefaults,\n      tierFor(\"software-profile\"),\n    ),\n    buildIndustryDiscoveryBundle(paths, issueDefaults),\n    buildBusinessModelsBundle(paths, issueDefaults),\n    buildBcmWriterBundle(paths, issueDefaults),\n    buildStandardsResearchBundle(paths, issueDefaults),\n    buildRegulatoryResearchBundle(paths, issueDefaults),\n    buildMaintenanceAuditBundle(\n      paths,\n      issueDefaults,\n      tierFor(\"maintenance-audit\"),\n    ),\n    buildDocsSyncBundle(paths),\n  ];\n}\n\n/**\n * Built-in rule bundles assembled with the default agent paths.\n * Preserved for backward compatibility with tests and consumers\n * that import the array directly. Prefer `buildBuiltInBundles(paths)`\n * when consumer overrides are in scope.\n */\nexport const BUILT_IN_BUNDLES: ReadonlyArray<AgentRuleBundle> =\n  buildBuiltInBundles();\n","import * as path from \"node:path\";\nimport { Project, ProjenrcFile } from \"projen/lib\";\n\n/**\n * Minimal shape projen's `TypescriptConfig` exposes for reading back the\n * final `include` array. We duck-type against it because non-TypeScript\n * projects don't have `tsconfig` at all.\n */\ninterface TypescriptConfigLike {\n  readonly include: ReadonlyArray<string>;\n}\n\ninterface WithTsconfig {\n  readonly tsconfig?: TypescriptConfigLike;\n}\n\ninterface WithSrcdir {\n  readonly srcdir?: string;\n}\n\n/**\n * For each detected project, read its `tsconfig.include` and prefix each\n * entry with the project's outdir relative to the root. Returns a\n * deduplicated, sorted array of scoped glob patterns suitable for use as a\n * rule's `filePatterns`.\n *\n * Projects without a `tsconfig` fall back to `<relOutdir>/<srcdir>/**\\/*.ts`\n * (srcdir defaults to `\"src\"`), which matches projen's defaults for any\n * plain `TypeScriptProject`.\n *\n * A TypeScript `.projenrc.ts` is additionally surfaced from projen's\n * `Projenrc` component: projen registers it in eslint's `allowDefaultProject`\n * and keeps it out of every `tsconfig.include`, so it would otherwise be\n * invisible to the tsconfig-driven scoping above.\n */\nexport function scopeFilePatternsToProjects(\n  root: Project,\n  detected: ReadonlyArray<Project>,\n): Array<string> {\n  const patterns = new Set<string>();\n\n  for (const project of detected) {\n    const rel = path.relative(root.outdir, project.outdir);\n    const include = readTsconfigInclude(project);\n\n    if (include) {\n      // The project has a tsconfig — use its `include` verbatim. An\n      // explicitly empty include (e.g. the MonorepoProject shell root,\n      // which drops projen's default `<srcdir>/**\\/*.ts`) intentionally\n      // contributes no patterns. Only a project with no tsconfig at all\n      // falls back to the default src glob below.\n      for (const entry of include) {\n        patterns.add(prefix(rel, entry));\n      }\n    } else {\n      const srcdir = (project as WithSrcdir).srcdir ?? \"src\";\n      patterns.add(prefix(rel, path.posix.join(srcdir, \"**/*.ts\")));\n    }\n\n    const projenrcTs = readProjenrcTsFile(project);\n    if (projenrcTs) {\n      patterns.add(prefix(rel, projenrcTs));\n    }\n  }\n\n  return [...patterns].sort();\n}\n\n/**\n * Read the `tsconfig.include` array from a projen Project, if present.\n * Returns `undefined` for projects without a tsconfig component.\n */\nfunction readTsconfigInclude(\n  project: Project,\n): ReadonlyArray<string> | undefined {\n  const tsconfig = (project as WithTsconfig).tsconfig;\n  if (!tsconfig) {\n    return undefined;\n  }\n  return tsconfig.include;\n}\n\n/**\n * Return the project's projen-managed projenrc path when it is a TypeScript\n * file (`.projenrc.ts`). projen keeps `.projenrc.ts` out of every\n * `tsconfig.include` (it is registered in eslint's `allowDefaultProject`\n * instead), so we read it from projen's `Projenrc` component. Returns\n * `undefined` for a JavaScript projenrc or when none is present.\n */\nfunction readProjenrcTsFile(project: Project): string | undefined {\n  const filePath = ProjenrcFile.of(project)?.filePath;\n  return filePath?.endsWith(\".ts\") ? filePath : undefined;\n}\n\n/**\n * Join a project-relative prefix with a glob entry using POSIX separators so\n * rendered rule files are stable across platforms. An empty `rel` means the\n * detected project is the root itself — return the entry unchanged.\n */\nfunction prefix(rel: string, entry: string): string {\n  if (!rel) {\n    return entry;\n  }\n  return path.posix.join(rel, entry);\n}\n","import { Component, JsonFile } from \"projen\";\nimport { TextFile } from \"projen/lib/textfile\";\nimport { ClaudeSettingsConfig } from \"../agent-config-options\";\nimport {\n  AGENT_RULE_SCOPE,\n  AgentCommand,\n  AgentProcedure,\n  AgentRule,\n  AgentSkill,\n  AgentSubAgent,\n  CLAUDE_RULE_TARGET,\n  McpServerConfig,\n  resolveModelAlias,\n} from \"../types\";\n\nconst GENERATED_MARKER =\n  \"<!-- ~~ Generated by @codedrifters/configulator. Edits welcome — please contribute improvements back. ~~ -->\";\n\n/**\n * Renders agent configuration files for Claude Code.\n *\n * Output files:\n * - CLAUDE.md — always-active rules targeted to CLAUDE_MD\n * - `.claude/rules/{name}.md` — scoped rules with optional paths frontmatter\n * - .claude/settings.json — permissions, hooks, MCP servers, sandbox\n * - `.claude/skills/{name}/SKILL.md` — skill definitions\n * - `.claude/agents/{name}.md` — sub-agent definitions\n * - `.claude/procedures/{name}` — executable procedures (shell scripts)\n * - `.claude/commands/{name}.md` — user-invokable slash commands\n */\nexport class ClaudeRenderer {\n  /**\n   * Render all Claude Code configuration files.\n   */\n  public static render(\n    component: Component,\n    rules: ReadonlyArray<AgentRule>,\n    skills: ReadonlyArray<AgentSkill>,\n    subAgents: ReadonlyArray<AgentSubAgent>,\n    mcpServers: Readonly<Record<string, McpServerConfig>>,\n    settings?: ClaudeSettingsConfig,\n    procedures?: ReadonlyArray<AgentProcedure>,\n    commands?: ReadonlyArray<AgentCommand>,\n  ): void {\n    ClaudeRenderer.renderClaudeMd(component, rules);\n    ClaudeRenderer.renderScopedRules(component, rules);\n    ClaudeRenderer.renderSettings(component, mcpServers, settings);\n    ClaudeRenderer.renderSkills(component, skills);\n    ClaudeRenderer.renderSubAgents(component, subAgents);\n    if (procedures && procedures.length > 0) {\n      ClaudeRenderer.renderProcedures(component, procedures);\n    }\n    if (commands && commands.length > 0) {\n      ClaudeRenderer.renderCommands(component, commands);\n    }\n  }\n\n  private static renderClaudeMd(\n    component: Component,\n    rules: ReadonlyArray<AgentRule>,\n  ): void {\n    const claudeMdRules = rules.filter((r) => {\n      if (r.platforms?.claude?.exclude) return false;\n      const target =\n        r.platforms?.claude?.target ?? ClaudeRenderer.defaultTarget(r);\n      return target === CLAUDE_RULE_TARGET.CLAUDE_MD;\n    });\n\n    if (claudeMdRules.length === 0) return;\n\n    const lines: string[] = [GENERATED_MARKER, \"\"];\n    for (let i = 0; i < claudeMdRules.length; i++) {\n      if (i > 0) lines.push(\"\", \"---\", \"\");\n      lines.push(...claudeMdRules[i].content.split(\"\\n\"));\n    }\n\n    new TextFile(component, \"CLAUDE.md\", { lines });\n  }\n\n  private static renderScopedRules(\n    component: Component,\n    rules: ReadonlyArray<AgentRule>,\n  ): void {\n    const scopedRules = rules.filter((r) => {\n      if (r.platforms?.claude?.exclude) return false;\n      const target =\n        r.platforms?.claude?.target ?? ClaudeRenderer.defaultTarget(r);\n      return target === CLAUDE_RULE_TARGET.SCOPED_FILE;\n    });\n\n    for (const rule of scopedRules) {\n      const lines: string[] = [];\n\n      if (rule.filePatterns && rule.filePatterns.length > 0) {\n        lines.push(\"---\");\n        lines.push(\"paths:\");\n        for (const pattern of rule.filePatterns) {\n          lines.push(`  - \"${pattern}\"`);\n        }\n        lines.push(\"---\");\n        lines.push(\"\");\n      }\n\n      lines.push(...rule.content.split(\"\\n\"));\n\n      new TextFile(component, `.claude/rules/${rule.name}.md`, { lines });\n    }\n  }\n\n  private static renderSettings(\n    component: Component,\n    mcpServers: Readonly<Record<string, McpServerConfig>>,\n    settings?: ClaudeSettingsConfig,\n  ): void {\n    const obj: Record<string, unknown> = {};\n    let hasContent = false;\n\n    if (settings?.defaultMode) {\n      obj.defaultMode = settings.defaultMode;\n      hasContent = true;\n    }\n\n    if (settings?.permissions) {\n      const perms: Record<string, unknown> = {};\n      if (settings.permissions.allow?.length) {\n        perms.allow = [...settings.permissions.allow];\n      }\n      if (settings.permissions.deny?.length) {\n        perms.deny = [...settings.permissions.deny];\n      }\n      if (settings.permissions.ask?.length) {\n        perms.ask = [...settings.permissions.ask];\n      }\n      if (settings.permissions.additionalDirectories?.length) {\n        perms.additionalDirectories = [\n          ...settings.permissions.additionalDirectories,\n        ];\n      }\n      if (Object.keys(perms).length > 0) {\n        obj.permissions = perms;\n        hasContent = true;\n      }\n    }\n\n    if (settings?.hooks) {\n      const hooks: Record<string, unknown> = {};\n      for (const [event, entries] of Object.entries(settings.hooks)) {\n        if (entries && entries.length > 0) {\n          hooks[event] = entries;\n        }\n      }\n      if (Object.keys(hooks).length > 0) {\n        obj.hooks = hooks;\n        hasContent = true;\n      }\n    }\n\n    // MCP servers from both cross-platform and Claude-specific config\n    const allMcpServers: Record<string, unknown> = {};\n\n    // Cross-platform MCP servers\n    for (const [name, config] of Object.entries(mcpServers)) {\n      allMcpServers[name] = ClaudeRenderer.buildMcpServerObj(config);\n    }\n\n    // Claude-specific MCP servers\n    if (settings?.mcpServers) {\n      for (const [name, config] of Object.entries(settings.mcpServers)) {\n        allMcpServers[name] = ClaudeRenderer.buildMcpServerObj(config);\n      }\n    }\n\n    if (Object.keys(allMcpServers).length > 0) {\n      obj.mcpServers = allMcpServers;\n      hasContent = true;\n    }\n\n    if (settings?.allowedMcpServers?.length) {\n      obj.allowedMcpServers = [...settings.allowedMcpServers];\n      hasContent = true;\n    }\n\n    if (settings?.deniedMcpServers?.length) {\n      obj.deniedMcpServers = [...settings.deniedMcpServers];\n      hasContent = true;\n    }\n\n    if (settings?.env && Object.keys(settings.env).length > 0) {\n      obj.env = { ...settings.env };\n      hasContent = true;\n    }\n\n    if (settings?.sandbox) {\n      obj.sandbox = ClaudeRenderer.buildSandboxObj(settings.sandbox);\n      hasContent = true;\n    }\n\n    if (settings?.autoMode) {\n      const autoMode: Record<string, unknown> = {};\n      if (settings.autoMode.environment?.length) {\n        autoMode.environment = [...settings.autoMode.environment];\n      }\n      if (settings.autoMode.allow?.length) {\n        autoMode.allow = [...settings.autoMode.allow];\n      }\n      if (settings.autoMode.soft_deny?.length) {\n        autoMode.soft_deny = [...settings.autoMode.soft_deny];\n      }\n      if (Object.keys(autoMode).length > 0) {\n        obj.autoMode = autoMode;\n        hasContent = true;\n      }\n    }\n\n    if (settings?.disableBypassPermissionsMode) {\n      obj.disableBypassPermissionsMode = settings.disableBypassPermissionsMode;\n      hasContent = true;\n    }\n\n    if (settings?.disableAutoMode) {\n      obj.disableAutoMode = settings.disableAutoMode;\n      hasContent = true;\n    }\n\n    if (settings?.disableAllHooks !== undefined) {\n      obj.disableAllHooks = settings.disableAllHooks;\n      hasContent = true;\n    }\n\n    if (settings?.excludeSensitivePatterns?.length) {\n      obj.excludeSensitivePatterns = [...settings.excludeSensitivePatterns];\n      hasContent = true;\n    }\n\n    if (settings?.model) {\n      obj.model = settings.model;\n      hasContent = true;\n    }\n\n    if (settings?.effortLevel) {\n      obj.effortLevel = settings.effortLevel;\n      hasContent = true;\n    }\n\n    if (settings?.attribution) {\n      obj.attribution = settings.attribution;\n      hasContent = true;\n    }\n\n    if (settings?.claudeMdExcludes?.length) {\n      obj.claudeMdExcludes = [...settings.claudeMdExcludes];\n      hasContent = true;\n    }\n\n    if (settings?.respectGitignore !== undefined) {\n      obj.respectGitignore = settings.respectGitignore;\n      hasContent = true;\n    }\n\n    if (!hasContent) return;\n\n    new JsonFile(component, \".claude/settings.json\", { obj });\n  }\n\n  private static buildSandboxObj(\n    sandbox: NonNullable<ClaudeSettingsConfig[\"sandbox\"]>,\n  ): Record<string, unknown> {\n    const obj: Record<string, unknown> = {};\n    if (sandbox.enabled !== undefined) obj.enabled = sandbox.enabled;\n    if (sandbox.mode) obj.mode = sandbox.mode;\n    if (sandbox.failIfUnavailable !== undefined) {\n      obj.failIfUnavailable = sandbox.failIfUnavailable;\n    }\n    if (sandbox.autoAllowBashIfSandboxed !== undefined) {\n      obj.autoAllowBashIfSandboxed = sandbox.autoAllowBashIfSandboxed;\n    }\n    if (sandbox.excludedCommands?.length) {\n      obj.excludedCommands = [...sandbox.excludedCommands];\n    }\n    if (sandbox.filesystem) {\n      const fs: Record<string, unknown> = {};\n      if (sandbox.filesystem.allowRead?.length) {\n        fs.allowRead = [...sandbox.filesystem.allowRead];\n      }\n      if (sandbox.filesystem.denyRead?.length) {\n        fs.denyRead = [...sandbox.filesystem.denyRead];\n      }\n      if (sandbox.filesystem.allowWrite?.length) {\n        fs.allowWrite = [...sandbox.filesystem.allowWrite];\n      }\n      if (sandbox.filesystem.denyWrite?.length) {\n        fs.denyWrite = [...sandbox.filesystem.denyWrite];\n      }\n      if (Object.keys(fs).length > 0) obj.filesystem = fs;\n    }\n    if (sandbox.network) {\n      const net: Record<string, unknown> = {};\n      if (sandbox.network.allowedDomains?.length) {\n        net.allowedDomains = [...sandbox.network.allowedDomains];\n      }\n      if (sandbox.network.denyDomains?.length) {\n        net.denyDomains = [...sandbox.network.denyDomains];\n      }\n      if (Object.keys(net).length > 0) obj.network = net;\n    }\n    return obj;\n  }\n\n  private static renderSkills(\n    component: Component,\n    skills: ReadonlyArray<AgentSkill>,\n  ): void {\n    for (const skill of skills) {\n      if (skill.platforms?.claude?.exclude) continue;\n\n      const lines: string[] = [];\n      lines.push(\"---\");\n      lines.push(`name: \"${skill.name}\"`);\n      lines.push(`description: \"${skill.description}\"`);\n      if (skill.disableModelInvocation) {\n        lines.push(`disable-model-invocation: true`);\n      }\n      if (skill.userInvocable === false) {\n        lines.push(`user-invocable: false`);\n      }\n      const resolvedSkillModel = resolveModelAlias(skill.model);\n      if (resolvedSkillModel) {\n        lines.push(`model: \"${resolvedSkillModel}\"`);\n      }\n      if (skill.effort) {\n        lines.push(`effort: \"${skill.effort}\"`);\n      }\n      if (skill.paths && skill.paths.length > 0) {\n        lines.push(`paths:`);\n        for (const p of skill.paths) {\n          lines.push(`  - \"${p}\"`);\n        }\n      }\n      if (skill.context) {\n        lines.push(`context: \"${skill.context}\"`);\n      }\n      if (skill.agent) {\n        lines.push(`agent: \"${skill.agent}\"`);\n      }\n      if (skill.shell) {\n        lines.push(`shell: \"${skill.shell}\"`);\n      }\n      if (skill.allowedTools && skill.allowedTools.length > 0) {\n        lines.push(`allowed-tools:`);\n        for (const tool of skill.allowedTools) {\n          lines.push(`  - \"${tool}\"`);\n        }\n      }\n      lines.push(\"---\");\n      lines.push(\"\");\n      lines.push(...skill.instructions.split(\"\\n\"));\n\n      new TextFile(component, `.claude/skills/${skill.name}/SKILL.md`, {\n        lines,\n      });\n\n      if (skill.referenceFiles && skill.referenceFiles.length > 0) {\n        for (const file of skill.referenceFiles) {\n          new TextFile(component, `.claude/skills/${skill.name}/${file.path}`, {\n            lines: file.content.split(\"\\n\"),\n          });\n        }\n      }\n    }\n  }\n\n  private static renderSubAgents(\n    component: Component,\n    subAgents: ReadonlyArray<AgentSubAgent>,\n  ): void {\n    for (const agent of subAgents) {\n      if (agent.platforms?.claude?.exclude) continue;\n\n      const lines: string[] = [];\n      lines.push(\"---\");\n      lines.push(`name: ${agent.name}`);\n      lines.push(`description: >-`);\n      lines.push(`  ${agent.description}`);\n      const resolvedModel = resolveModelAlias(agent.model);\n      if (resolvedModel) {\n        lines.push(`model: ${resolvedModel}`);\n      }\n      if (agent.tools && agent.tools.length > 0) {\n        lines.push(`tools:`);\n        for (const tool of agent.tools) {\n          lines.push(`  - \"${tool}\"`);\n        }\n      }\n      if (agent.disallowedTools && agent.disallowedTools.length > 0) {\n        lines.push(`disallowedTools:`);\n        for (const tool of agent.disallowedTools) {\n          lines.push(`  - \"${tool}\"`);\n        }\n      }\n      if (agent.maxTurns) {\n        lines.push(`maxTurns: ${agent.maxTurns}`);\n      }\n      if (agent.skills && agent.skills.length > 0) {\n        lines.push(`skills:`);\n        for (const skill of agent.skills) {\n          lines.push(`  - \"${skill}\"`);\n        }\n      }\n      if (agent.platforms?.claude?.permissionMode) {\n        lines.push(`permissionMode: ${agent.platforms.claude.permissionMode}`);\n      }\n      if (agent.platforms?.claude?.isolation) {\n        lines.push(`isolation: ${agent.platforms.claude.isolation}`);\n      }\n      if (agent.platforms?.claude?.background) {\n        lines.push(`background: true`);\n      }\n      if (agent.platforms?.claude?.effort) {\n        lines.push(`effort: ${agent.platforms.claude.effort}`);\n      }\n      if (agent.platforms?.claude?.memory) {\n        lines.push(`memory: ${agent.platforms.claude.memory}`);\n      }\n      lines.push(\"---\");\n      lines.push(\"\");\n      lines.push(...agent.prompt.split(\"\\n\"));\n\n      new TextFile(component, `.claude/agents/${agent.name}.md`, { lines });\n    }\n  }\n\n  private static buildMcpServerObj(\n    config: McpServerConfig,\n  ): Record<string, unknown> {\n    const server: Record<string, unknown> = {};\n    if (config.transport) server.type = config.transport;\n    if (config.command) server.command = config.command;\n    if (config.args) server.args = [...config.args];\n    if (config.url) server.url = config.url;\n    if (config.headers && Object.keys(config.headers).length > 0) {\n      server.headers = { ...config.headers };\n    }\n    if (config.env) server.env = { ...config.env };\n    return server;\n  }\n\n  private static renderProcedures(\n    component: Component,\n    procedures: ReadonlyArray<AgentProcedure>,\n  ): void {\n    for (const proc of procedures) {\n      new TextFile(component, `.claude/procedures/${proc.name}`, {\n        lines: proc.content.split(\"\\n\"),\n        executable: true,\n      });\n    }\n  }\n\n  /**\n   * Renders user-invokable slash commands to `.claude/commands/<name>.md`.\n   *\n   * Each command file carries a YAML frontmatter block with the\n   * `description` (always present) and an optional `model` alias. The\n   * body is the {@link AgentCommand.content} written verbatim.\n   *\n   * @see https://docs.claude.com/en/docs/claude-code/slash-commands\n   */\n  private static renderCommands(\n    component: Component,\n    commands: ReadonlyArray<AgentCommand>,\n  ): void {\n    for (const command of commands) {\n      const lines: string[] = [];\n      lines.push(\"---\");\n      lines.push(`description: ${command.description}`);\n      const resolvedModel = resolveModelAlias(command.model);\n      if (resolvedModel) {\n        lines.push(`model: ${resolvedModel}`);\n      }\n      lines.push(\"---\");\n      lines.push(\"\");\n      lines.push(...command.content.split(\"\\n\"));\n\n      new TextFile(component, `.claude/commands/${command.name}.md`, { lines });\n    }\n  }\n\n  /**\n   * Determine the default Claude rule target based on rule scope.\n   * ALWAYS-scoped rules default to CLAUDE_MD; FILE_PATTERN rules default to SCOPED_FILE.\n   */\n  private static defaultTarget(rule: AgentRule): string {\n    return rule.scope === AGENT_RULE_SCOPE.ALWAYS\n      ? CLAUDE_RULE_TARGET.CLAUDE_MD\n      : CLAUDE_RULE_TARGET.SCOPED_FILE;\n  }\n}\n","import { Component, JsonFile } from \"projen\";\nimport { TextFile } from \"projen/lib/textfile\";\nimport { CursorSettingsConfig } from \"../agent-config-options\";\nimport {\n  AGENT_RULE_SCOPE,\n  AgentRule,\n  AgentSkill,\n  AgentSubAgent,\n  McpServerConfig,\n} from \"../types\";\n\nconst GENERATED_MARKER =\n  \"# ~~ Generated by @codedrifters/configulator. Edits welcome — please contribute improvements back. ~~\";\n\n/**\n * Renders agent configuration files for Cursor.\n *\n * Output files:\n * - `.cursor/rules/{name}.mdc` — YAML frontmatter + markdown body\n * - `.cursor/agents/{name}.md` — sub-agent definitions\n * - .cursor/mcp.json — MCP server configuration\n * - .cursor/hooks.json — lifecycle hooks\n * - .cursorignore — hard security boundary\n * - .cursorindexingignore — soft indexing boundary\n */\nexport class CursorRenderer {\n  /**\n   * Render all Cursor configuration files.\n   */\n  public static render(\n    component: Component,\n    rules: ReadonlyArray<AgentRule>,\n    skills: ReadonlyArray<AgentSkill>,\n    subAgents: ReadonlyArray<AgentSubAgent>,\n    mcpServers: Readonly<Record<string, McpServerConfig>>,\n    settings?: CursorSettingsConfig,\n  ): void {\n    CursorRenderer.renderRules(component, rules);\n    CursorRenderer.renderSkills(component, skills);\n    CursorRenderer.renderSubAgents(component, subAgents);\n    CursorRenderer.renderMcpServers(component, mcpServers);\n    CursorRenderer.renderHooks(component, settings);\n    CursorRenderer.renderIgnoreFiles(component, settings);\n  }\n\n  private static renderRules(\n    component: Component,\n    rules: ReadonlyArray<AgentRule>,\n  ): void {\n    for (const rule of rules) {\n      if (rule.platforms?.cursor?.exclude) continue;\n\n      const lines: string[] = [];\n      const description =\n        rule.platforms?.cursor?.description ?? rule.description;\n      const isAlways = rule.scope === AGENT_RULE_SCOPE.ALWAYS;\n\n      // YAML frontmatter\n      lines.push(\"---\");\n      lines.push(`description: \"${description}\"`);\n      lines.push(`alwaysApply: ${isAlways}`);\n      if (!isAlways && rule.filePatterns && rule.filePatterns.length > 0) {\n        lines.push(`path: ${JSON.stringify([...rule.filePatterns])}`);\n      }\n      lines.push(\"---\");\n      lines.push(\"\");\n      lines.push(...rule.content.split(\"\\n\"));\n\n      new TextFile(component, `.cursor/rules/${rule.name}.mdc`, { lines });\n    }\n  }\n\n  private static renderSkills(\n    component: Component,\n    skills: ReadonlyArray<AgentSkill>,\n  ): void {\n    for (const skill of skills) {\n      if (skill.platforms?.cursor?.exclude) continue;\n\n      const lines: string[] = [];\n      lines.push(\"---\");\n      lines.push(`name: \"${skill.name}\"`);\n      lines.push(`description: \"${skill.description}\"`);\n      if (skill.disableModelInvocation) {\n        lines.push(`disable-model-invocation: true`);\n      }\n      if (skill.userInvocable === false) {\n        lines.push(`user-invocable: false`);\n      }\n      if (skill.context) {\n        lines.push(`context: \"${skill.context}\"`);\n      }\n      if (skill.agent) {\n        lines.push(`agent: \"${skill.agent}\"`);\n      }\n      if (skill.shell) {\n        lines.push(`shell: \"${skill.shell}\"`);\n      }\n      if (skill.allowedTools && skill.allowedTools.length > 0) {\n        lines.push(`allowed-tools:`);\n        for (const tool of skill.allowedTools) {\n          lines.push(`  - \"${tool}\"`);\n        }\n      }\n      lines.push(\"---\");\n      lines.push(\"\");\n      lines.push(...skill.instructions.split(\"\\n\"));\n\n      new TextFile(component, `.cursor/skills/${skill.name}/SKILL.md`, {\n        lines,\n      });\n\n      if (skill.referenceFiles && skill.referenceFiles.length > 0) {\n        for (const file of skill.referenceFiles) {\n          new TextFile(component, `.cursor/skills/${skill.name}/${file.path}`, {\n            lines: file.content.split(\"\\n\"),\n          });\n        }\n      }\n    }\n  }\n\n  private static renderSubAgents(\n    component: Component,\n    subAgents: ReadonlyArray<AgentSubAgent>,\n  ): void {\n    for (const agent of subAgents) {\n      if (agent.platforms?.cursor?.exclude) continue;\n\n      const lines: string[] = [];\n      lines.push(\"---\");\n      lines.push(`name: ${agent.name}`);\n      lines.push(`description: >-`);\n      lines.push(`  ${agent.description}`);\n      // Cursor uses its own model selection; omit the model field\n      // to let it use its default (e.g., composer).\n      if (agent.platforms?.cursor?.readonly) {\n        lines.push(`readonly: true`);\n      }\n      if (agent.platforms?.cursor?.isBackground) {\n        lines.push(`is_background: true`);\n      }\n      lines.push(\"---\");\n      lines.push(\"\");\n      lines.push(...agent.prompt.split(\"\\n\"));\n\n      new TextFile(component, `.cursor/agents/${agent.name}.md`, { lines });\n    }\n  }\n\n  private static renderMcpServers(\n    component: Component,\n    mcpServers: Readonly<Record<string, McpServerConfig>>,\n  ): void {\n    const serverNames = Object.keys(mcpServers);\n    if (serverNames.length === 0) return;\n\n    const obj: Record<string, unknown> = { mcpServers: {} };\n    const servers = obj.mcpServers as Record<string, unknown>;\n\n    for (const [name, config] of Object.entries(mcpServers)) {\n      const server: Record<string, unknown> = {};\n      if (config.transport) server.transport = config.transport;\n      if (config.command) server.command = config.command;\n      if (config.args) server.args = [...config.args];\n      if (config.url) server.url = config.url;\n      if (config.headers && Object.keys(config.headers).length > 0) {\n        server.headers = { ...config.headers };\n      }\n      if (config.env) server.env = { ...config.env };\n      servers[name] = server;\n    }\n\n    new JsonFile(component, \".cursor/mcp.json\", { obj });\n  }\n\n  private static renderHooks(\n    component: Component,\n    settings?: CursorSettingsConfig,\n  ): void {\n    if (!settings?.hooks) return;\n\n    const hooks: Record<string, unknown[]> = {};\n    const hookEntries = settings.hooks;\n\n    // Render all hook events dynamically\n    for (const [event, actions] of Object.entries(hookEntries)) {\n      if (actions && actions.length > 0) {\n        hooks[event] = actions.map((h: { command: string }) => ({\n          command: h.command,\n        }));\n      }\n    }\n\n    if (Object.keys(hooks).length === 0) return;\n\n    new JsonFile(component, \".cursor/hooks.json\", {\n      obj: { version: 1, hooks },\n    });\n  }\n\n  private static renderIgnoreFiles(\n    component: Component,\n    settings?: CursorSettingsConfig,\n  ): void {\n    if (settings?.ignorePatterns && settings.ignorePatterns.length > 0) {\n      new TextFile(component, \".cursorignore\", {\n        lines: [GENERATED_MARKER, \"\", ...settings.ignorePatterns],\n      });\n    }\n\n    if (\n      settings?.indexingIgnorePatterns &&\n      settings.indexingIgnorePatterns.length > 0\n    ) {\n      new TextFile(component, \".cursorindexingignore\", {\n        lines: [GENERATED_MARKER, \"\", ...settings.indexingIgnorePatterns],\n      });\n    }\n  }\n}\n","import { ResolvedProjectMetadata } from \"../projects/project-metadata-options\";\n\n/**\n * Default fallback placeholders for unresolved template variables.\n */\nconst FALLBACKS: Record<string, string> = {\n  \"repository.owner\": \"<owner>\",\n  \"repository.name\": \"<repo>\",\n  \"repository.defaultBranch\": \"main\",\n  \"organization.name\": \"<organization>\",\n  \"organization.githubOrg\": \"<org>\",\n  \"githubProject.name\": \"<project-name>\",\n  \"githubProject.number\": \"<project-number>\",\n  \"githubProject.nodeId\": \"<project-node-id>\",\n  docsPath: \"<docs-path>\",\n  // The monorepo-layout seed block is additive: when absent, the\n  // seeded `project-context.md` template reads cleanly without it.\n  // Fall back to an empty string so no placeholder text leaks into\n  // rendered prompts for repos that predate the layout contract.\n  monorepoLayoutSeedBlock: \"\",\n};\n\n/** Matches `{{dotted.path}}` template variables. */\nconst TEMPLATE_RE = /\\{\\{(\\w+(?:\\.\\w+)*)\\}\\}/g;\n\n/**\n * Looks up a dotted path (e.g., \"repository.owner\") on a metadata object.\n * Returns the value as a string, or undefined if not found.\n */\nfunction getNestedValue(\n  obj: Record<string, unknown>,\n  path: string,\n): string | undefined {\n  const parts = path.split(\".\");\n  let current: unknown = obj;\n\n  for (const part of parts) {\n    if (current == null || typeof current !== \"object\") {\n      return undefined;\n    }\n    current = (current as Record<string, unknown>)[part];\n  }\n\n  if (current == null) {\n    return undefined;\n  }\n\n  return String(current);\n}\n\n/**\n * Result of template variable resolution.\n */\nexport interface TemplateResolveResult {\n  /** The template string with all variables resolved or replaced with fallbacks. */\n  readonly resolved: string;\n  /** Template variable keys that could not be resolved from metadata. */\n  readonly unresolvedKeys: ReadonlyArray<string>;\n}\n\n/**\n * Resolves `{{dotted.path}}` template variables in a string using project metadata.\n * Unresolved variables are replaced with their fallback placeholders.\n *\n * @param template - String potentially containing `{{variable}}` patterns\n * @param metadata - Resolved project metadata, or undefined if not available\n * @returns The resolved string and a list of any unresolved variable keys\n */\nexport function resolveTemplateVariables(\n  template: string,\n  metadata: ResolvedProjectMetadata | undefined,\n): TemplateResolveResult {\n  if (!TEMPLATE_RE.test(template)) {\n    return { resolved: template, unresolvedKeys: [] };\n  }\n\n  const unresolvedKeys: string[] = [];\n\n  // Reset regex lastIndex since we used .test() above\n  TEMPLATE_RE.lastIndex = 0;\n\n  const resolved = template.replace(TEMPLATE_RE, (_match, key: string) => {\n    if (metadata) {\n      const value = getNestedValue(\n        metadata as unknown as Record<string, unknown>,\n        key,\n      );\n      if (value !== undefined) {\n        return value;\n      }\n    }\n\n    unresolvedKeys.push(key);\n    return FALLBACKS[key] ?? `<${key}>`;\n  });\n\n  return { resolved, unresolvedKeys };\n}\n","import { Component } from \"projen\";\nimport { AgentRule, AgentSkill, AgentSubAgent } from \"../types\";\n\n/**\n * Renders agent configuration files for OpenAI Codex.\n *\n * Output files (future):\n * - AGENTS.md — root-level instructions\n * - `{dir}/AGENTS.md` — directory-scoped instructions\n *\n * TODO: Implement in a future issue.\n */\nexport class CodexRenderer {\n  public static render(\n    _component: Component,\n    _rules: ReadonlyArray<AgentRule>,\n    _skills: ReadonlyArray<AgentSkill>,\n    _subAgents: ReadonlyArray<AgentSubAgent>,\n  ): void {\n    // Codex renderer is not yet implemented.\n  }\n}\n","import { Component } from \"projen\";\nimport { AgentRule, AgentSkill, AgentSubAgent } from \"../types\";\n\n/**\n * Renders agent configuration files for GitHub Copilot.\n *\n * Output files (future):\n * - .github/copilot-instructions.md — root instructions\n * - .github/instructions/*.instructions.md — scoped instructions\n *\n * TODO: Implement in a future issue.\n */\nexport class CopilotRenderer {\n  public static render(\n    _component: Component,\n    _rules: ReadonlyArray<AgentRule>,\n    _skills: ReadonlyArray<AgentSkill>,\n    _subAgents: ReadonlyArray<AgentSubAgent>,\n  ): void {\n    // Copilot renderer is not yet implemented.\n  }\n}\n","import { Component } from \"projen\";\nimport { NodeProject } from \"projen/lib/javascript\";\nimport { JsonFile } from \"projen/lib/json\";\nimport { VERSION } from \"../versions\";\n\n/**\n * Options for the `.api.md` rollup slot produced by API Extractor.\n */\nexport interface ApiExtractorReportOptions {\n  /**\n   * Folder (relative to the package root) where the `.api.md` rollup\n   * is written when the extractor runs. Treated as a scratch/temp\n   * location because rollups are **regenerated on scan** rather than\n   * committed to git (per docs-sync epic #448 resolved decision #3).\n   *\n   * The parent `ApiExtractor` component adds this folder to the\n   * package's `.gitignore` so rollups never land on the default branch.\n   *\n   * @default \".api-extractor/\"\n   */\n  readonly reportFolder?: string;\n\n  /**\n   * Filename of the generated rollup, relative to `reportFolder`.\n   * Accepts the `<unscopedPackageName>` placeholder API Extractor\n   * expands at runtime.\n   *\n   * @default \"<unscopedPackageName>.api.md\"\n   */\n  readonly reportFileName?: string;\n}\n\n/**\n * Options for the `ApiExtractor` projen component.\n */\nexport interface ApiExtractorOptions {\n  /**\n   * Path to the TypeScript `.d.ts` rollup produced by the package's\n   * compile step, relative to the package root. Used as the\n   * extractor's `mainEntryPointFilePath`.\n   *\n   * Defaults to `<projectFolder>/lib/index.d.ts` — matches the\n   * `TypeScriptProject` default layout.\n   *\n   * @default \"<projectFolder>/lib/index.d.ts\"\n   */\n  readonly mainEntryPointFilePath?: string;\n\n  /**\n   * Path to the generated `api-extractor.json` config file (relative\n   * to the package root).\n   *\n   * @default \"api-extractor.json\"\n   */\n  readonly configFilePath?: string;\n\n  /**\n   * Rollup report options (where the `.api.md` lands).\n   */\n  readonly report?: ApiExtractorReportOptions;\n\n  /**\n   * Override the version of `@microsoft/api-extractor` that is added\n   * to the package's devDeps. Defaults to `VERSION.API_EXTRACTOR_VERSION`.\n   */\n  readonly apiExtractorVersion?: string;\n\n  /**\n   * When `true`, the extractor's `.api.md` rollup is treated as the\n   * committed baseline and diff-checked in-place. The docs-sync epic\n   * deliberately sets this to `false` — rollups are regenerate-on-scan\n   * and not committed to git.\n   *\n   * @default false\n   */\n  readonly commitApiReport?: boolean;\n}\n\n/**\n * Default folder where `.api.md` rollups are written. Gitignored by\n * the component so rollups never land in a commit.\n */\nexport const DEFAULT_API_EXTRACTOR_REPORT_FOLDER = \".api-extractor/\";\n\n/**\n * Default filename template for rollups. The `<unscopedPackageName>`\n * placeholder is expanded by `@microsoft/api-extractor` at run time.\n */\nexport const DEFAULT_API_EXTRACTOR_REPORT_FILENAME =\n  \"<unscopedPackageName>.api.md\";\n\n/**\n * Default path (relative to the package root) to the TypeScript\n * `.d.ts` rollup the extractor consumes. Matches the\n * `TypeScriptProject` default output layout.\n */\nexport const DEFAULT_API_EXTRACTOR_ENTRY_POINT =\n  \"<projectFolder>/lib/index.d.ts\";\n\n/**\n * Default path (relative to the package root) to the generated\n * `api-extractor.json` config file.\n */\nexport const DEFAULT_API_EXTRACTOR_CONFIG_FILE = \"api-extractor.json\";\n\n/**\n * Wires `@microsoft/api-extractor` into a TypeScript project so the\n * docs-sync pipeline can detect public-API drift introduced by a\n * diff.\n *\n * The component adds the extractor devDep, synthesizes an\n * `api-extractor.json` under the package root, and gitignores the\n * generated `.api.md` rollup. Rollups are **regenerated on scan**\n * (never committed to git) per docs-sync epic #448 resolved\n * decision #3 — the in-repo helper at\n * `.claude/procedures/extract-api.sh` runs the extractor end-to-end\n * and writes the rollup to the scratch folder for the scan phase\n * to consume in-memory.\n *\n * Callers normally do not construct this directly — the\n * `TypeScriptProject` constructor creates one automatically.\n */\nexport class ApiExtractor extends Component {\n  /**\n   * Find the ApiExtractor component on a project.\n   */\n  public static of(project: NodeProject): ApiExtractor | undefined {\n    const isDefined = (c: Component): c is ApiExtractor =>\n      c instanceof ApiExtractor;\n    return project.components.find(isDefined);\n  }\n\n  /**\n   * Generated config file path, relative to the package root.\n   */\n  public readonly configFilePath: string;\n\n  /**\n   * Entry-point path supplied to the extractor.\n   */\n  public readonly mainEntryPointFilePath: string;\n\n  /**\n   * Folder where `.api.md` rollups are written.\n   */\n  public readonly reportFolder: string;\n\n  /**\n   * Filename (or filename template) of the rollup.\n   */\n  public readonly reportFileName: string;\n\n  /**\n   * Pinned version of `@microsoft/api-extractor`.\n   */\n  public readonly apiExtractorVersion: string;\n\n  /**\n   * Whether the generated report is committed alongside source.\n   * `false` by default — rollups regenerate on scan.\n   */\n  public readonly commitApiReport: boolean;\n\n  constructor(\n    public readonly project: NodeProject,\n    options: ApiExtractorOptions = {},\n  ) {\n    super(project);\n\n    this.configFilePath =\n      options.configFilePath ?? DEFAULT_API_EXTRACTOR_CONFIG_FILE;\n    this.mainEntryPointFilePath =\n      options.mainEntryPointFilePath ?? DEFAULT_API_EXTRACTOR_ENTRY_POINT;\n    this.reportFolder =\n      options.report?.reportFolder ?? DEFAULT_API_EXTRACTOR_REPORT_FOLDER;\n    this.reportFileName =\n      options.report?.reportFileName ?? DEFAULT_API_EXTRACTOR_REPORT_FILENAME;\n    this.apiExtractorVersion =\n      options.apiExtractorVersion ?? VERSION.API_EXTRACTOR_VERSION;\n    this.commitApiReport = options.commitApiReport ?? false;\n\n    /**\n     * Add the extractor as a devDep. Pinned to a concrete version so\n     * every consuming package runs the same rollup logic.\n     */\n    project.addDevDeps(`@microsoft/api-extractor@${this.apiExtractorVersion}`);\n\n    /**\n     * Rollups are regenerate-on-scan by default. Gitignore the\n     * scratch folder so no `.api.md` file can land on the default\n     * branch by accident.\n     */\n    if (!this.commitApiReport) {\n      const normalizedFolder = this.reportFolder.replace(/\\/$/, \"\");\n      project.gitignore.addPatterns(\n        `/${normalizedFolder}/`,\n        `${normalizedFolder}/**/*.api.md`,\n        // Defensive: api-extractor's default `reportTempFolder` is\n        // `<projectFolder>/temp/` when not overridden. Our generated\n        // config routes that into `reportFolder` already, but a stale\n        // extractor or a hand-edited config could still produce a\n        // `temp/` folder. Ignore it so rollups never leak into git.\n        \"/temp/\",\n      );\n      project.npmignore?.addPatterns(`/${normalizedFolder}/`, \"/temp/\");\n    }\n\n    /**\n     * `api-extractor.json` is a dev-time config — it doesn't need to\n     * ship to npm consumers of the package.\n     */\n    project.npmignore?.addPatterns(`/${this.configFilePath}`);\n\n    /**\n     * Generate `api-extractor.json` so every package can be extracted\n     * with a one-liner. Kept minimal — only the knobs the docs-sync\n     * scan phase actually reads are turned on.\n     *\n     * `marker: false` — api-extractor's JSON schema is strict\n     * (`additionalProperties: false`) and rejects projen's usual\n     * `\"//\"` generated-by comment. The `linguist-generated` git\n     * attribute still flags the file as generated in diffs.\n     */\n    new JsonFile(project, this.configFilePath, {\n      marker: false,\n      obj: this.renderConfig(),\n    });\n  }\n\n  /**\n   * Render the JSON body of the generated `api-extractor.json`. Kept\n   * as a public method so tests can assert the shape without going\n   * through `synthSnapshot`.\n   */\n  public renderConfig(): Record<string, unknown> {\n    return {\n      $schema:\n        \"https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json\",\n      projectFolder: \".\",\n      mainEntryPointFilePath: this.mainEntryPointFilePath,\n      bundledPackages: [],\n      compiler: {\n        tsconfigFilePath: \"<projectFolder>/tsconfig.json\",\n      },\n      apiReport: {\n        enabled: true,\n        reportFolder: `<projectFolder>/${this.reportFolder}`,\n        // Route the \"temp\" rollup copy that api-extractor always\n        // writes into the same scratch folder so it inherits the\n        // gitignore entry. The default (`<projectFolder>/temp/`)\n        // would land beside the source tree and be tracked by git.\n        reportTempFolder: `<projectFolder>/${this.reportFolder}`,\n        reportFileName: this.reportFileName,\n        includeForgottenExports: false,\n      },\n      docModel: {\n        enabled: false,\n      },\n      dtsRollup: {\n        enabled: false,\n      },\n      tsdocMetadata: {\n        enabled: false,\n      },\n      messages: {\n        compilerMessageReporting: {\n          default: { logLevel: \"warning\" },\n        },\n        extractorMessageReporting: {\n          default: { logLevel: \"warning\" },\n          \"ae-missing-release-tag\": { logLevel: \"none\" },\n        },\n        tsdocMessageReporting: {\n          default: { logLevel: \"warning\" },\n        },\n      },\n    };\n  }\n}\n","import { Component } from \"projen\";\nimport { NodeProject } from \"projen/lib/javascript\";\nimport { TextFile } from \"projen/lib/textfile\";\nimport {\n  AstroConfigOptions,\n  AstroIntegrationSpec,\n} from \"./astro-config-options\";\n\n/**\n * Renders `astro.config.mjs` for an Astro project.\n */\nexport class AstroConfig extends Component {\n  /**\n   * Find the AstroConfig component on a project.\n   */\n  public static of(project: NodeProject): AstroConfig | undefined {\n    const isAstroConfig = (c: Component): c is AstroConfig =>\n      c instanceof AstroConfig;\n    return project.components.find(isAstroConfig);\n  }\n\n  private readonly configFilePath: string;\n  private readonly site?: string;\n  private readonly base?: string;\n  private readonly output?: string;\n  private readonly integrations: Array<AstroIntegrationSpec>;\n  private readonly adapter?: AstroIntegrationSpec;\n\n  constructor(\n    public readonly project: NodeProject,\n    options: AstroConfigOptions = {},\n  ) {\n    super(project);\n\n    this.configFilePath = \"astro.config.mjs\";\n    this.site = options.site;\n    this.base = options.base;\n    this.output = options.output;\n    this.integrations = options.integrations ?? [];\n    this.adapter = options.adapter;\n\n    this.synthesizeConfig();\n  }\n\n  /**\n   * Render the config file contents as an array of lines.\n   *\n   * Exposed for unit testing — `synthesizeConfig` writes these to disk.\n   */\n  public renderConfig(): Array<string> {\n    const imports: Array<string> = [\n      'import { defineConfig } from \"astro/config\";',\n    ];\n    const specs: Array<AstroIntegrationSpec> = [\n      ...this.integrations,\n      ...(this.adapter ? [this.adapter] : []),\n    ];\n    for (const spec of specs) {\n      imports.push(renderImport(spec));\n    }\n\n    const body: Array<string> = [];\n    if (this.site !== undefined) {\n      body.push(`  site: ${JSON.stringify(this.site)},`);\n    }\n    if (this.base !== undefined) {\n      body.push(`  base: ${JSON.stringify(this.base)},`);\n    }\n    if (this.output !== undefined) {\n      body.push(`  output: ${JSON.stringify(this.output)},`);\n    }\n    if (this.integrations.length > 0) {\n      const calls = this.integrations.map(renderCall).join(\", \");\n      body.push(`  integrations: [${calls}],`);\n    }\n    if (this.adapter) {\n      body.push(`  adapter: ${renderCall(this.adapter)},`);\n    }\n\n    return [...imports, \"\", \"export default defineConfig({\", ...body, \"});\"];\n  }\n\n  private synthesizeConfig(): void {\n    this.project.tryRemoveFile(this.configFilePath);\n    new TextFile(this, this.configFilePath, {\n      lines: this.renderConfig(),\n    });\n  }\n}\n\nfunction renderImport(spec: AstroIntegrationSpec): string {\n  const asDefault = spec.defaultImport ?? true;\n  const binding = asDefault ? spec.name : `{ ${spec.name} }`;\n  return `import ${binding} from ${JSON.stringify(spec.importPath)};`;\n}\n\nfunction renderCall(spec: AstroIntegrationSpec): string {\n  return `${spec.name}(${spec.args ?? \"\"})`;\n}\n","/**\n * Astro output mode.\n *\n * @see https://docs.astro.build/en/reference/configuration-reference/#output\n */\nexport const AstroOutput = {\n  STATIC: \"static\",\n  SERVER: \"server\",\n  HYBRID: \"hybrid\",\n} as const;\n\nexport type AstroOutput = (typeof AstroOutput)[keyof typeof AstroOutput];\n\n/**\n * Declarative spec for an Astro integration or adapter import.\n *\n * Rendered into `astro.config.mjs` as an import plus an invocation in\n * the `integrations` array (or as the `adapter` field).\n */\nexport interface AstroIntegrationSpec {\n  /**\n   * Local binding used in the generated config, e.g. \"react\".\n   */\n  readonly name: string;\n\n  /**\n   * Module to import from, e.g. `@astrojs/react`.\n   */\n  readonly importPath: string;\n\n  /**\n   * Raw argument expression passed to the integration call.\n   *\n   * Written verbatim inside the parentheses, e.g. `\"{ include: ['**\\/*.tsx'] }\"`.\n   * When omitted the integration is invoked with no arguments.\n   */\n  readonly args?: string;\n\n  /**\n   * When true, use a default import (`import name from ...`).\n   * When false or omitted, use a named import (`import { name } from ...`).\n   *\n   * @default true\n   */\n  readonly defaultImport?: boolean;\n}\n\n/**\n * Options controlling the rendered `astro.config.mjs`.\n */\nexport interface AstroConfigOptions {\n  /**\n   * Site URL (used for canonical URLs, sitemaps, RSS).\n   */\n  readonly site?: string;\n\n  /**\n   * Base path the site is deployed under.\n   */\n  readonly base?: string;\n\n  /**\n   * Output mode.\n   *\n   * @default AstroOutput.STATIC\n   */\n  readonly output?: AstroOutput;\n\n  /**\n   * Integrations rendered into the `integrations` array.\n   */\n  readonly integrations?: Array<AstroIntegrationSpec>;\n\n  /**\n   * SSR adapter rendered into the `adapter` field.\n   */\n  readonly adapter?: AstroIntegrationSpec;\n}\n","import { join, relative } from \"node:path\";\n// eslint-disable-next-line import/no-extraneous-dependencies\nimport { AWS_STAGE_TYPE, AwsStageType } from \"@codedrifters/utils\";\nimport { Component } from \"projen\";\nimport { AwsCdkTypeScriptApp } from \"projen/lib/awscdk\";\nimport { AwsDeploymentTarget } from \"./aws-deployment-target\";\nimport { CdkCli } from \"./cdk-cli\";\nimport { mergeCdkOptions } from \"./cdk-cli-merge\";\nimport { CdkSynthOptions } from \"./cdk-cli-options\";\nimport { renderCdkSynth } from \"./cdk-cli-renderer\";\nimport { GIT_BRANCH_NAME_ENV, GIT_BRANCH_NAME_ENV_VALUE } from \"../git\";\nimport { TurboRepo } from \"../turbo\";\n\n/**\n * Sort weight per stage, lowest precedence first. Used to fold per-target synth\n * options in a stable, declaration-order-independent way.\n */\nconst SYNTH_STAGE_RANK: Record<AwsStageType, number> = {\n  [AWS_STAGE_TYPE.DEV]: 0,\n  [AWS_STAGE_TYPE.STAGE]: 1,\n  [AWS_STAGE_TYPE.PROD]: 2,\n};\n\n/*******************************************************************************\n *\n * AWS Deployment Configuration\n *\n * This component allows configuration of multiple AWS deployment\n * targets, each with its own account, region, and deployment type\n * (dev, stage, prod). It supports both local and CI deployments,\n * with customizable settings for each target.\n *\n ******************************************************************************/\n\n/*\nexport interface AwsDeploymentConfigOptions {}\n*/\n\nexport class AwsDeploymentConfig extends Component {\n  public static of(\n    project: AwsCdkTypeScriptApp,\n  ): AwsDeploymentConfig | undefined {\n    const isDefined = (c: Component): c is AwsDeploymentConfig =>\n      c instanceof AwsDeploymentConfig;\n    return project.components.find(isDefined);\n  }\n\n  /**\n   * Environment variables to be injected into all tasks.\n   */\n  public readonly env: Record<string, string>;\n\n  /**\n   * The relative path to the project directory from the root of the project.\n   */\n  public readonly projectPath: string;\n\n  /**\n   * The relative path to the root of the project from the output directory.\n   */\n  public readonly rootPath: string;\n\n  /**\n   * The output directory for the CDK synthesis, from the root directory.\n   */\n  public readonly rootCdkOut: string;\n\n  /**\n   * The output directory for the CDK synthesis.\n   */\n  public readonly cdkOut: string;\n\n  /**\n   * Array of targets for deployment.\n   */\n  public readonly awsDeploymentTargets: Array<AwsDeploymentTarget> = [];\n\n  /**\n   * The CDK CLI component that owns shared `cdk` invocation options for this\n   * project.\n   */\n  public readonly cdkCli: CdkCli;\n\n  constructor(project: AwsCdkTypeScriptApp) {\n    super(project);\n\n    /**\n     * Ensure the CdkCli component is attached so deploy / watch / synth tasks\n     * can resolve typed options instead of hard-coding CLI strings.\n     */\n    this.cdkCli = CdkCli.of(project) || new CdkCli(project);\n\n    /**\n     * Common variables used across tasks.\n     *\n     * This is the BELOW-turbo layer: it resolves the branch actually baked\n     * into the synthesized assembly. Its `[ -n \"$GIT_BRANCH_NAME\" ]` guard\n     * consumes whatever the ABOVE-turbo layer (the root `build:all` task env,\n     * written by `TurboRepo.activateBranchNameEnvVar`) exported, so both share\n     * one constant and cannot drift — see `git-branch-env.ts`.\n     */\n    this.env = {\n      [GIT_BRANCH_NAME_ENV]: GIT_BRANCH_NAME_ENV_VALUE,\n    };\n    this.projectPath = relative(project.root.outdir, project.outdir);\n    this.rootPath = relative(project.outdir, project.root.outdir);\n    this.rootCdkOut = join(\"dist\", this.projectPath, \"cdk.out\");\n    this.cdkOut = join(this.rootPath, \"dist\", this.projectPath, \"cdk.out\");\n\n    /**\n     * Reset some tasks we will rebuild below.\n     */\n    [\"deploy\", \"watch\"].forEach((taskName) => {\n      const task = project.tasks.tryFind(taskName);\n      if (task) {\n        task.reset();\n        task.say(\n          \"Generic task is disabled. Please use the specific task for your deployment target.\",\n        );\n      }\n    });\n\n    /**\n     * Redefine Synth here\n     *\n     * Deploy and watch get reconfigured per deployment target.\n     * @see addDeploymentTarget()\n     */\n    this.configureSynthTask();\n  }\n\n  /*****************************************************************************\n   *\n   * Target filter helpers\n   *\n   * Return various targets for deployment scripts to use.\n   *\n   ****************************************************************************/\n\n  /**\n   * @returns All production deployment targets.\n   */\n  public get prodTargets(): Array<AwsDeploymentTarget> {\n    return this.awsDeploymentTargets.filter(\n      (target) => target.awsStageType === AWS_STAGE_TYPE.PROD,\n    );\n  }\n  public get prodTargetsForCI(): Array<AwsDeploymentTarget> {\n    return this.awsDeploymentTargets.filter(\n      (target) =>\n        target.awsStageType === AWS_STAGE_TYPE.PROD && target.ciDeployment,\n    );\n  }\n  public get prodTargetsForLocal(): Array<AwsDeploymentTarget> {\n    return this.awsDeploymentTargets.filter(\n      (target) =>\n        target.awsStageType === AWS_STAGE_TYPE.PROD && target.localDeployment,\n    );\n  }\n\n  /**\n   *\n   * @returns All stage deployment targets.\n   */\n  public get stageTargets(): Array<AwsDeploymentTarget> {\n    return this.awsDeploymentTargets.filter(\n      (target) => target.awsStageType === AWS_STAGE_TYPE.STAGE,\n    );\n  }\n  public get stageTargetsForCI(): Array<AwsDeploymentTarget> {\n    return this.awsDeploymentTargets.filter(\n      (target) =>\n        target.awsStageType === AWS_STAGE_TYPE.STAGE && target.ciDeployment,\n    );\n  }\n  public get stageTargetsForLocal(): Array<AwsDeploymentTarget> {\n    return this.awsDeploymentTargets.filter(\n      (target) =>\n        target.awsStageType === AWS_STAGE_TYPE.STAGE && target.localDeployment,\n    );\n  }\n\n  /**\n   *\n   * @returns All dev deployment targets.\n   */\n  public get devTargets(): Array<AwsDeploymentTarget> {\n    return this.awsDeploymentTargets.filter(\n      (target) => target.awsStageType === AWS_STAGE_TYPE.DEV,\n    );\n  }\n  public get devTargetsForCI(): Array<AwsDeploymentTarget> {\n    return this.awsDeploymentTargets.filter(\n      (target) =>\n        target.awsStageType === AWS_STAGE_TYPE.DEV && target.ciDeployment,\n    );\n  }\n  public get devTargetsForLocal(): Array<AwsDeploymentTarget> {\n    return this.awsDeploymentTargets.filter(\n      (target) =>\n        target.awsStageType === AWS_STAGE_TYPE.DEV && target.localDeployment,\n    );\n  }\n\n  /*****************************************************************************\n   *\n   * Synth Tasks\n   *\n   * - Configure synth task to use the branch name\n   * - Change the output location for easier workflows.\n   *\n   ****************************************************************************/\n\n  /**\n   * Resolve the synth options for the project-wide `synth` / `synth:silent`\n   * tasks.\n   *\n   * `cdk synth` produces one cloud assembly that every target deploys from, so\n   * there is no single target to resolve against. Each registered target's\n   * resolved options are folded together lowest-stage-first, so a higher stage\n   * wins scalar collisions and arrays/records union across targets. Sorting\n   * makes the result independent of the order targets were declared in. With a\n   * single target this is exactly `synthOptionsFor(target)`; with none it is\n   * empty.\n   */\n  private resolveSynthOptions = (): CdkSynthOptions => {\n    const ordered = [...this.awsDeploymentTargets].sort(\n      (a, b) =>\n        SYNTH_STAGE_RANK[a.awsStageType] - SYNTH_STAGE_RANK[b.awsStageType] ||\n        a.account.localeCompare(b.account) ||\n        a.region.localeCompare(b.region),\n    );\n\n    return mergeCdkOptions<CdkSynthOptions>(\n      ...ordered.map((target) => this.cdkCli.synthOptionsFor(target)),\n    );\n  };\n\n  /**\n   * (Re)build the project-wide synth tasks.\n   *\n   * Idempotent — it resets both tasks before rebuilding them, so it is safe to\n   * run once from the constructor (keeping the tasks well-formed for a project\n   * with no targets) and again from `preSynthesize`, once every target has\n   * registered itself and the override chain can actually be resolved.\n   *\n   * `--output` is pinned at the call site because it is a property of the\n   * project layout, and `--quiet` is pinned on `synth:silent` because it is\n   * what makes that task silent. Every other flag flows through the chain.\n   */\n  private configureSynthTask = (): void => {\n    const synthOpts = this.resolveSynthOptions();\n\n    this.project.tasks.tryFind(\"synth\")?.reset(`rm -rf ${this.cdkOut}`);\n    this.project.tasks\n      .tryFind(\"synth\")\n      ?.exec(`cdk ${renderCdkSynth({ ...synthOpts, output: this.cdkOut })}`, {\n        env: this.env,\n      });\n\n    this.project.tasks.tryFind(\"synth:silent\")?.reset(`rm -rf ${this.cdkOut}`);\n    this.project.tasks.tryFind(\"synth:silent\")?.exec(\n      `cdk ${renderCdkSynth({\n        ...synthOpts,\n        output: this.cdkOut,\n        quiet: true,\n      })}`,\n      {\n        env: this.env,\n      },\n    );\n  };\n\n  preSynthesize(): void {\n    super.preSynthesize();\n\n    /**\n     * Rebuild the synth tasks now that every deployment target has registered\n     * itself. Targets attach during construction, which happens after this\n     * component's own constructor ran, so this is the first point at which the\n     * per-target synth override chain can be resolved.\n     */\n    this.configureSynthTask();\n\n    /**\n     * If turbo's active we should ensure the post compile task\n     * is configured to consider the cdk output directory in it's root location.\n     */\n    if (TurboRepo.of(this.project)) {\n      const turbo = TurboRepo.of(this.project)!;\n      turbo.postCompileTask?.outputs.push(join(this.cdkOut, \"**\"));\n    }\n  }\n}\n","// eslint-disable-next-line import/no-extraneous-dependencies\nimport { AwsStageType } from \"@codedrifters/utils\";\nimport { Component } from \"projen\";\nimport { AwsCdkTypeScriptApp } from \"projen/lib/awscdk\";\nimport { AwsDeploymentTarget } from \"./aws-deployment-target\";\nimport {\n  CDK_BOOTSTRAP_DEFAULTS_BY_STAGE,\n  CDK_DEPLOY_DEFAULTS_BY_STAGE,\n  CDK_DESTROY_DEFAULTS_BY_STAGE,\n  CDK_DIFF_DEFAULTS_BY_STAGE,\n  CDK_SYNTH_DEFAULTS_BY_STAGE,\n  CDK_WATCH_DEFAULTS_BY_STAGE,\n} from \"./cdk-cli-defaults\";\nimport { mergeCdkOptions } from \"./cdk-cli-merge\";\nimport {\n  CdkBootstrapOptions,\n  CdkDeployOptions,\n  CdkDestroyOptions,\n  CdkDiffOptions,\n  CdkSynthOptions,\n  CdkTargetOverrides,\n  CdkWatchOptions,\n} from \"./cdk-cli-options\";\n\n/*******************************************************************************\n *\n * AWS CDK CLI Component\n *\n * Owns the per-project options that get layered into every `cdk` CLI\n * invocation the generated project makes. Phase 1 covered `cdk deploy`; Phase\n * 2 extended the component with `synth`, `watch`, `destroy`, `diff`, and\n * `bootstrap`. Phase 5 (this revision) wires in the full per-target /\n * per-account override surface and the generic {@link mergeCdkOptions} folder.\n *\n * ## Override precedence\n *\n * Each `*OptionsFor(target)` accessor folds the layers below in\n * **lowest-precedence-first** order; the rightmost (highest) layer wins on\n * scalar collisions, arrays concat-and-dedupe across layers, and record-valued\n * fields merge one level deep with the higher layer winning on key collisions.\n *\n * 1. **Per-stage built-in default** — from `CDK_*_DEFAULTS_BY_STAGE` for the\n *    target's {@link AwsDeploymentTarget.awsStageType}.\n * 2. **Per-stage consumer override** — from this component's\n *    `<command>Defaults[stage]` map.\n * 3. **Per-account override** — from `accountOverrides[target.account][<command>]`.\n * 4. **Per-target override** — from `target.cdkOptions.<command>`.\n * 5. **Call-site explicit option** — passed by the caller into the renderer\n *    directly, after the accessor returns. The accessor does not see this\n *    layer; the caller is responsible for spreading the accessor result first\n *    and then the call-site option on top.\n *\n * ## CLI version\n *\n * Beyond per-command flags, the component also owns {@link CdkCli.cliVersion} —\n * the `aws-cdk` version generated CI jobs install before invoking `cdk`. It\n * defaults to the project's own `aws-cdk` requirement so a deploy runs the same\n * CLI that synthesized the cloud assembly it is deploying.\n *\n * Auto-instantiated by {@link AwsDeploymentConfig} when absent; consumers can\n * pre-instantiate it via `new CdkCli(project, options)` to register custom\n * per-stage defaults, per-account overrides, and a pinned CLI version.\n *\n ******************************************************************************/\n\n/**\n * Options accepted by {@link CdkCli}.\n */\nexport interface CdkCliOptions {\n  /**\n   * Consumer-supplied overrides for the built-in per-stage deploy defaults.\n   *\n   * Each entry is merged on top of\n   * {@link CDK_DEPLOY_DEFAULTS_BY_STAGE} for the matching stage via\n   * {@link mergeCdkOptions}.\n   */\n  readonly deployDefaults?: Partial<\n    Record<AwsStageType, Partial<CdkDeployOptions>>\n  >;\n\n  /**\n   * Consumer-supplied overrides for the built-in per-stage synth defaults.\n   *\n   * Each entry is merged on top of\n   * {@link CDK_SYNTH_DEFAULTS_BY_STAGE} for the matching stage via\n   * {@link mergeCdkOptions}.\n   */\n  readonly synthDefaults?: Partial<\n    Record<AwsStageType, Partial<CdkSynthOptions>>\n  >;\n\n  /**\n   * Consumer-supplied overrides for the built-in per-stage watch defaults.\n   *\n   * Each entry is merged on top of\n   * {@link CDK_WATCH_DEFAULTS_BY_STAGE} for the matching stage via\n   * {@link mergeCdkOptions}.\n   */\n  readonly watchDefaults?: Partial<\n    Record<AwsStageType, Partial<CdkWatchOptions>>\n  >;\n\n  /**\n   * Consumer-supplied overrides for the built-in per-stage destroy defaults.\n   *\n   * Each entry is merged on top of\n   * {@link CDK_DESTROY_DEFAULTS_BY_STAGE} for the matching stage via\n   * {@link mergeCdkOptions}.\n   */\n  readonly destroyDefaults?: Partial<\n    Record<AwsStageType, Partial<CdkDestroyOptions>>\n  >;\n\n  /**\n   * Consumer-supplied overrides for the built-in per-stage diff defaults.\n   *\n   * Each entry is merged on top of\n   * {@link CDK_DIFF_DEFAULTS_BY_STAGE} for the matching stage via\n   * {@link mergeCdkOptions}.\n   */\n  readonly diffDefaults?: Partial<\n    Record<AwsStageType, Partial<CdkDiffOptions>>\n  >;\n\n  /**\n   * Consumer-supplied overrides for the built-in per-stage bootstrap defaults.\n   *\n   * Each entry is merged on top of\n   * {@link CDK_BOOTSTRAP_DEFAULTS_BY_STAGE} for the matching stage via\n   * {@link mergeCdkOptions}.\n   */\n  readonly bootstrapDefaults?: Partial<\n    Record<AwsStageType, Partial<CdkBootstrapOptions>>\n  >;\n\n  /**\n   * Per-account overrides keyed by AWS account ID.\n   *\n   * Each value is a {@link CdkTargetOverrides} bundle that applies to every\n   * {@link AwsDeploymentTarget} whose `account` matches the key. Sits in the\n   * precedence chain between per-stage overrides and per-target overrides —\n   * see {@link CdkCli} for the full layer order.\n   *\n   * Example: pin `--no-rollback` on every deploy into a sandbox account\n   * regardless of the target's stage:\n   *\n   * ```typescript\n   * new CdkCli(project, {\n   *   accountOverrides: {\n   *     \"111122223333\": { deploy: { rollback: false } },\n   *   },\n   * });\n   * ```\n   */\n  readonly accountOverrides?: Record<string, CdkTargetOverrides>;\n\n  /**\n   * The `aws-cdk` CLI version CI jobs install before invoking `cdk`.\n   *\n   * Rendered into the generated deploy and diff jobs as\n   * `pnpm dlx \"aws-cdk@<version>\"`, so a CI run deploys a cloud assembly with\n   * the same CLI that synthesized it instead of whatever happens to be latest\n   * on the registry at run time.\n   *\n   * Accepts any npm version specifier. Supplying a range (`^2`) rather than an\n   * exact version keeps the drift this option exists to close, so prefer an\n   * exact pin.\n   *\n   * @default - the project's own `aws-cdk` dependency requirement\n   * (`cdkDeps.cdkCliVersion`), which is the CLI that runs the `synth` task and\n   * therefore produces the cloud assembly CI deploys. Projects created through\n   * configulator's `AwsCdkProject` pin this exactly; a bare projen\n   * `AwsCdkTypeScriptApp` that never set `cdkCliVersion` falls back to projen's\n   * own `^2` default.\n   */\n  readonly cliVersion?: string;\n}\n\nexport class CdkCli extends Component {\n  /**\n   * Find the {@link CdkCli} component already attached to the project, if any.\n   */\n  public static of(project: AwsCdkTypeScriptApp): CdkCli | undefined {\n    const isDefined = (c: Component): c is CdkCli => c instanceof CdkCli;\n    return project.components.find(isDefined);\n  }\n\n  /**\n   * The consumer-supplied per-stage deploy default overrides.\n   */\n  public readonly deployDefaults: Partial<\n    Record<AwsStageType, Partial<CdkDeployOptions>>\n  >;\n\n  /**\n   * The consumer-supplied per-stage synth default overrides.\n   */\n  public readonly synthDefaults: Partial<\n    Record<AwsStageType, Partial<CdkSynthOptions>>\n  >;\n\n  /**\n   * The consumer-supplied per-stage watch default overrides.\n   */\n  public readonly watchDefaults: Partial<\n    Record<AwsStageType, Partial<CdkWatchOptions>>\n  >;\n\n  /**\n   * The consumer-supplied per-stage destroy default overrides.\n   */\n  public readonly destroyDefaults: Partial<\n    Record<AwsStageType, Partial<CdkDestroyOptions>>\n  >;\n\n  /**\n   * The consumer-supplied per-stage diff default overrides.\n   */\n  public readonly diffDefaults: Partial<\n    Record<AwsStageType, Partial<CdkDiffOptions>>\n  >;\n\n  /**\n   * The consumer-supplied per-stage bootstrap default overrides.\n   */\n  public readonly bootstrapDefaults: Partial<\n    Record<AwsStageType, Partial<CdkBootstrapOptions>>\n  >;\n\n  /**\n   * The consumer-supplied per-account overrides, keyed by AWS account ID.\n   */\n  public readonly accountOverrides: Record<string, CdkTargetOverrides>;\n\n  /**\n   * The resolved `aws-cdk` CLI version that generated CI jobs install.\n   *\n   * Always concrete, so callers rendering a workflow step never have to\n   * re-apply the default. See {@link CdkCliOptions.cliVersion}.\n   */\n  public readonly cliVersion: string;\n\n  constructor(project: AwsCdkTypeScriptApp, options: CdkCliOptions = {}) {\n    super(project);\n    this.deployDefaults = options.deployDefaults ?? {};\n    this.synthDefaults = options.synthDefaults ?? {};\n    this.watchDefaults = options.watchDefaults ?? {};\n    this.destroyDefaults = options.destroyDefaults ?? {};\n    this.diffDefaults = options.diffDefaults ?? {};\n    this.bootstrapDefaults = options.bootstrapDefaults ?? {};\n    this.accountOverrides = options.accountOverrides ?? {};\n\n    /**\n     * Default to the requirement the project already declares on `aws-cdk`.\n     * Projen installs that same requirement as a devDependency, and its binary\n     * is what the `synth` task runs — so defaulting here keeps the CLI that\n     * deploys a cloud assembly identical to the one that built it.\n     */\n    this.cliVersion = options.cliVersion ?? project.cdkDeps.cdkCliVersion;\n  }\n\n  /**\n   * Resolve the `cdk deploy` options to use against a given target.\n   *\n   * Folds the precedence chain via {@link mergeCdkOptions}: per-stage built-in\n   * → per-stage consumer override → per-account override → per-target\n   * override. The call-site explicit layer is applied by the caller after\n   * this method returns. See {@link CdkCli} for the full chain.\n   */\n  public deployOptionsFor(target: AwsDeploymentTarget): CdkDeployOptions {\n    const stage = target.awsStageType;\n    return mergeCdkOptions<CdkDeployOptions>(\n      CDK_DEPLOY_DEFAULTS_BY_STAGE[stage],\n      this.deployDefaults[stage],\n      this.accountOverrides[target.account]?.deploy,\n      target.cdkOptions?.deploy,\n    );\n  }\n\n  /**\n   * Resolve the `cdk synth` options to use against a given target.\n   *\n   * Folds the precedence chain via {@link mergeCdkOptions}: per-stage built-in\n   * → per-stage consumer override → per-account override → per-target\n   * override. See {@link CdkCli} for the full chain.\n   */\n  public synthOptionsFor(target: AwsDeploymentTarget): CdkSynthOptions {\n    const stage = target.awsStageType;\n    return mergeCdkOptions<CdkSynthOptions>(\n      CDK_SYNTH_DEFAULTS_BY_STAGE[stage],\n      this.synthDefaults[stage],\n      this.accountOverrides[target.account]?.synth,\n      target.cdkOptions?.synth,\n    );\n  }\n\n  /**\n   * Resolve the `cdk watch` options to use against a given target.\n   *\n   * Folds the precedence chain via {@link mergeCdkOptions}: per-stage built-in\n   * → per-stage consumer override → per-account override → per-target\n   * override. See {@link CdkCli} for the full chain.\n   */\n  public watchOptionsFor(target: AwsDeploymentTarget): CdkWatchOptions {\n    const stage = target.awsStageType;\n    return mergeCdkOptions<CdkWatchOptions>(\n      CDK_WATCH_DEFAULTS_BY_STAGE[stage],\n      this.watchDefaults[stage],\n      this.accountOverrides[target.account]?.watch,\n      target.cdkOptions?.watch,\n    );\n  }\n\n  /**\n   * Resolve the `cdk destroy` options to use against a given target.\n   *\n   * Folds the precedence chain via {@link mergeCdkOptions}: per-stage built-in\n   * → per-stage consumer override → per-account override → per-target\n   * override. See {@link CdkCli} for the full chain.\n   */\n  public destroyOptionsFor(target: AwsDeploymentTarget): CdkDestroyOptions {\n    const stage = target.awsStageType;\n    return mergeCdkOptions<CdkDestroyOptions>(\n      CDK_DESTROY_DEFAULTS_BY_STAGE[stage],\n      this.destroyDefaults[stage],\n      this.accountOverrides[target.account]?.destroy,\n      target.cdkOptions?.destroy,\n    );\n  }\n\n  /**\n   * Resolve the `cdk diff` options to use against a given target.\n   *\n   * Folds the precedence chain via {@link mergeCdkOptions}: per-stage built-in\n   * → per-stage consumer override → per-account override → per-target\n   * override. See {@link CdkCli} for the full chain.\n   */\n  public diffOptionsFor(target: AwsDeploymentTarget): CdkDiffOptions {\n    const stage = target.awsStageType;\n    return mergeCdkOptions<CdkDiffOptions>(\n      CDK_DIFF_DEFAULTS_BY_STAGE[stage],\n      this.diffDefaults[stage],\n      this.accountOverrides[target.account]?.diff,\n      target.cdkOptions?.diff,\n    );\n  }\n\n  /**\n   * Resolve the `cdk bootstrap` options to use against a given target.\n   *\n   * Folds the precedence chain via {@link mergeCdkOptions}: per-stage built-in\n   * → per-stage consumer override → per-account override → per-target\n   * override. See {@link CdkCli} for the full chain.\n   */\n  public bootstrapOptionsFor(target: AwsDeploymentTarget): CdkBootstrapOptions {\n    const stage = target.awsStageType;\n    return mergeCdkOptions<CdkBootstrapOptions>(\n      CDK_BOOTSTRAP_DEFAULTS_BY_STAGE[stage],\n      this.bootstrapDefaults[stage],\n      this.accountOverrides[target.account]?.bootstrap,\n      target.cdkOptions?.bootstrap,\n    );\n  }\n}\n","// eslint-disable-next-line import/no-extraneous-dependencies\nimport { AwsStageType } from \"@codedrifters/utils\";\nimport {\n  CdkBootstrapOptions,\n  CdkDeployOptions,\n  CdkDestroyOptions,\n  CdkDiffOptions,\n  CdkSynthOptions,\n  CdkWatchOptions,\n} from \"./cdk-cli-options\";\n\n/*******************************************************************************\n *\n * AWS CDK CLI Defaults\n *\n * Per-stage default option sets the `CdkCli` component layers in when a\n * consumer asks for the options to use against a given deployment target.\n * Phase 1 registered defaults for `cdk deploy`; Phase 2 registers defaults for\n * `synth`, `watch`, `destroy`, `diff`, and `bootstrap`.\n *\n ******************************************************************************/\n\n/**\n * Per-stage defaults for `cdk deploy`.\n *\n * - `dev` opts into `--no-rollback` for fast iteration.\n * - `stage` and `prod` deliberately omit `rollback` so the CLI default\n *   (`true`, i.e. atomic deploys with rollback) applies — this is what allows\n *   replacement-style updates to succeed in stage/prod.\n * - `prod` pins `--method=change-set` to leave a reviewable change-set trail.\n * - `express` is deliberately **not** defaulted on any stage. CloudFormation\n *   express mode skips resource stabilization and flips the CLI's `rollback`\n *   default to `false`, so it is opt-in per consumer via `deployDefaults`,\n *   `accountOverrides`, or a target's `cdkOptions.deploy` — never a built-in.\n */\nexport const CDK_DEPLOY_DEFAULTS_BY_STAGE: Record<\n  AwsStageType,\n  Partial<CdkDeployOptions>\n> = {\n  dev: {\n    rollback: false,\n    requireApproval: \"never\",\n    progress: \"events\",\n  },\n  stage: {\n    requireApproval: \"never\",\n    progress: \"events\",\n  },\n  prod: {\n    requireApproval: \"never\",\n    progress: \"events\",\n    method: \"change-set\",\n  },\n};\n\n/**\n * Per-stage defaults for `cdk synth`.\n *\n * Deliberately empty. `--quiet` is what distinguishes the generated `synth`\n * task from `synth:silent`, so it is pinned at the `synth:silent` call site\n * rather than seeded here — a per-stage default would silence both tasks and\n * collapse them into the same command. Consumers that genuinely want a quiet\n * `synth` can still set `synthDefaults[stage].quiet`, which reaches the\n * rendered command; `synth:silent` stays silent regardless.\n */\nexport const CDK_SYNTH_DEFAULTS_BY_STAGE: Record<\n  AwsStageType,\n  Partial<CdkSynthOptions>\n> = {\n  dev: {},\n  stage: {},\n  prod: {},\n};\n\n/**\n * Per-stage defaults for `cdk watch`.\n *\n * Every stage uses `--progress=events` to stream CloudFormation events line by\n * line. The CLI default for `cdk watch --hotswap` is already `true`, so the\n * record leaves it unset.\n */\nexport const CDK_WATCH_DEFAULTS_BY_STAGE: Record<\n  AwsStageType,\n  Partial<CdkWatchOptions>\n> = {\n  dev: { progress: \"events\" },\n  stage: { progress: \"events\" },\n  prod: { progress: \"events\" },\n};\n\n/**\n * Per-stage defaults for `cdk destroy`.\n *\n * `dev` opts into `--force` so local teardown does not prompt; `stage` and\n * `prod` deliberately omit `force` so the CLI's confirmation prompt fires.\n */\nexport const CDK_DESTROY_DEFAULTS_BY_STAGE: Record<\n  AwsStageType,\n  Partial<CdkDestroyOptions>\n> = {\n  dev: { force: true },\n  stage: {},\n  prod: {},\n};\n\n/**\n * Per-stage defaults for `cdk diff`.\n *\n * Empty by default — diff has no flags whose stage-by-stage value is obvious.\n * Reserved for consumer overrides.\n */\nexport const CDK_DIFF_DEFAULTS_BY_STAGE: Record<\n  AwsStageType,\n  Partial<CdkDiffOptions>\n> = {\n  dev: {},\n  stage: {},\n  prod: {},\n};\n\n/**\n * Per-stage defaults for `cdk bootstrap`.\n *\n * `prod` opts into `--termination-protection` so the bootstrap stack cannot be\n * accidentally deleted; `dev` and `stage` omit it.\n */\nexport const CDK_BOOTSTRAP_DEFAULTS_BY_STAGE: Record<\n  AwsStageType,\n  Partial<CdkBootstrapOptions>\n> = {\n  dev: {},\n  stage: {},\n  prod: { terminationProtection: true },\n};\n","/*******************************************************************************\n *\n * AWS CDK CLI Option Merge\n *\n * Generic helper that folds a precedence-ordered list of `CdkXxxOptions`\n * fragments into a single resolved option set. Used by every\n * `CdkCli.*OptionsFor(target)` accessor to assemble the documented 5-level\n * override stack (per-stage default → per-account override → per-target\n * override → consumer override → call-site explicit) without per-command merge\n * logic.\n *\n * Merge semantics (see also the `CdkCli` JSDoc):\n *\n * - **Scalars** (booleans, strings, numbers, enums): a non-`undefined` value in\n *   a later (higher-precedence) layer overwrites the previous value. An\n *   `undefined` value in a later layer is treated as \"no opinion\" and falls\n *   through to whatever lower layers contributed.\n * - **Arrays**: concatenated low → high precedence, then deduplicated preserving\n *   document order (first occurrence wins). This lets a per-stage default seed\n *   a list and per-target/per-account layers append to it without losing the\n *   seeded entries.\n * - **Records / maps** (plain object values, including `tags` and `context`\n *   when modelled as `Record<string, string>`): merged one level deep; later\n *   layers win on key collisions, earlier layers' keys survive otherwise.\n * - **`undefined` layers** and **`undefined` field values** short-circuit — no\n *   field on the output is touched by a missing layer or a `undefined` entry.\n *\n ******************************************************************************/\n\n/**\n * Internal: returns true when `value` is a plain object that should be treated\n * as a record/map for merge purposes. Arrays and `null` are intentionally\n * excluded — they are scalar at the field level (arrays follow the array\n * concat-and-dedupe path; `null` is not part of the option surface).\n */\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n  return typeof value === \"object\" && value !== null && !Array.isArray(value);\n};\n\n/**\n * Dedupe an array while preserving first-occurrence order. Used after the\n * concat step so a per-stage default + per-target override that both name the\n * same entry collapse to a single entry.\n */\nconst dedupePreservingOrder = <T>(items: Array<T>): Array<T> => {\n  const seen = new Set<T>();\n  const out: Array<T> = [];\n  for (const item of items) {\n    if (!seen.has(item)) {\n      seen.add(item);\n      out.push(item);\n    }\n  }\n  return out;\n};\n\n/**\n * Fold a precedence-ordered list of partial CDK CLI option layers into a\n * single resolved option set.\n *\n * Layers are supplied in **lowest-precedence-first** order. Each subsequent\n * layer's non-`undefined` values overwrite the previous accumulator for\n * scalars; arrays are concatenated and deduped; record-valued fields are\n * merged one level deep.\n *\n * `undefined` layers are skipped entirely. `undefined` field values within a\n * layer are skipped per-field — they never clobber a previously set value.\n *\n * @typeParam TOptions - The fully resolved option interface (e.g.\n *   `CdkDeployOptions`). The function returns `TOptions`, but the caller is\n *   responsible for ensuring every field its consumers depend on is supplied\n *   by at least one layer — the helper does not validate completeness.\n */\nexport const mergeCdkOptions = <TOptions>(\n  ...layers: Array<Partial<TOptions> | undefined>\n): TOptions => {\n  const accumulator: Record<string, unknown> = {};\n\n  for (const layer of layers) {\n    if (layer === undefined) {\n      continue;\n    }\n\n    for (const [key, incoming] of Object.entries(layer)) {\n      if (incoming === undefined) {\n        continue;\n      }\n\n      const existing = accumulator[key];\n\n      if (Array.isArray(incoming)) {\n        const previous = Array.isArray(existing) ? existing : [];\n        accumulator[key] = dedupePreservingOrder([...previous, ...incoming]);\n        continue;\n      }\n\n      if (isPlainObject(incoming)) {\n        const previous = isPlainObject(existing) ? existing : {};\n        accumulator[key] = { ...previous, ...incoming };\n        continue;\n      }\n\n      // Scalar (boolean, string, number, enum) — override wins.\n      accumulator[key] = incoming;\n    }\n  }\n\n  return accumulator as TOptions;\n};\n","import {\n  CdkAcknowledgeOptions,\n  CdkBootstrapOptions,\n  CdkCliTelemetryOptions,\n  CdkContextOptions,\n  CdkDeployOptions,\n  CdkDestroyOptions,\n  CdkDiagnoseOptions,\n  CdkDiffOptions,\n  CdkDocsOptions,\n  CdkDoctorOptions,\n  CdkDriftOptions,\n  CdkFlagsOptions,\n  CdkGcOptions,\n  CdkGlobalOptions,\n  CdkImportOptions,\n  CdkInitOptions,\n  CdkListOptions,\n  CdkLspOptions,\n  CdkMetadataOptions,\n  CdkMigrateOptions,\n  CdkNoticesOptions,\n  CdkOrphanOptions,\n  CdkPublishAssetsOptions,\n  CdkRefactorOptions,\n  CdkRollbackOptions,\n  CdkSynthOptions,\n  CdkValidateOptions,\n  CdkWatchOptions,\n} from \"./cdk-cli-options\";\n\n/*******************************************************************************\n *\n * AWS CDK CLI Renderer\n *\n * Pure helpers that turn typed option objects into the corresponding\n * command-line string. Phase 1 covered `cdk deploy`; Phase 2 adds renderers\n * for `synth`, `watch`, `destroy`, `diff`, `bootstrap`, and `list`; Phase 3\n * adds renderers for the maintenance / lifecycle commands `rollback`,\n * `import`, `gc`, `drift`, `refactor`, `publish-assets`, and `orphan`;\n * Phase 4 adds renderers for the inspection / scaffolding commands `init`,\n * `migrate`, `context`, `metadata`, `flags`, `acknowledge`, `notices`,\n * `doctor`, and `docs`; Phase 5 brings the surface level with aws-cdk CLI\n * 2.1136.0 and adds `validate`, `lsp`, `diagnose`, and `cli-telemetry`.\n *\n * Conventions:\n *   - Boolean fields are tri-state: `true` → `--flag`, `false` → `--no-flag`,\n *     `undefined` → nothing.\n *   - Arrays render as repeated `--flag value` pairs (one per entry).\n *   - Records render as repeated `--flag KEY=VALUE` pairs.\n *   - `verbose: n` renders as `-v` repeated `n` times.\n *   - Field order is fixed at compile time so snapshots are stable.\n *   - Trailing positional `stackPatterns` are double-quoted to preserve glob\n *     characters across shells.\n *   - Command-specific positionals (`init.template`, `metadata.stack`,\n *     `acknowledge.id`) render after the command-specific flags, before\n *     the trailing tokens (`-v` repetitions and `stackPatterns`).\n *\n ******************************************************************************/\n\n/**\n * Quote a value for safe inclusion in a shell command. Single quotes are used\n * unless the value contains a single quote itself, in which case the value is\n * wrapped in double quotes with embedded double quotes escaped.\n */\nconst quote = (value: string): string => {\n  if (value === \"\") {\n    return '\"\"';\n  }\n  // Conservative: prefer no quoting for simple tokens (alphanumerics plus a\n  // small set of shell-safe characters); fall back to double quotes otherwise.\n  if (/^[A-Za-z0-9_\\-./:=@%+,]+$/.test(value)) {\n    return value;\n  }\n  return `\"${value.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"`;\n};\n\n/**\n * Render a tri-state boolean flag. `true` → `--flag`, `false` → `--no-flag`,\n * `undefined` → nothing.\n */\nconst renderTriBool = (\n  flag: string,\n  value: boolean | undefined,\n): string | undefined => {\n  if (value === undefined) {\n    return undefined;\n  }\n  return value ? `--${flag}` : `--no-${flag}`;\n};\n\n/**\n * Render a `--flag=value` token. Returns `undefined` when the value is\n * `undefined`.\n */\nconst renderValue = (\n  flag: string,\n  value: string | number | undefined,\n): string | undefined => {\n  if (value === undefined) {\n    return undefined;\n  }\n  return `--${flag}=${quote(String(value))}`;\n};\n\n/**\n * Render a repeatable array flag. Each entry produces one `--flag=value`\n * token; an empty or undefined array contributes nothing.\n */\nconst renderArray = (\n  flag: string,\n  values: Array<string> | undefined,\n): Array<string> => {\n  if (!values || values.length === 0) {\n    return [];\n  }\n  return values.map((value) => `--${flag}=${quote(value)}`);\n};\n\n/**\n * Render a repeatable record flag. Each entry produces one\n * `--flag=KEY=VALUE` token; an empty or undefined record contributes nothing.\n */\nconst renderRecord = (\n  flag: string,\n  values: Record<string, string> | undefined,\n): Array<string> => {\n  if (!values) {\n    return [];\n  }\n  const keys = Object.keys(values);\n  if (keys.length === 0) {\n    return [];\n  }\n  return keys.map((key) => `--${flag}=${quote(`${key}=${values[key]}`)}`);\n};\n\n/**\n * Render `verbose: n` as `-v` repeated `n` times.\n */\nconst renderVerbose = (value: number | undefined): Array<string> => {\n  if (value === undefined || value <= 0) {\n    return [];\n  }\n  return Array.from({ length: value }, () => \"-v\");\n};\n\n/**\n * Render the trailing positional stack patterns. Each pattern is double-quoted\n * to preserve glob characters across shells.\n */\nconst renderStackPatterns = (\n  values: Array<string> | undefined,\n): Array<string> => {\n  if (!values || values.length === 0) {\n    return [];\n  }\n  return values.map((pattern) => `\"${pattern}\"`);\n};\n\n/**\n * Render the shared global flag tokens (everything declared on\n * {@link CdkGlobalOptions} except `verbose` and `stackPatterns`, which are\n * appended last by each renderer).\n */\nconst renderGlobalTokens = (\n  opts: CdkGlobalOptions,\n): Array<string | undefined> => [\n  renderValue(\"app\", opts.app),\n  renderTriBool(\"asset-metadata\", opts.assetMetadata),\n  renderValue(\"build\", opts.build),\n  renderValue(\"ca-bundle-path\", opts.caBundlePath),\n  renderTriBool(\"ci\", opts.ci),\n  renderTriBool(\"color\", opts.color),\n  ...renderRecord(\"context\", opts.context),\n  renderTriBool(\"debug\", opts.debug),\n  renderTriBool(\"debug-app\", opts.debugApp),\n  renderTriBool(\"debug-cli\", opts.debugCli),\n  renderTriBool(\"ec2creds\", opts.ec2creds),\n  renderTriBool(\"ignore-errors\", opts.ignoreErrors),\n  renderTriBool(\"json\", opts.json),\n  renderTriBool(\"lookups\", opts.lookups),\n  renderTriBool(\"no-color\", opts.noColor),\n  renderTriBool(\"notices\", opts.notices),\n  renderValue(\"output\", opts.output),\n  renderTriBool(\"path-metadata\", opts.pathMetadata),\n  ...renderArray(\"plugin\", opts.plugin),\n  renderValue(\"profile\", opts.profile),\n  renderValue(\"proxy\", opts.proxy),\n  renderValue(\"region\", opts.region),\n  renderValue(\"role-arn\", opts.roleArn),\n  renderTriBool(\"staging\", opts.staging),\n  renderTriBool(\"strict\", opts.strict),\n  renderValue(\"telemetry-file\", opts.telemetryFile),\n  renderTriBool(\"trace\", opts.trace),\n  ...renderArray(\"unstable\", opts.unstable),\n  renderTriBool(\"version-reporting\", opts.versionReporting),\n  renderTriBool(\"yes\", opts.yes),\n];\n\n/**\n * Render the trailing tokens shared by every command — `-v` repetitions and\n * the quoted stack patterns — appended after the command-specific flags.\n */\nconst renderTrailingTokens = (opts: CdkGlobalOptions): Array<string> => [\n  ...renderVerbose(opts.verbose),\n  ...renderStackPatterns(opts.stackPatterns),\n];\n\n/**\n * Filter undefined / empty tokens and join the surviving tokens with the\n * command name as the leading segment.\n */\nconst compose = (\n  command: string,\n  tokens: Array<string | undefined>,\n): string => {\n  const parts = tokens.filter(\n    (token): token is string => token !== undefined && token !== \"\",\n  );\n  return [command, ...parts].join(\" \");\n};\n\n/**\n * Render a `cdk deploy ...` command from the supplied options. Returns the\n * full command string (starting with `deploy`).\n */\nexport const renderCdkDeploy = (opts: CdkDeployOptions): string => {\n  // Global flags first (alphabetised within group), then deploy-specific\n  // flags (alphabetised within group), then verbose, then trailing positional\n  // stack patterns. Field order is deliberately stable so snapshot tests can\n  // anchor on it.\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // Deploy-specific flags\n    renderTriBool(\"all\", opts.all),\n    renderValue(\"asset-build-concurrency\", opts.assetBuildConcurrency),\n    renderTriBool(\"asset-parallelism\", opts.assetParallelism),\n    renderTriBool(\"asset-prebuild\", opts.assetPrebuild),\n    ...renderArray(\"build-exclude\", opts.buildExclude),\n    renderValue(\"change-set-name\", opts.changeSetName),\n    renderValue(\"concurrency\", opts.concurrency),\n    renderTriBool(\"exclusively\", opts.exclusively),\n    renderTriBool(\"execute\", opts.execute),\n    renderTriBool(\"express\", opts.express),\n    renderTriBool(\"force\", opts.force),\n    renderTriBool(\"hotswap\", opts.hotswap),\n    renderValue(\n      \"hotswap-ecs-maximum-healthy-percent\",\n      opts.hotswapEcsMaximumHealthyPercent,\n    ),\n    renderValue(\n      \"hotswap-ecs-minimum-healthy-percent\",\n      opts.hotswapEcsMinimumHealthyPercent,\n    ),\n    renderValue(\n      \"hotswap-ecs-stabilization-timeout-seconds\",\n      opts.hotswapEcsStabilizationTimeoutSeconds,\n    ),\n    renderTriBool(\"hotswap-fallback\", opts.hotswapFallback),\n    renderTriBool(\"ignore-no-stacks\", opts.ignoreNoStacks),\n    renderTriBool(\"import-existing-resources\", opts.importExistingResources),\n    renderTriBool(\"logs\", opts.logs),\n    renderValue(\"method\", opts.method),\n    ...renderArray(\"notification-arns\", opts.notificationArns),\n    renderValue(\"outputs-file\", opts.outputsFile),\n    ...renderArray(\"parameters\", opts.parameters),\n    renderTriBool(\"previous-parameters\", opts.previousParameters),\n    renderValue(\"progress\", opts.progress),\n    renderValue(\"require-approval\", opts.requireApproval),\n    renderTriBool(\"revert-drift\", opts.revertDrift),\n    renderTriBool(\"rollback\", opts.rollback),\n    ...renderRecord(\"tags\", opts.tags),\n    renderValue(\"toolkit-stack-name\", opts.toolkitStackName),\n    renderTriBool(\"watch\", opts.watch),\n    ...renderTrailingTokens(opts),\n  ];\n  return compose(\"deploy\", tokens);\n};\n\n/**\n * Render a `cdk synth ...` command from the supplied options.\n */\nexport const renderCdkSynth = (opts: CdkSynthOptions): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // Synth-specific flags\n    renderTriBool(\"exclusively\", opts.exclusively),\n    renderTriBool(\"quiet\", opts.quiet),\n    renderTriBool(\"validation\", opts.validation),\n    ...renderTrailingTokens(opts),\n  ];\n  return compose(\"synth\", tokens);\n};\n\n/**\n * Render a `cdk watch ...` command from the supplied options.\n */\nexport const renderCdkWatch = (opts: CdkWatchOptions): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // Watch-specific flags\n    ...renderArray(\"build-exclude\", opts.buildExclude),\n    renderValue(\"change-set-name\", opts.changeSetName),\n    renderValue(\"concurrency\", opts.concurrency),\n    renderTriBool(\"exclusively\", opts.exclusively),\n    renderTriBool(\"force\", opts.force),\n    renderTriBool(\"hotswap\", opts.hotswap),\n    renderValue(\n      \"hotswap-ecs-maximum-healthy-percent\",\n      opts.hotswapEcsMaximumHealthyPercent,\n    ),\n    renderValue(\n      \"hotswap-ecs-minimum-healthy-percent\",\n      opts.hotswapEcsMinimumHealthyPercent,\n    ),\n    renderValue(\n      \"hotswap-ecs-stabilization-timeout-seconds\",\n      opts.hotswapEcsStabilizationTimeoutSeconds,\n    ),\n    renderTriBool(\"hotswap-fallback\", opts.hotswapFallback),\n    renderTriBool(\"logs\", opts.logs),\n    renderValue(\"progress\", opts.progress),\n    renderTriBool(\"rollback\", opts.rollback),\n    renderValue(\"toolkit-stack-name\", opts.toolkitStackName),\n    ...renderTrailingTokens(opts),\n  ];\n  return compose(\"watch\", tokens);\n};\n\n/**\n * Render a `cdk destroy ...` command from the supplied options.\n */\nexport const renderCdkDestroy = (opts: CdkDestroyOptions): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // Destroy-specific flags\n    renderTriBool(\"all\", opts.all),\n    renderValue(\"concurrency\", opts.concurrency),\n    renderTriBool(\"exclusively\", opts.exclusively),\n    renderTriBool(\"express\", opts.express),\n    renderTriBool(\"force\", opts.force),\n    ...renderTrailingTokens(opts),\n  ];\n  return compose(\"destroy\", tokens);\n};\n\n/**\n * Render a `cdk diff ...` command from the supplied options.\n */\nexport const renderCdkDiff = (opts: CdkDiffOptions): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // Diff-specific flags\n    renderTriBool(\"change-set\", opts.changeSet),\n    renderValue(\"context-lines\", opts.contextLines),\n    renderTriBool(\"exclusively\", opts.exclusively),\n    renderTriBool(\"fail\", opts.fail),\n    renderTriBool(\"import-existing-resources\", opts.importExistingResources),\n    renderTriBool(\"include-moves\", opts.includeMoves),\n    renderValue(\"method\", opts.method),\n    renderTriBool(\"processed\", opts.processed),\n    renderTriBool(\"quiet\", opts.quiet),\n    renderTriBool(\"security-only\", opts.securityOnly),\n    renderValue(\"template\", opts.template),\n    ...renderTrailingTokens(opts),\n  ];\n  return compose(\"diff\", tokens);\n};\n\n/**\n * Render a `cdk bootstrap ...` command from the supplied options.\n */\nexport const renderCdkBootstrap = (opts: CdkBootstrapOptions): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // Bootstrap-specific flags\n    renderValue(\"bootstrap-bucket-name\", opts.bootstrapBucketName),\n    renderTriBool(\"bootstrap-customer-key\", opts.bootstrapCustomerKey),\n    renderValue(\"bootstrap-kms-key-id\", opts.bootstrapKmsKeyId),\n    ...renderArray(\n      \"cloudformation-execution-policies\",\n      opts.cloudformationExecutionPolicies,\n    ),\n    renderValue(\"custom-permissions-boundary\", opts.customPermissionsBoundary),\n    renderTriBool(\"deny-external-id\", opts.denyExternalId),\n    renderTriBool(\n      \"example-permissions-boundary\",\n      opts.examplePermissionsBoundary,\n    ),\n    renderTriBool(\"execute\", opts.execute),\n    renderTriBool(\"express\", opts.express),\n    renderTriBool(\"force\", opts.force),\n    renderTriBool(\"import-existing-resources\", opts.importExistingResources),\n    renderTriBool(\"previous-parameters\", opts.previousParameters),\n    renderTriBool(\n      \"public-access-block-configuration\",\n      opts.publicAccessBlockConfiguration,\n    ),\n    renderValue(\"qualifier\", opts.qualifier),\n    renderTriBool(\"show-template\", opts.showTemplate),\n    ...renderRecord(\"tags\", opts.tags),\n    renderValue(\"template\", opts.template),\n    renderTriBool(\"termination-protection\", opts.terminationProtection),\n    renderValue(\"toolkit-stack-name\", opts.toolkitStackName),\n    ...renderArray(\"trust\", opts.trust),\n    ...renderArray(\"trust-for-lookup\", opts.trustForLookup),\n    ...renderArray(\"untrust\", opts.untrust),\n    ...renderTrailingTokens(opts),\n  ];\n  return compose(\"bootstrap\", tokens);\n};\n\n/**\n * Render a `cdk list ...` command from the supplied options.\n */\nexport const renderCdkList = (opts: CdkListOptions): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // List-specific flags\n    renderTriBool(\"long\", opts.long),\n    renderTriBool(\"show-dependencies\", opts.showDependencies),\n    ...renderTrailingTokens(opts),\n  ];\n  return compose(\"list\", tokens);\n};\n\n/**\n * Render a variadic list of trailing positional arguments — `cdk orphan`'s\n * logical IDs and `cdk flags`' feature-flag names. Each entry is double-quoted\n * to preserve any characters the CLI tolerates that shells would otherwise\n * interpret.\n */\nconst renderQuotedPositionals = (\n  values: Array<string> | undefined,\n): Array<string> => {\n  if (!values || values.length === 0) {\n    return [];\n  }\n  return values.map((value) => `\"${value}\"`);\n};\n\n/**\n * Render a `cdk rollback ...` command from the supplied options.\n */\nexport const renderCdkRollback = (opts: CdkRollbackOptions): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // Rollback-specific flags\n    renderTriBool(\"all\", opts.all),\n    renderTriBool(\"force\", opts.force),\n    ...renderArray(\"orphan\", opts.orphan),\n    renderValue(\"toolkit-stack-name\", opts.toolkitStackName),\n    renderTriBool(\"validate-bootstrap-version\", opts.validateBootstrapVersion),\n    ...renderTrailingTokens(opts),\n  ];\n  return compose(\"rollback\", tokens);\n};\n\n/**\n * Render a `cdk import ...` command from the supplied options.\n */\nexport const renderCdkImport = (opts: CdkImportOptions): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // Import-specific flags\n    renderValue(\"change-set-name\", opts.changeSetName),\n    renderTriBool(\"execute\", opts.execute),\n    renderTriBool(\"force\", opts.force),\n    ...renderArray(\"notification-arns\", opts.notificationArns),\n    renderValue(\"record-resource-mapping\", opts.recordResourceMapping),\n    renderValue(\"resource-mapping\", opts.resourceMapping),\n    renderValue(\"resource-mapping-inline\", opts.resourceMappingInline),\n    renderTriBool(\"rollback\", opts.rollback),\n    renderValue(\"toolkit-stack-name\", opts.toolkitStackName),\n    ...renderTrailingTokens(opts),\n  ];\n  return compose(\"import\", tokens);\n};\n\n/**\n * Render a `cdk gc ...` command from the supplied options.\n *\n * The CLI requires the global `--unstable=gc` flag for this command; callers\n * are responsible for including `\"gc\"` in {@link CdkGlobalOptions.unstable}.\n */\nexport const renderCdkGc = (opts: CdkGcOptions): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // GC-specific flags\n    renderValue(\"action\", opts.action),\n    renderValue(\"bootstrap-stack-name\", opts.bootstrapStackName),\n    renderTriBool(\"confirm\", opts.confirm),\n    renderValue(\"created-buffer-days\", opts.createdBufferDays),\n    renderValue(\"rollback-buffer-days\", opts.rollbackBufferDays),\n    renderValue(\"toolkit-stack-name\", opts.toolkitStackName),\n    renderValue(\"type\", opts.type),\n    ...renderTrailingTokens(opts),\n  ];\n  return compose(\"gc\", tokens);\n};\n\n/**\n * Render a `cdk drift ...` command from the supplied options.\n */\nexport const renderCdkDrift = (opts: CdkDriftOptions): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // Drift-specific flags\n    renderTriBool(\"fail\", opts.fail),\n    ...renderTrailingTokens(opts),\n  ];\n  return compose(\"drift\", tokens);\n};\n\n/**\n * Render a `cdk refactor ...` command from the supplied options.\n */\nexport const renderCdkRefactor = (opts: CdkRefactorOptions): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // Refactor-specific flags\n    ...renderArray(\"additional-stack-name\", opts.additionalStackName),\n    renderTriBool(\"dry-run\", opts.dryRun),\n    renderTriBool(\"force\", opts.force),\n    renderValue(\"override-file\", opts.overrideFile),\n    renderTriBool(\"revert\", opts.revert),\n    renderValue(\"toolkit-stack-name\", opts.toolkitStackName),\n    ...renderTrailingTokens(opts),\n  ];\n  return compose(\"refactor\", tokens);\n};\n\n/**\n * Render a `cdk publish-assets ...` command from the supplied options.\n */\nexport const renderCdkPublishAssets = (\n  opts: CdkPublishAssetsOptions,\n): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // Publish-assets-specific flags\n    renderTriBool(\"all\", opts.all),\n    renderValue(\"concurrency\", opts.concurrency),\n    renderTriBool(\"exclusively\", opts.exclusively),\n    renderTriBool(\"force\", opts.force),\n    ...renderTrailingTokens(opts),\n  ];\n  return compose(\"publish-assets\", tokens);\n};\n\n/**\n * Render a `cdk orphan ...` command from the supplied options. Positional\n * `logicalIds` render after the command name as quoted, space-separated\n * arguments.\n */\nexport const renderCdkOrphan = (opts: CdkOrphanOptions): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // Orphan has no command-specific flags; trailing tokens carry verbose\n    // repetitions and stack patterns, and logical IDs render last.\n    ...renderTrailingTokens(opts),\n    ...renderQuotedPositionals(opts.logicalIds),\n  ];\n  return compose(\"orphan\", tokens);\n};\n\n/**\n * Render a single positional argument as a quoted token. Returns an empty\n * array when the value is `undefined` so it can be spread into the token\n * list without conditionals.\n */\nconst renderPositional = (value: string | undefined): Array<string> => {\n  if (value === undefined) {\n    return [];\n  }\n  return [`\"${value}\"`];\n};\n\n/**\n * Render a `cdk init ...` command from the supplied options. The positional\n * `template` argument renders after the command-specific flags, before the\n * trailing tokens.\n */\nexport const renderCdkInit = (opts: CdkInitOptions): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // Init-specific flags\n    renderValue(\"from-path\", opts.fromPath),\n    renderTriBool(\"generate-only\", opts.generateOnly),\n    renderValue(\"language\", opts.language),\n    renderValue(\"lib-version\", opts.libVersion),\n    renderTriBool(\"list\", opts.list),\n    renderValue(\"package-manager\", opts.packageManager),\n    renderValue(\"project-name\", opts.projectName),\n    renderValue(\"template-path\", opts.templatePath),\n    // Positional template arg precedes the trailing tokens.\n    ...renderPositional(opts.template),\n    ...renderTrailingTokens(opts),\n  ];\n  return compose(\"init\", tokens);\n};\n\n/**\n * Render a `cdk migrate ...` command from the supplied options.\n *\n * `--region` is emitted by {@link renderGlobalTokens} rather than here: the\n * CLI declares the flag both globally and on `migrate`, and the surface models\n * it once on `CdkGlobalOptions` so exactly one `--region` token renders.\n */\nexport const renderCdkMigrate = (opts: CdkMigrateOptions): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // Migrate-specific flags\n    renderValue(\"account\", opts.account),\n    renderTriBool(\"compress\", opts.compress),\n    ...renderArray(\"filter\", opts.filter),\n    renderValue(\"from-path\", opts.fromPath),\n    renderValue(\"from-scan\", opts.fromScan),\n    renderTriBool(\"from-stack\", opts.fromStack),\n    renderValue(\"language\", opts.language),\n    renderValue(\"output-path\", opts.outputPath),\n    renderValue(\"stack-name\", opts.stackName),\n    ...renderTrailingTokens(opts),\n  ];\n  return compose(\"migrate\", tokens);\n};\n\n/**\n * Render a `cdk context ...` command from the supplied options. The CLI's\n * `--reset` flag takes a context key as its value, so `reset` is rendered\n * as `--reset=KEY` rather than as a tri-state boolean.\n */\nexport const renderCdkContext = (opts: CdkContextOptions): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // Context-specific flags\n    renderTriBool(\"clear\", opts.clear),\n    renderTriBool(\"force\", opts.force),\n    renderValue(\"reset\", opts.reset),\n    ...renderTrailingTokens(opts),\n  ];\n  return compose(\"context\", tokens);\n};\n\n/**\n * Render a `cdk metadata ...` command from the supplied options. The\n * positional `stack` argument renders after the command-specific flags\n * (there are none beyond the inherited globals), before the trailing\n * tokens.\n */\nexport const renderCdkMetadata = (opts: CdkMetadataOptions): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // Positional stack arg precedes the trailing tokens.\n    ...renderPositional(opts.stack),\n    ...renderTrailingTokens(opts),\n  ];\n  return compose(\"metadata\", tokens);\n};\n\n/**\n * Render a `cdk flags ...` command from the supplied options. `--value` is the\n * only value-taking flag on this command; `--set` and the rest are tri-state\n * booleans. Variadic positional feature-flag names render last, after the\n * trailing tokens.\n */\nexport const renderCdkFlags = (opts: CdkFlagsOptions): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // Flags-specific flags\n    renderTriBool(\"all\", opts.all),\n    renderValue(\"concurrency\", opts.concurrency),\n    renderTriBool(\"default\", opts.default),\n    renderTriBool(\"interactive\", opts.interactive),\n    renderTriBool(\"recommended\", opts.recommended),\n    renderTriBool(\"safe\", opts.safe),\n    renderTriBool(\"set\", opts.set),\n    renderTriBool(\"unconfigured\", opts.unconfigured),\n    renderValue(\"value\", opts.value),\n    ...renderTrailingTokens(opts),\n    ...renderQuotedPositionals(opts.flagNames),\n  ];\n  return compose(\"flags\", tokens);\n};\n\n/**\n * Render a `cdk acknowledge ...` command from the supplied options. The\n * positional `id` argument renders after the command-specific flags (there\n * are none beyond the inherited globals), before the trailing tokens.\n */\nexport const renderCdkAcknowledge = (opts: CdkAcknowledgeOptions): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // Positional notice id precedes the trailing tokens.\n    ...renderPositional(opts.id),\n    ...renderTrailingTokens(opts),\n  ];\n  return compose(\"acknowledge\", tokens);\n};\n\n/**\n * Render a `cdk notices ...` command from the supplied options.\n */\nexport const renderCdkNotices = (opts: CdkNoticesOptions): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // Notices-specific flags\n    renderTriBool(\"unacknowledged\", opts.unacknowledged),\n    ...renderTrailingTokens(opts),\n  ];\n  return compose(\"notices\", tokens);\n};\n\n/**\n * Render a `cdk doctor ...` command from the supplied options. `doctor` has\n * no command-specific flags; only the inherited globals and trailing tokens\n * contribute output.\n */\nexport const renderCdkDoctor = (opts: CdkDoctorOptions): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    ...renderTrailingTokens(opts),\n  ];\n  return compose(\"doctor\", tokens);\n};\n\n/**\n * Render a `cdk docs ...` command from the supplied options.\n */\nexport const renderCdkDocs = (opts: CdkDocsOptions): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // Docs-specific flags\n    renderValue(\"browser\", opts.browser),\n    ...renderTrailingTokens(opts),\n  ];\n  return compose(\"docs\", tokens);\n};\n\n/**\n * Render a `cdk validate ...` command from the supplied options. The variadic\n * `STACKS` positional is carried by the inherited `stackPatterns` field and\n * renders in trailing-token position.\n */\nexport const renderCdkValidate = (opts: CdkValidateOptions): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // Validate-specific flags\n    renderTriBool(\"online\", opts.online),\n    renderTriBool(\"watch\", opts.watch),\n    ...renderTrailingTokens(opts),\n  ];\n  return compose(\"validate\", tokens);\n};\n\n/**\n * Render a `cdk lsp ...` command from the supplied options. `lsp` takes no\n * positional arguments.\n */\nexport const renderCdkLsp = (opts: CdkLspOptions): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // Lsp-specific flags\n    renderTriBool(\"features\", opts.features),\n    ...renderTrailingTokens(opts),\n  ];\n  return compose(\"lsp\", tokens);\n};\n\n/**\n * Render a `cdk diagnose ...` command from the supplied options. The variadic\n * `STACKS` positional is carried by the inherited `stackPatterns` field and\n * renders in trailing-token position.\n */\nexport const renderCdkDiagnose = (opts: CdkDiagnoseOptions): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // Diagnose-specific flags\n    renderValue(\"concurrency\", opts.concurrency),\n    renderValue(\"toolkit-stack-name\", opts.toolkitStackName),\n    ...renderTrailingTokens(opts),\n  ];\n  return compose(\"diagnose\", tokens);\n};\n\n/**\n * Render a `cdk cli-telemetry ...` command from the supplied options.\n *\n * `--enable`, `--disable`, and `--status` are mutually exclusive in the CLI.\n * The renderer emits whatever it is given without validating that constraint,\n * matching how the rest of this surface treats upstream `conflicts`\n * declarations.\n */\nexport const renderCdkCliTelemetry = (opts: CdkCliTelemetryOptions): string => {\n  const tokens: Array<string | undefined> = [\n    ...renderGlobalTokens(opts),\n    // Cli-telemetry-specific flags\n    renderTriBool(\"disable\", opts.disable),\n    renderTriBool(\"enable\", opts.enable),\n    renderTriBool(\"status\", opts.status),\n    ...renderTrailingTokens(opts),\n  ];\n  return compose(\"cli-telemetry\", tokens);\n};\n","/*******************************************************************************\n *\n * Turbo Run CLI Enums\n *\n * `as const` enums for the enumerated value flags on the `turbo run` CLI\n * surface (Turbo 2.9.18). Mirrors the pattern used by the `cdk` CLI enums in\n * `../aws/cdk-cli-enums.ts`: a named `as const` object per flag plus a derived\n * union type, so consumers get autocomplete and the compiler rejects typos\n * without us reaching for a TypeScript `enum`.\n *\n * Consumed by {@link TurboRunOptions} in `./turbo-repo`.\n *\n ******************************************************************************/\n\n/**\n * `--continue` values accepted by `turbo run`.\n */\nexport const TURBO_RUN_CONTINUE = {\n  Never: \"never\",\n  DependenciesSuccessful: \"dependencies-successful\",\n  Always: \"always\",\n} as const;\n\n/**\n * Type for {@link TURBO_RUN_CONTINUE} values.\n */\nexport type TurboRunContinue =\n  (typeof TURBO_RUN_CONTINUE)[keyof typeof TURBO_RUN_CONTINUE];\n\n/**\n * `--output-logs` values accepted by `turbo run`.\n */\nexport const TURBO_RUN_OUTPUT_LOGS = {\n  Full: \"full\",\n  None: \"none\",\n  HashOnly: \"hash-only\",\n  NewOnly: \"new-only\",\n  ErrorsOnly: \"errors-only\",\n} as const;\n\n/**\n * Type for {@link TURBO_RUN_OUTPUT_LOGS} values.\n */\nexport type TurboRunOutputLogs =\n  (typeof TURBO_RUN_OUTPUT_LOGS)[keyof typeof TURBO_RUN_OUTPUT_LOGS];\n\n/**\n * `--log-order` values accepted by `turbo run`.\n */\nexport const TURBO_RUN_LOG_ORDER = {\n  Auto: \"auto\",\n  Stream: \"stream\",\n  Grouped: \"grouped\",\n} as const;\n\n/**\n * Type for {@link TURBO_RUN_LOG_ORDER} values.\n */\nexport type TurboRunLogOrder =\n  (typeof TURBO_RUN_LOG_ORDER)[keyof typeof TURBO_RUN_LOG_ORDER];\n\n/**\n * `--log-prefix` values accepted by `turbo run`.\n */\nexport const TURBO_RUN_LOG_PREFIX = {\n  Auto: \"auto\",\n  None: \"none\",\n  Task: \"task\",\n} as const;\n\n/**\n * Type for {@link TURBO_RUN_LOG_PREFIX} values.\n */\nexport type TurboRunLogPrefix =\n  (typeof TURBO_RUN_LOG_PREFIX)[keyof typeof TURBO_RUN_LOG_PREFIX];\n\n/**\n * `--dry-run` values accepted by `turbo run`. Use `additionalArgs: [\"--dry-run\"]`\n * for the bare flag form.\n */\nexport const TURBO_RUN_DRY_RUN = {\n  Text: \"text\",\n  Json: \"json\",\n} as const;\n\n/**\n * Type for {@link TURBO_RUN_DRY_RUN} values.\n */\nexport type TurboRunDryRun =\n  (typeof TURBO_RUN_DRY_RUN)[keyof typeof TURBO_RUN_DRY_RUN];\n","// eslint-disable-next-line import/no-extraneous-dependencies\nimport {\n  AWS_STAGE_TYPE,\n  AwsEnvironmentType,\n  AwsStageType,\n  DEPLOYMENT_TARGET_ROLE,\n  DeploymentTargetRoleType,\n} from \"@codedrifters/utils\";\nimport { Component } from \"projen\";\nimport { AwsCdkTypeScriptApp } from \"projen/lib/awscdk\";\nimport { AwsDeploymentConfig } from \"./aws-deployment-config\";\nimport { CdkTargetOverrides } from \"./cdk-cli-options\";\nimport {\n  renderCdkBootstrap,\n  renderCdkDeploy,\n  renderCdkDestroy,\n  renderCdkWatch,\n} from \"./cdk-cli-renderer\";\nimport { GitBranch } from \"../git\";\n\n/*******************************************************************************\n *\n * AWS Deployment Configuration\n *\n * A single deployment target that CDK applications can be deployed into.\n *\n ******************************************************************************/\n\n/**\n * Represents the configuration for local deployment in AWS.\n */\nexport interface AwsLocalDeploymentConfig {\n  /**\n   * The AWS profile (in ~/.aws/config) to use for local deployment.\n   *\n   * @default generated dynamically based role name, account and region\n   */\n  readonly profile?: string;\n\n  /**\n   * Named Role used to conduct local deployments.\n   *\n   * @default \"poweruseraccess\"\n   */\n  readonly roleName?: string;\n\n  /**\n   * The pattern used to identify stacks to deploy in CI deployments.\n   *\n   * @default `*-${account}-${region}`\n   */\n  readonly stackPattern?: string;\n}\n\nexport interface CiDeploymentConfig {\n  /**\n   * The OIDC IAM Role to assume for CI deployments.\n   */\n  readonly roleArn: string;\n\n  /**\n   * The pattern used to identify stacks to deploy in CI deployments.\n   *\n   * @default `*-${account}-${region}`\n   */\n  readonly stackPattern?: string;\n}\n\n/**\n * Represents a deployment target in AWS, including account and region, and\n * branches allowed to deploy to this target.\n */\nexport interface AwsDeploymentTargetOptions {\n  /**\n   * The account name for the deployment target.\n   */\n  readonly account: string;\n\n  /**\n   * The AWS region for the deployment target.\n   */\n  readonly region: string;\n\n  /**\n   * AWS deployment type, such as dev, stage, or prod.\n   *\n   * @default 'dev'\n   */\n  readonly awsStageType?: AwsStageType;\n\n  /**\n   * Deployment target role: whether this (account, region) is the primary or\n   * secondary deployment target (e.g. primary vs replica region).\n   *\n   * @default 'primary'\n   */\n  readonly deploymentTargetRole?: DeploymentTargetRoleType;\n\n  /**\n   * AWS environment type, such as primary or secondary.\n   *\n   * @deprecated Use `deploymentTargetRole` instead. This property is maintained for backward compatibility.\n   * @default 'primary'\n   */\n  readonly awsEnvironmentType?: AwsEnvironmentType;\n\n  /**\n   * The AWS profile to use for this deployment target.\n   *\n   * @default ['main'] when prod release type, ['feature/*'] when dev type\n   */\n  readonly branches?: Array<GitBranch>;\n\n  /**\n   * Can this deployment target be used for local development?\n   *\n   * @default true for dev environments, false for prod environments\n   */\n  readonly localDeployment?: boolean;\n\n  /**\n   * Configuration when deploying to this target locally.\n   */\n  readonly localDeploymentConfig?: AwsLocalDeploymentConfig;\n\n  /**\n   * Can this deployment target be used in CI deployments?\n   *\n   * @default false\n   */\n  readonly ciDeployment?: boolean;\n\n  /*\n   * Configuration when deploying to this target in CI.\n\n   */\n  readonly ciDeploymentConfig?: CiDeploymentConfig;\n\n  /**\n   * Per-target overrides for `cdk` CLI options.\n   *\n   * Layered on top of the per-stage defaults and any per-account overrides\n   * configured on {@link CdkCli}. See {@link CdkCli} for the full precedence\n   * chain.\n   */\n  readonly cdkOptions?: CdkTargetOverrides;\n}\n\nexport class AwsDeploymentTarget extends Component {\n  /**\n   * Static method to discovert targets in a project.\n   */\n  public static of(\n    project: AwsCdkTypeScriptApp,\n  ): Array<AwsDeploymentTarget> | undefined {\n    const isDefined = (c: Component): c is AwsDeploymentTarget =>\n      c instanceof AwsDeploymentTarget;\n    return project.components.filter(isDefined);\n  }\n\n  /**\n   * The account name for the deployment target.\n   */\n  public account: string;\n\n  /**\n   * The AWS region for the deployment target.\n   */\n  public region: string;\n\n  /**'\n   * AWS stage type, such as dev, stage, or prod.\n   *\n   * @default 'dev'\n   */\n  public awsStageType: AwsStageType;\n\n  /**\n   * Deployment target role: whether this (account, region) is the primary or\n   * secondary deployment target (e.g. primary vs replica region).\n   *\n   * @default 'primary'\n   */\n  public deploymentTargetRole: DeploymentTargetRoleType;\n\n  /**\n   * AWS environment type, such as primary or secondary.\n   *\n   * @deprecated Use `deploymentTargetRole` instead. This property is maintained for backward compatibility.\n   * @default 'primary'\n   */\n  public awsEnvironmentType: AwsEnvironmentType;\n\n  /**\n   * The AWS profile to use for this deployment target.\n   *\n   * @default ['main'] when prod release type, ['feature/*'] when dev type\n   */\n  public branches: Array<GitBranch> = [];\n\n  /**\n   * Can this deployment target be used for local development?\n   *\n   * @default true for dev environments, false for prod environments\n   */\n  public localDeployment?: boolean;\n\n  /**\n   * Configuration when deploying to this target locally.\n   */\n  public localDeploymentConfig?: AwsLocalDeploymentConfig;\n\n  /**\n   * Can this deployment target be used in CI deployments?\n   *\n   * @default false\n   */\n  public ciDeployment?: boolean;\n\n  /*\n   * Configuration when deploying to this target in CI.\n   */\n  public ciDeploymentConfig?: Required<CiDeploymentConfig>;\n\n  /**\n   * Configuration for the CDK output directory for this deployment target.\n   */\n  public awsDeploymentConfig: AwsDeploymentConfig;\n\n  /**\n   * Per-target overrides for `cdk` CLI options.\n   *\n   * Read by `CdkCli.*OptionsFor(target)` as the second-highest layer in the\n   * precedence chain (below call-site explicit options, above per-account\n   * overrides). See {@link CdkCli} for the full chain.\n   */\n  public cdkOptions?: CdkTargetOverrides;\n\n  constructor(\n    project: AwsCdkTypeScriptApp,\n    options: AwsDeploymentTargetOptions,\n  ) {\n    super(project);\n\n    /**\n     * Set target region and account.\n     */\n    this.account = options.account;\n    this.region = options.region;\n\n    /**\n     * Per-target CDK CLI overrides (consumed by CdkCli.*OptionsFor).\n     */\n    this.cdkOptions = options.cdkOptions;\n\n    /**\n     * Set default type\n     */\n    this.awsStageType = options.awsStageType || AWS_STAGE_TYPE.DEV;\n\n    /**\n     * Set deployment target role (preferred) or fall back to deprecated awsEnvironmentType.\n     */\n    const role =\n      options.deploymentTargetRole ??\n      options.awsEnvironmentType ??\n      DEPLOYMENT_TARGET_ROLE.PRIMARY;\n    this.deploymentTargetRole = role;\n    this.awsEnvironmentType = role;\n\n    /**\n     * Set default Branches\n     */\n\n    this.branches =\n      options.branches ??\n      (this.awsStageType === AWS_STAGE_TYPE.PROD\n        ? [\n            {\n              branch: \"main\",\n            },\n          ]\n        : [\n            {\n              branch: \"feature/*\",\n            },\n          ]);\n\n    /**\n     * Set default for local deployment\n     */\n    this.localDeployment =\n      options.localDeployment ?? this.awsStageType === AWS_STAGE_TYPE.DEV;\n\n    /**\n     * Some default configurations for local deployments.\n     */\n    if (this.localDeployment) {\n      const roleName =\n        options.localDeploymentConfig?.roleName?.toLowerCase() ||\n        \"poweruseraccess\";\n      const profile =\n        options.localDeploymentConfig?.profile ||\n        `${roleName}-${this.awsStageType}-${this.account}-${this.region}`;\n\n      const stackPattern =\n        options.localDeploymentConfig?.stackPattern ||\n        `${this.awsStageType}/${this.awsEnvironmentType}/*-${this.account}-${this.region}`;\n\n      this.localDeploymentConfig = {\n        profile,\n        roleName,\n        stackPattern,\n        ...options.localDeploymentConfig,\n      };\n    }\n\n    /**\n     * Set CI deployment default\n     */\n    this.ciDeployment = options.ciDeployment ?? false;\n\n    /**\n     * Some defaults for CI deployments.\n     */\n    if (this.ciDeployment) {\n      const roleArn =\n        options.ciDeploymentConfig?.roleArn ||\n        `arn:aws:iam::${this.account}:role/GitHubDeployer}`;\n\n      const stackPattern =\n        options.ciDeploymentConfig?.stackPattern ||\n        `${this.awsStageType}/${this.awsEnvironmentType}/*-${this.account}-${this.region}`;\n\n      this.ciDeploymentConfig = {\n        roleArn,\n        stackPattern,\n        ...options.ciDeploymentConfig,\n      };\n    }\n\n    /**\n     * Find or create CDK folder config for this project.\n     */\n    this.awsDeploymentConfig =\n      AwsDeploymentConfig.of(project) || new AwsDeploymentConfig(project);\n\n    /**\n     * Add the target to the deployment targets array.\n     */\n    this.awsDeploymentConfig.awsDeploymentTargets.push(this);\n\n    // Deploy tasks are configured per target.\n    this.configureDeployTask();\n\n    // Watch tasks are configured per target.\n    this.configureWatchTask();\n\n    // Destroy tasks are configured per target.\n    this.configureDestroyTask();\n\n    // Bootstrap tasks are configured per target.\n    this.configureBootstrapTask();\n  }\n\n  /*****************************************************************************\n   *\n   * Deploy Tasks\n   *\n   * - If local deploy, add a deploy task.\n   *\n   ****************************************************************************/\n\n  private configureDeployTask = (): void => {\n    if (this.localDeployment) {\n      const taskName = [\n        \"deploy\",\n        this.awsStageType,\n        this.account,\n        this.region,\n      ].join(\":\");\n      const deployTask = this.project.tasks.addTask(taskName, {\n        env: this.awsDeploymentConfig.env,\n      });\n      const deployOpts = this.awsDeploymentConfig.cdkCli.deployOptionsFor(this);\n      deployTask.exec(\n        `cdk ${renderCdkDeploy({\n          ...deployOpts,\n          lookups: false,\n          profile: this.localDeploymentConfig?.profile,\n          app: this.awsDeploymentConfig.cdkOut,\n          stackPatterns: this.localDeploymentConfig?.stackPattern\n            ? [this.localDeploymentConfig.stackPattern]\n            : undefined,\n        })}`,\n      );\n    }\n  };\n\n  /*****************************************************************************\n   *\n   * Watch tasks\n   *\n   * - Configure watch task to use the branch name\n   * - configure watch task to use the correct synth output location.\n   *\n   ****************************************************************************/\n\n  private configureWatchTask = (): void => {\n    if (this.localDeployment) {\n      const taskName = [\n        \"watch\",\n        this.awsStageType,\n        this.account,\n        this.region,\n      ].join(\":\");\n      const watchTask = this.project.tasks.addTask(taskName, {\n        env: this.awsDeploymentConfig.env,\n      });\n\n      // update the synth first\n      const synthSilent = this.project.tasks.tryFind(\"synth:silent\");\n      if (synthSilent) {\n        watchTask.spawn(synthSilent);\n      }\n\n      // do a normal deploy\n      const deployOpts = this.awsDeploymentConfig.cdkCli.deployOptionsFor(this);\n      watchTask.exec(\n        `cdk ${renderCdkDeploy({\n          ...deployOpts,\n          lookups: false,\n          profile: this.localDeploymentConfig?.profile,\n          app: this.awsDeploymentConfig.cdkOut,\n          stackPatterns: this.localDeploymentConfig?.stackPattern\n            ? [this.localDeploymentConfig.stackPattern]\n            : undefined,\n        })}`,\n      );\n\n      // watch for changes and log output\n      const watchOpts = this.awsDeploymentConfig.cdkCli.watchOptionsFor(this);\n      watchTask.exec(\n        `cdk ${renderCdkWatch({\n          ...watchOpts,\n          lookups: false,\n          hotswap: true,\n          profile: this.localDeploymentConfig?.profile,\n          stackPatterns: this.localDeploymentConfig?.stackPattern\n            ? [this.localDeploymentConfig.stackPattern]\n            : undefined,\n        })}`,\n      );\n    }\n  };\n\n  /*****************************************************************************\n   *\n   * Destroy Tasks\n   *\n   * - If local deploy, add a destroy task.\n   *\n   * Mirrors the deploy task family so `destroyDefaults`, per-account\n   * `destroy` overrides, and a target's `cdkOptions.destroy` all reach a\n   * rendered command. Projen's generic `destroy` passthrough is deliberately\n   * left intact as an ad-hoc escape hatch — unlike the generic `deploy` and\n   * `watch` tasks, it is not reset to a disabled stub.\n   *\n   ****************************************************************************/\n\n  private configureDestroyTask = (): void => {\n    if (this.localDeployment) {\n      const taskName = [\n        \"destroy\",\n        this.awsStageType,\n        this.account,\n        this.region,\n      ].join(\":\");\n      const destroyTask = this.project.tasks.addTask(taskName, {\n        env: this.awsDeploymentConfig.env,\n      });\n      const destroyOpts =\n        this.awsDeploymentConfig.cdkCli.destroyOptionsFor(this);\n      destroyTask.exec(\n        `cdk ${renderCdkDestroy({\n          ...destroyOpts,\n          lookups: false,\n          profile: this.localDeploymentConfig?.profile,\n          app: this.awsDeploymentConfig.cdkOut,\n          stackPatterns: this.localDeploymentConfig?.stackPattern\n            ? [this.localDeploymentConfig.stackPattern]\n            : undefined,\n        })}`,\n      );\n    }\n  };\n\n  /*****************************************************************************\n   *\n   * Bootstrap Tasks\n   *\n   * Unlike deploy / watch / destroy, this family is generated for **every**\n   * target rather than only those with `localDeployment` enabled. Bootstrapping\n   * provisions the CDK toolkit stack for one account/region pair, and a\n   * CI-only target needs that done before its first deployment just as much as\n   * a local one — gating on `localDeployment` would also make the built-in\n   * `prod` default (`--termination-protection`) unreachable, since prod targets\n   * default to `localDeployment: false`.\n   *\n   * The tasks are never invoked automatically; running one is always a\n   * deliberate, elevated-credentials operation.\n   *\n   ****************************************************************************/\n\n  private configureBootstrapTask = (): void => {\n    const taskName = [\n      \"bootstrap\",\n      this.awsStageType,\n      this.account,\n      this.region,\n    ].join(\":\");\n    const bootstrapTask = this.project.tasks.addTask(taskName, {\n      env: this.awsDeploymentConfig.env,\n    });\n    const bootstrapOpts =\n      this.awsDeploymentConfig.cdkCli.bootstrapOptionsFor(this);\n\n    /**\n     * `--app` and `--lookups` are deliberately not pinned: bootstrap\n     * provisions the toolkit stack and does not read the cloud assembly.\n     * `--profile` is pinned only when the target has a local profile to use;\n     * a CI-only target falls back to the ambient credentials of whoever runs\n     * the task. The environment is passed as a trailing positional.\n     */\n    bootstrapTask.exec(\n      `cdk ${renderCdkBootstrap({\n        ...bootstrapOpts,\n        profile: this.localDeploymentConfig?.profile,\n        stackPatterns: [`aws://${this.account}/${this.region}`],\n      })}`,\n    );\n  };\n}\n","/*******************************************************************************\n *\n * AWS CDK CLI Enums\n *\n * `as const` enums for the `cdk` CLI surface. Phase 1 covered `cdk deploy`;\n * Phase 2 adds the enum needed by `cdk diff`; Phase 3 adds the enums needed by\n * `cdk gc`; Phase 4 adds the enums needed by `cdk init` (and reused by `cdk\n * migrate`); Phase 5 brings the surface up to aws-cdk CLI 2.1136.0 (the pinned\n * version) plus the additions that landed in 2.1137/2.1138.\n *\n ******************************************************************************/\n\n/**\n * `--require-approval` values accepted by `cdk deploy`.\n */\nexport const CDK_REQUIRE_APPROVAL = {\n  Never: \"never\",\n  AnyChange: \"any-change\",\n  Broadening: \"broadening\",\n} as const;\n\n/**\n * Type for {@link CDK_REQUIRE_APPROVAL} values.\n */\nexport type CdkRequireApproval =\n  (typeof CDK_REQUIRE_APPROVAL)[keyof typeof CDK_REQUIRE_APPROVAL];\n\n/**\n * `--method` values accepted by `cdk deploy`.\n */\nexport const CDK_DEPLOY_METHOD = {\n  ChangeSet: \"change-set\",\n  Direct: \"direct\",\n  PrepareChangeSet: \"prepare-change-set\",\n  ExecuteChangeSet: \"execute-change-set\",\n} as const;\n\n/**\n * Type for {@link CDK_DEPLOY_METHOD} values.\n */\nexport type CdkDeployMethod =\n  (typeof CDK_DEPLOY_METHOD)[keyof typeof CDK_DEPLOY_METHOD];\n\n/**\n * `--progress` values accepted by `cdk deploy` and `cdk watch`.\n *\n * `ErrorsOnly` displays nothing except errors — upstream recommends it for AI\n * agents and other consumers that do not benefit from continuous progress\n * updates.\n *\n * **CLI version note:** `ErrorsOnly` requires aws-cdk CLI **2.1137.0 or\n * later**. This repository currently pins 2.1136.0, which rejects\n * `--progress=errors-only`. Consumers on the pinned version should stay on\n * `Bar` or `Events` until the pin advances.\n */\nexport const CDK_PROGRESS = {\n  Bar: \"bar\",\n  Events: \"events\",\n  ErrorsOnly: \"errors-only\",\n} as const;\n\n/**\n * Type for {@link CDK_PROGRESS} values.\n */\nexport type CdkProgress = (typeof CDK_PROGRESS)[keyof typeof CDK_PROGRESS];\n\n/**\n * `--method` values accepted by `cdk diff`.\n */\nexport const CDK_DIFF_METHOD = {\n  Auto: \"auto\",\n  ChangeSet: \"change-set\",\n  Template: \"template\",\n} as const;\n\n/**\n * Type for {@link CDK_DIFF_METHOD} values.\n */\nexport type CdkDiffMethod =\n  (typeof CDK_DIFF_METHOD)[keyof typeof CDK_DIFF_METHOD];\n\n/**\n * `--action` values accepted by `cdk gc`.\n */\nexport const CDK_GC_ACTION = {\n  DeleteTagged: \"delete-tagged\",\n  Full: \"full\",\n  Print: \"print\",\n  Tag: \"tag\",\n} as const;\n\n/**\n * Type for {@link CDK_GC_ACTION} values.\n */\nexport type CdkGcAction = (typeof CDK_GC_ACTION)[keyof typeof CDK_GC_ACTION];\n\n/**\n * `--type` values accepted by `cdk gc`.\n */\nexport const CDK_GC_TYPE = {\n  All: \"all\",\n  Ecr: \"ecr\",\n  S3: \"s3\",\n} as const;\n\n/**\n * Type for {@link CDK_GC_TYPE} values.\n */\nexport type CdkGcType = (typeof CDK_GC_TYPE)[keyof typeof CDK_GC_TYPE];\n\n/**\n * Positional `<template>` values accepted by `cdk init`.\n */\nexport const CDK_INIT_TEMPLATE = {\n  App: \"app\",\n  Lib: \"lib\",\n  SampleApp: \"sample-app\",\n} as const;\n\n/**\n * Type for {@link CDK_INIT_TEMPLATE} values.\n */\nexport type CdkInitTemplate =\n  (typeof CDK_INIT_TEMPLATE)[keyof typeof CDK_INIT_TEMPLATE];\n\n/**\n * `--language` values accepted by `cdk init`. Also reused by `cdk migrate`'s\n * `--language` flag, which accepts the same set of language identifiers.\n */\nexport const CDK_INIT_LANGUAGE = {\n  CSharp: \"csharp\",\n  FSharp: \"fsharp\",\n  Go: \"go\",\n  Java: \"java\",\n  JavaScript: \"javascript\",\n  Python: \"python\",\n  TypeScript: \"typescript\",\n} as const;\n\n/**\n * Type for {@link CDK_INIT_LANGUAGE} values.\n */\nexport type CdkInitLanguage =\n  (typeof CDK_INIT_LANGUAGE)[keyof typeof CDK_INIT_LANGUAGE];\n\n/**\n * `--package-manager` values accepted by `cdk init`.\n *\n * Only applicable to TypeScript and JavaScript projects; the CLI defaults to\n * `npm` for those and ignores the flag for every other language.\n */\nexport const CDK_INIT_PACKAGE_MANAGER = {\n  Npm: \"npm\",\n  Yarn: \"yarn\",\n  Pnpm: \"pnpm\",\n  Bun: \"bun\",\n} as const;\n\n/**\n * Type for {@link CDK_INIT_PACKAGE_MANAGER} values.\n */\nexport type CdkInitPackageManager =\n  (typeof CDK_INIT_PACKAGE_MANAGER)[keyof typeof CDK_INIT_PACKAGE_MANAGER];\n\n/**\n * `--from-scan` values accepted by `cdk migrate` — whether to start a new\n * CloudFormation resource scan or reuse the last successful one.\n *\n * Upstream declares `--from-scan` as a free-form `string` option and documents\n * the two accepted values only in the flag description rather than as a yargs\n * `choices` array. This enum pins that documented pair so callers cannot\n * render an invocation the CLI will reject.\n */\nexport const CDK_MIGRATE_FROM_SCAN = {\n  New: \"new\",\n  MostRecent: \"most-recent\",\n} as const;\n\n/**\n * Type for {@link CDK_MIGRATE_FROM_SCAN} values.\n */\nexport type CdkMigrateFromScan =\n  (typeof CDK_MIGRATE_FROM_SCAN)[keyof typeof CDK_MIGRATE_FROM_SCAN];\n","import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { Nodes, Parent, Root } from \"mdast\";\nimport { fromMarkdown } from \"mdast-util-from-markdown\";\n\n/**\n * One row in the doc reference-extraction report — describes a single\n * inline-code symbol mention found in a markdown page and whether\n * that symbol is present in the supplied `knownSymbols` list.\n */\nexport interface DocReferenceRecord {\n  /**\n   * Path to the markdown file the mention was found in. Resolved\n   * relative to the configured `docsRoot` so reports are stable\n   * across machines (no absolute prefixes leak through).\n   */\n  readonly docPath: string;\n\n  /**\n   * 1-indexed line number of the inline-code span in the markdown\n   * source.\n   */\n  readonly line: number;\n\n  /**\n   * 1-indexed column where the inline-code span starts (the position\n   * of the opening backtick).\n   */\n  readonly column: number;\n\n  /**\n   * The exact symbol text inside the backticks, e.g. `analyzeTsDocCoverage`.\n   * Whitespace inside the inline-code span is preserved as-is and\n   * the candidate is included only when it matches the configured\n   * identifier pattern.\n   */\n  readonly symbol: string;\n\n  /**\n   * `true` when the symbol appears in the supplied `knownSymbols`\n   * set. The downstream scan phase (#519) treats `false` as an\n   * orphan reference candidate (advisory).\n   */\n  readonly isKnown: boolean;\n}\n\n/**\n * Options accepted by {@link extractDocReferences}.\n */\nexport interface ExtractDocReferencesOptions {\n  /**\n   * Absolute path to the docs root that should be walked for\n   * `*.md` files. Defaults to `docs/src/content/docs/` relative\n   * to the current working directory when omitted.\n   *\n   * @default \"docs/src/content/docs\"\n   */\n  readonly docsRoot?: string;\n\n  /**\n   * List of known public symbols to cross-index inline-code\n   * mentions against. Typically the `symbol` column of the\n   * report returned by `analyzeTsDocCoverage()` plus, optionally,\n   * any extra names sourced from the api-extractor `.api.md`\n   * rollup. Order is irrelevant; duplicates are deduplicated.\n   */\n  readonly knownSymbols?: ReadonlyArray<string>;\n\n  /**\n   * Regular expression a candidate must match to be considered a\n   * TypeScript-identifier-shaped symbol. The default rejects\n   * obvious non-symbol prose tokens (paths with slashes, prose\n   * with spaces, lowercase one-letter words) while accepting the\n   * three common identifier shapes used in the monorepo:\n   * camelCase (`analyzeTsDocCoverage`), PascalCase\n   * (`TsDocCoverageRecord`), and UPPER_SNAKE_CASE (`MAX_RETRIES`).\n   *\n   * Override this only if a project uses an unusual identifier\n   * style — a custom pattern that is too permissive will produce\n   * a noisy backlog of false positives.\n   *\n   * @default /^(?:[a-z][a-zA-Z0-9]*|[A-Z][a-zA-Z0-9]*|[A-Z][A-Z0-9_]*)$/\n   */\n  readonly symbolPattern?: RegExp;\n}\n\nconst DEFAULT_DOCS_ROOT = \"docs/src/content/docs\";\n\n/**\n * Default identifier pattern. Accepts the three common identifier\n * shapes used in this monorepo and rejects everything else.\n *\n * - `analyzeTsDocCoverage` (camelCase) — at least one character.\n * - `TsDocCoverageRecord` (PascalCase) — at least one character.\n * - `MAX_RETRIES` (UPPER_SNAKE_CASE) — only digits and underscores after the first uppercase letter.\n */\nconst DEFAULT_SYMBOL_PATTERN =\n  /^(?:[a-z][a-zA-Z0-9]*|[A-Z][a-zA-Z0-9]*|[A-Z][A-Z0-9_]*)$/;\n\n/**\n * Walks every `*.md` file under the configured docs root and\n * returns one record per inline-code symbol mention.\n *\n * The walker is AST-based — markdown is parsed with\n * `mdast-util-from-markdown` and only `inlineCode` nodes are\n * inspected. This means fenced code blocks, indented code blocks,\n * and HTML comments are skipped natively and never produce false\n * positives. Mentions inside link text or list items are\n * extracted normally.\n *\n * Candidates are filtered with the configured `symbolPattern`\n * (defaults to TS-identifier shapes — camelCase, PascalCase,\n * UPPER_SNAKE_CASE) so prose tokens like flags, file paths, or\n * multi-word phrases never appear in the report.\n *\n * @param options - Extraction options. All fields are optional;\n *                  pass an empty object to use defaults.\n */\nexport function extractDocReferences(\n  options: ExtractDocReferencesOptions = {},\n): Array<DocReferenceRecord> {\n  const docsRoot = path.resolve(options.docsRoot ?? DEFAULT_DOCS_ROOT);\n  const symbolPattern = options.symbolPattern ?? DEFAULT_SYMBOL_PATTERN;\n  const knownSymbols = new Set(options.knownSymbols ?? []);\n\n  if (!fs.existsSync(docsRoot)) {\n    return [];\n  }\n\n  const records: Array<DocReferenceRecord> = [];\n  for (const absolutePath of walkMarkdownFiles(docsRoot)) {\n    const docPath = toPosix(path.relative(docsRoot, absolutePath));\n    const source = fs.readFileSync(absolutePath, \"utf-8\");\n    const tree = fromMarkdown(stripYamlFrontmatter(source));\n    collectInlineCode(tree, (symbol, position) => {\n      if (!symbolPattern.test(symbol)) {\n        return;\n      }\n      records.push({\n        docPath,\n        line: position.line,\n        column: position.column,\n        symbol,\n        isKnown: knownSymbols.has(symbol),\n      });\n    });\n  }\n\n  // Sort by docPath then line then column so the report is\n  // deterministic across runs — downstream consumers (the scan\n  // phase report writer in #519) depend on a stable ordering.\n  records.sort((a, b) => {\n    if (a.docPath !== b.docPath) {\n      return a.docPath.localeCompare(b.docPath);\n    }\n    if (a.line !== b.line) {\n      return a.line - b.line;\n    }\n    if (a.column !== b.column) {\n      return a.column - b.column;\n    }\n    return a.symbol.localeCompare(b.symbol);\n  });\n\n  return records;\n}\n\nfunction walkMarkdownFiles(root: string): Array<string> {\n  const out: Array<string> = [];\n  const stack: Array<string> = [root];\n  while (stack.length > 0) {\n    const dir = stack.pop()!;\n    let entries: Array<fs.Dirent>;\n    try {\n      entries = fs.readdirSync(dir, { withFileTypes: true });\n    } catch {\n      continue;\n    }\n    for (const entry of entries) {\n      const full = path.join(dir, entry.name);\n      if (entry.isDirectory()) {\n        stack.push(full);\n      } else if (entry.isFile() && full.toLowerCase().endsWith(\".md\")) {\n        out.push(full);\n      }\n    }\n  }\n  // Sort here too so the final report ordering is independent of\n  // the (platform-specific) directory-listing order.\n  out.sort();\n  return out;\n}\n\ninterface InlineCodePosition {\n  readonly line: number;\n  readonly column: number;\n}\n\nfunction collectInlineCode(\n  tree: Root,\n  visit: (symbol: string, position: InlineCodePosition) => void,\n): void {\n  // Walk only nodes that can contain inline phrasing content.\n  // `code` (fenced + indented) and `html` (HTML blocks +\n  // comments) are *intentionally* never descended into — they\n  // are the must-NOT-extract cases enumerated in the issue body.\n  walk(tree);\n\n  function walk(node: Nodes): void {\n    if (node.type === \"inlineCode\") {\n      const start = node.position?.start;\n      if (!start) {\n        return;\n      }\n      visit(node.value, { line: start.line, column: start.column });\n      return;\n    }\n    if (node.type === \"code\" || node.type === \"html\") {\n      return;\n    }\n    const parent = node as Partial<Parent>;\n    if (Array.isArray(parent.children)) {\n      for (const child of parent.children) {\n        walk(child as Nodes);\n      }\n    }\n  }\n}\n\nfunction toPosix(p: string): string {\n  return p.split(path.sep).join(\"/\");\n}\n\n/**\n * Strip leading YAML frontmatter (`--- ... ---`) from a markdown\n * source while preserving line numbers. Without the dedicated\n * frontmatter micromark extension, `mdast-util-from-markdown`\n * parses `---` as a thematic break and the YAML body as a\n * heading + paragraph, which leaks backtick-quoted values from\n * frontmatter into the inline-code report.\n *\n * The fence-content lines are replaced with blank lines (not\n * removed) so reported `line` numbers continue to point at the\n * correct position in the original source.\n */\nfunction stripYamlFrontmatter(source: string): string {\n  if (!source.startsWith(\"---\")) {\n    return source;\n  }\n  const lines = source.split(\"\\n\");\n  if (lines[0] !== \"---\") {\n    return source;\n  }\n  let endIndex = -1;\n  for (let i = 1; i < lines.length; i++) {\n    if (lines[i] === \"---\") {\n      endIndex = i;\n      break;\n    }\n  }\n  if (endIndex < 0) {\n    return source;\n  }\n  for (let i = 0; i <= endIndex; i++) {\n    lines[i] = \"\";\n  }\n  return lines.join(\"\\n\");\n}\n","import * as path from \"node:path\";\nimport * as ts from \"typescript\";\nimport {\n  ExtractFencedSamplesOptions,\n  FencedSampleRecord,\n  SampleLang,\n  extractFencedSamples,\n} from \"./extraction\";\n\n/**\n * One row in the sample-compilation report — describes a single\n * compilation failure. Compiles that succeeded are intentionally\n * absent: the docs-sync scan phase consumes failures only and treats\n * an empty array as \"every sample compiled cleanly\".\n */\nexport interface SampleCompilationFailure {\n  /**\n   * Path to the markdown file the sample was extracted from. Resolved\n   * relative to the configured `docsRoot` so reports are stable\n   * across machines.\n   */\n  readonly docPath: string;\n\n  /**\n   * 1-indexed line number of the opening fence in the source markdown\n   * file (the line that begins with the three backticks).\n   */\n  readonly line: number;\n\n  /**\n   * 0-indexed position of this fenced block among all fenced TS-shaped\n   * blocks in the same markdown file.\n   */\n  readonly fenceIndex: number;\n\n  /**\n   * Language tag the sample carried — one of `ts`, `typescript`,\n   * `tsx`, or `typescriptreact`.\n   */\n  readonly lang: SampleLang;\n\n  /**\n   * Flat array of compiler diagnostics, one entry per `tsc` finding.\n   * Each entry is the message text plus any code prefix the compiler\n   * surfaced — formatted to be self-contained so the consuming scan\n   * report can render the failure without re-running the compiler.\n   */\n  readonly diagnostics: Array<string>;\n}\n\n/**\n * Options accepted by {@link compileFencedSamples}.\n */\nexport interface CompileFencedSamplesOptions extends ExtractFencedSamplesOptions {\n  /**\n   * Override the {@link ts.CompilerOptions} the helper uses when\n   * compiling each sample. Merged on top of the helper's defaults\n   * (see {@link DEFAULT_SAMPLE_COMPILER_OPTIONS}). Override sparingly:\n   * the defaults are tuned to be permissive on prose samples (no\n   * unused-locals/unused-parameters errors, JSX preserved for tsx,\n   * lib targets DOM/ES2022). Setting an option to `undefined` here\n   * removes the helper's default for that key.\n   */\n  readonly compilerOptions?: ts.CompilerOptions;\n\n  /**\n   * When `true`, diagnostics carrying TS error code `2307`\n   * (\"Cannot find module …\") are demoted from failures to silent\n   * skips for repo-relative module specifiers (paths starting with\n   * `./`, `../`, or `/`). Bare specifiers like `react` or\n   * `@scope/pkg` are still treated as failures because they\n   * indicate genuinely missing imports rather than docs-relative\n   * sample drift.\n   *\n   * @default true\n   */\n  readonly tolerateRepoRelativeMissingModule?: boolean;\n}\n\n/**\n * Default compiler options applied to every fenced sample. Tuned to\n * be permissive on prose samples while still surfacing real\n * compilation errors:\n *\n * - `target` / `module` mirror modern Node + ES module conventions.\n * - `lib` carries `DOM` so samples that mention `console`,\n *   `document`, or `window` compile cleanly.\n * - `strict` stays on so the helper still catches type errors.\n * - `noUnusedLocals` / `noUnusedParameters` stay **off** because\n *   prose samples often declare a name purely to demonstrate a\n *   shape; flagging that as a failure would block useful docs.\n * - `skipLibCheck` is on so a missing `.d.ts` in a transitive\n *   dependency does not poison the suite.\n * - `jsx` preserves the JSX so `tsx` fenced blocks compile.\n * - `noEmit` is the whole point — we only need diagnostics.\n */\nexport const DEFAULT_SAMPLE_COMPILER_OPTIONS: ts.CompilerOptions = {\n  target: ts.ScriptTarget.ES2022,\n  module: ts.ModuleKind.ESNext,\n  moduleResolution: ts.ModuleResolutionKind.Bundler,\n  lib: [\"lib.es2022.d.ts\", \"lib.dom.d.ts\"],\n  strict: true,\n  noUnusedLocals: false,\n  noUnusedParameters: false,\n  skipLibCheck: true,\n  esModuleInterop: true,\n  resolveJsonModule: true,\n  isolatedModules: true,\n  jsx: ts.JsxEmit.Preserve,\n  noEmit: true,\n  allowSyntheticDefaultImports: true,\n};\n\nconst REPO_RELATIVE_MODULE_PATTERN = /^['\"](?:\\.\\.?\\/|\\/)/;\n\n/**\n * Walks every `*.md` file under the configured docs root, extracts\n * fenced TypeScript samples, and runs the TypeScript compiler against\n * each non-skipped sample. Returns one record per failing sample —\n * passing samples are intentionally absent from the result.\n *\n * Each sample is compiled in its own in-memory program so unrelated\n * blocks never share scope. Skipped samples (fence meta `skip` /\n * `no-check`, or first line `// @no-check`) are passed through\n * unchecked.\n *\n * The helper does not invoke `tsc` as a subprocess — it uses the TS\n * compiler API directly with the host's `typescript` peer dependency.\n * That means a single test or scan run produces a single TypeScript\n * Program per sample, which is fast enough for the scan-phase budget\n * but does mean callers must not pass it the full repo's `docs/`\n * tree at unit-test time. Tests stay on small inline tmpdir fixtures.\n *\n * @param options - Compilation options. All fields are optional;\n *                  pass an empty object to use defaults.\n */\nexport function compileFencedSamples(\n  options: CompileFencedSamplesOptions = {},\n): Array<SampleCompilationFailure> {\n  const samples = extractFencedSamples(options);\n  const tolerateRepoRelative =\n    options.tolerateRepoRelativeMissingModule ?? true;\n  const failures: Array<SampleCompilationFailure> = [];\n  for (const sample of samples) {\n    if (sample.skipped) {\n      continue;\n    }\n    const diagnostics = compileSingleSample(\n      sample,\n      options.compilerOptions,\n      tolerateRepoRelative,\n    );\n    if (diagnostics.length > 0) {\n      failures.push({\n        docPath: sample.docPath,\n        line: sample.line,\n        fenceIndex: sample.fenceIndex,\n        lang: sample.lang,\n        diagnostics,\n      });\n    }\n  }\n  return failures;\n}\n\nfunction compileSingleSample(\n  sample: FencedSampleRecord,\n  overrides: ts.CompilerOptions | undefined,\n  tolerateRepoRelative: boolean,\n): Array<string> {\n  const filename = sampleFilename(sample);\n  const compilerOptions = mergeCompilerOptions(overrides);\n  const host = createSingleFileHost(filename, sample.code, compilerOptions);\n  const program = ts.createProgram({\n    rootNames: [filename],\n    options: compilerOptions,\n    host,\n  });\n  const sourceFile = program.getSourceFile(filename);\n  const collected: Array<ts.Diagnostic> = [];\n  if (sourceFile) {\n    collected.push(...program.getSyntacticDiagnostics(sourceFile));\n    collected.push(...program.getSemanticDiagnostics(sourceFile));\n  } else {\n    collected.push(...program.getSyntacticDiagnostics());\n    collected.push(...program.getSemanticDiagnostics());\n  }\n  const diagnostics: Array<string> = [];\n  for (const d of collected) {\n    if (tolerateRepoRelative && isRepoRelativeMissingModule(d, sample.code)) {\n      continue;\n    }\n    diagnostics.push(formatDiagnostic(d));\n  }\n  return diagnostics;\n}\n\nfunction sampleFilename(sample: FencedSampleRecord): string {\n  const safeDoc = sample.docPath.replace(/[^a-zA-Z0-9]+/g, \"_\");\n  const ext =\n    sample.lang === SampleLang.Tsx || sample.lang === SampleLang.Typescriptreact\n      ? \"tsx\"\n      : \"ts\";\n  // Use a virtual absolute path so module resolution stays predictable.\n  return path.posix.join(\"/\", `${safeDoc}__${sample.fenceIndex}.${ext}`);\n}\n\nfunction mergeCompilerOptions(\n  overrides: ts.CompilerOptions | undefined,\n): ts.CompilerOptions {\n  if (!overrides) {\n    return { ...DEFAULT_SAMPLE_COMPILER_OPTIONS };\n  }\n  const merged: ts.CompilerOptions = { ...DEFAULT_SAMPLE_COMPILER_OPTIONS };\n  for (const key of Object.keys(overrides)) {\n    const value = overrides[key];\n    if (value === undefined) {\n      delete merged[key];\n    } else {\n      merged[key] = value;\n    }\n  }\n  return merged;\n}\n\nfunction createSingleFileHost(\n  filename: string,\n  source: string,\n  compilerOptions: ts.CompilerOptions,\n): ts.CompilerHost {\n  // Start from the default host so lib.*.d.ts files resolve from the\n  // installed `typescript` package — the helper relies on the peer\n  // dependency's bundled libs to type-check `console`, `Promise`,\n  // and other globals.\n  const baseHost = ts.createCompilerHost(compilerOptions, true);\n  return {\n    ...baseHost,\n    getSourceFile(name, languageVersionOrOptions, onError, shouldCreate) {\n      if (name === filename) {\n        return ts.createSourceFile(\n          name,\n          source,\n          languageVersionOrOptions,\n          true,\n        );\n      }\n      return baseHost.getSourceFile(\n        name,\n        languageVersionOrOptions,\n        onError,\n        shouldCreate,\n      );\n    },\n    fileExists(name) {\n      if (name === filename) {\n        return true;\n      }\n      return baseHost.fileExists(name);\n    },\n    readFile(name) {\n      if (name === filename) {\n        return source;\n      }\n      return baseHost.readFile(name);\n    },\n    writeFile() {\n      // noEmit — never write anything.\n    },\n    getCanonicalFileName(name) {\n      return baseHost.getCanonicalFileName(name);\n    },\n    useCaseSensitiveFileNames() {\n      return baseHost.useCaseSensitiveFileNames();\n    },\n    getNewLine() {\n      return baseHost.getNewLine();\n    },\n    getDefaultLibFileName(o) {\n      return baseHost.getDefaultLibFileName(o);\n    },\n    getCurrentDirectory() {\n      return baseHost.getCurrentDirectory();\n    },\n  };\n}\n\nfunction isRepoRelativeMissingModule(d: ts.Diagnostic, code: string): boolean {\n  if (d.code !== 2307) {\n    return false;\n  }\n  // The diagnostic's textual form contains the module specifier\n  // wrapped in single quotes. `ts.flattenDiagnosticMessageText` is the\n  // canonical accessor for the message regardless of chained\n  // diagnostic shape.\n  const text = ts.flattenDiagnosticMessageText(d.messageText, \"\\n\");\n  // Pull the module specifier out of the message: shape is\n  // `Cannot find module 'X' or its corresponding type declarations.`\n  const match = /'([^']+)'/.exec(text);\n  if (!match) {\n    return false;\n  }\n  const specifier = match[1];\n  if (!specifier) {\n    return false;\n  }\n  // Match the specifier as a quoted string against the source so we\n  // also catch the case where the message used double quotes.\n  const inSourceSingle = `'${specifier}'`;\n  const inSourceDouble = `\"${specifier}\"`;\n  if (!code.includes(inSourceSingle) && !code.includes(inSourceDouble)) {\n    return false;\n  }\n  return REPO_RELATIVE_MODULE_PATTERN.test(`'${specifier}'`);\n}\n\nfunction formatDiagnostic(d: ts.Diagnostic): string {\n  const text = ts.flattenDiagnosticMessageText(d.messageText, \" \");\n  const code = d.code === undefined ? \"\" : `TS${d.code}: `;\n  return `${code}${text}`.trim();\n}\n","import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { Code, Nodes, Parent, Root } from \"mdast\";\nimport { fromMarkdown } from \"mdast-util-from-markdown\";\n\n/**\n * One row in the fenced-sample extraction report — describes a single\n * fenced TypeScript code block found in a markdown page.\n */\nexport interface FencedSampleRecord {\n  /**\n   * Path to the markdown file the sample was extracted from. Resolved\n   * relative to the configured `docsRoot` so reports are stable\n   * across machines (no absolute prefixes leak through).\n   */\n  readonly docPath: string;\n\n  /**\n   * 1-indexed line number of the opening fence (the line that begins\n   * with the three backticks), as reported by the markdown parser.\n   */\n  readonly line: number;\n\n  /**\n   * 0-indexed position of this fenced block among all fenced TS-shaped\n   * blocks in the same markdown file. Useful when a single page has\n   * multiple samples and the consumer needs to disambiguate findings.\n   */\n  readonly fenceIndex: number;\n\n  /**\n   * Language tag as written on the opening fence (e.g. `ts`,\n   * `typescript`, `tsx`, `typescriptreact`). Always lower-cased.\n   */\n  readonly lang: SampleLang;\n\n  /**\n   * Raw source of the code block, exactly as written between the\n   * fences. Trailing newlines are preserved so the compiler sees the\n   * same input the human author intended.\n   */\n  readonly code: string;\n\n  /**\n   * `true` when the sample was tagged as opt-out (via fence meta or\n   * an in-source pragma) and the compilation phase should skip it.\n   * Skipped samples are still surfaced in the extraction report so\n   * downstream consumers can audit them; the {@link compileFencedSamples}\n   * helper filters them out before invoking `tsc`.\n   */\n  readonly skipped: boolean;\n\n  /**\n   * Short description of why a sample was skipped. Empty string when\n   * `skipped` is `false`.\n   */\n  readonly skipReason: string;\n}\n\n/**\n * Recognized fenced-block language tags that the extractor treats as\n * compilable TypeScript samples.\n */\nexport const SampleLang = {\n  Ts: \"ts\",\n  Typescript: \"typescript\",\n  Tsx: \"tsx\",\n  Typescriptreact: \"typescriptreact\",\n} as const;\n\n/**\n * String-literal type matching the values of {@link SampleLang}.\n */\nexport type SampleLang = (typeof SampleLang)[keyof typeof SampleLang];\n\n/**\n * Options accepted by {@link extractFencedSamples}.\n */\nexport interface ExtractFencedSamplesOptions {\n  /**\n   * Absolute or repo-relative path to the docs root that should be\n   * walked for `*.md` files. Defaults to `docs/src/content/docs/`\n   * relative to the current working directory when omitted.\n   *\n   * @default \"docs/src/content/docs\"\n   */\n  readonly docsRoot?: string;\n\n  /**\n   * When `true`, fenced blocks tagged `tsx` or `typescriptreact` are\n   * included in the report. Defaults to `true` because the docs-sync\n   * scan phase is JSX-aware; flip to `false` to scope a run to plain\n   * TypeScript only.\n   *\n   * @default true\n   */\n  readonly includeTsx?: boolean;\n}\n\nconst DEFAULT_DOCS_ROOT = \"docs/src/content/docs\";\n\nconst PLAIN_LANGS = new Set<SampleLang>([SampleLang.Ts, SampleLang.Typescript]);\nconst JSX_LANGS = new Set<SampleLang>([\n  SampleLang.Tsx,\n  SampleLang.Typescriptreact,\n]);\n\n/**\n * Walks every `*.md` file under the configured docs root and returns\n * one record per fenced TypeScript code block.\n *\n * The walker is AST-based — markdown is parsed with\n * `mdast-util-from-markdown` and only `code` (fenced + indented)\n * nodes are inspected. The `lang` attribute on the AST node is\n * matched against {@link SampleLang}; fences tagged `ts`,\n * `typescript`, `tsx`, or `typescriptreact` produce records.\n * Anything else (`bash`, `json`, untagged, etc.) is skipped.\n *\n * Skip detection. A sample is recorded with `skipped: true` when\n * either of these conditions holds:\n *\n * - The fence's `meta` string contains the word `skip` or `no-check`\n *   (case-insensitive) — i.e. either token follows the language tag\n *   on the opening fence line.\n * - The sample's first non-blank line is the comment `// @no-check`\n *   (case-insensitive on the directive name; the leading `//` is\n *   required).\n *\n * @param options - Extraction options. All fields are optional; pass\n *                  an empty object to use defaults.\n */\nexport function extractFencedSamples(\n  options: ExtractFencedSamplesOptions = {},\n): Array<FencedSampleRecord> {\n  const docsRoot = path.resolve(options.docsRoot ?? DEFAULT_DOCS_ROOT);\n  const includeTsx = options.includeTsx ?? true;\n\n  if (!fs.existsSync(docsRoot)) {\n    return [];\n  }\n\n  const records: Array<FencedSampleRecord> = [];\n  for (const absolutePath of walkMarkdownFiles(docsRoot)) {\n    const docPath = toPosix(path.relative(docsRoot, absolutePath));\n    const source = fs.readFileSync(absolutePath, \"utf-8\");\n    const tree = fromMarkdown(stripYamlFrontmatter(source));\n    let fenceIndex = 0;\n    collectFencedCode(tree, (node) => {\n      const lang = normalizeLang(node.lang);\n      if (lang === undefined) {\n        return;\n      }\n      if (!includeTsx && JSX_LANGS.has(lang)) {\n        return;\n      }\n      if (!PLAIN_LANGS.has(lang) && !JSX_LANGS.has(lang)) {\n        return;\n      }\n      const start = node.position?.start;\n      if (!start) {\n        return;\n      }\n      const skip = detectSkip(node);\n      records.push({\n        docPath,\n        line: start.line,\n        fenceIndex,\n        lang,\n        code: node.value ?? \"\",\n        skipped: skip.skipped,\n        skipReason: skip.reason,\n      });\n      fenceIndex += 1;\n    });\n  }\n\n  records.sort((a, b) => {\n    if (a.docPath !== b.docPath) {\n      return a.docPath.localeCompare(b.docPath);\n    }\n    if (a.line !== b.line) {\n      return a.line - b.line;\n    }\n    return a.fenceIndex - b.fenceIndex;\n  });\n\n  return records;\n}\n\nfunction walkMarkdownFiles(root: string): Array<string> {\n  const out: Array<string> = [];\n  const stack: Array<string> = [root];\n  while (stack.length > 0) {\n    const dir = stack.pop()!;\n    let entries: Array<fs.Dirent>;\n    try {\n      entries = fs.readdirSync(dir, { withFileTypes: true });\n    } catch {\n      continue;\n    }\n    for (const entry of entries) {\n      const full = path.join(dir, entry.name);\n      if (entry.isDirectory()) {\n        stack.push(full);\n      } else if (entry.isFile() && full.toLowerCase().endsWith(\".md\")) {\n        out.push(full);\n      }\n    }\n  }\n  out.sort();\n  return out;\n}\n\nfunction collectFencedCode(tree: Root, visit: (node: Code) => void): void {\n  walk(tree);\n\n  function walk(node: Nodes): void {\n    if (node.type === \"code\") {\n      visit(node);\n      return;\n    }\n    if (node.type === \"html\") {\n      return;\n    }\n    const parent = node as Partial<Parent>;\n    if (Array.isArray(parent.children)) {\n      for (const child of parent.children) {\n        walk(child as Nodes);\n      }\n    }\n  }\n}\n\nfunction normalizeLang(raw: string | null | undefined): SampleLang | undefined {\n  if (!raw) {\n    return undefined;\n  }\n  const lower = raw.toLowerCase();\n  switch (lower) {\n    case \"ts\":\n      return SampleLang.Ts;\n    case \"typescript\":\n      return SampleLang.Typescript;\n    case \"tsx\":\n      return SampleLang.Tsx;\n    case \"typescriptreact\":\n      return SampleLang.Typescriptreact;\n    default:\n      return undefined;\n  }\n}\n\nconst META_SKIP_PATTERN = /\\b(skip|no-check)\\b/i;\nconst PRAGMA_NO_CHECK_PATTERN = /^\\s*\\/\\/\\s*@no-check\\b/i;\n\ninterface SkipDetection {\n  readonly skipped: boolean;\n  readonly reason: string;\n}\n\nfunction detectSkip(node: Code): SkipDetection {\n  const meta = node.meta ?? \"\";\n  const metaMatch = META_SKIP_PATTERN.exec(meta);\n  if (metaMatch) {\n    return { skipped: true, reason: `meta:${metaMatch[1].toLowerCase()}` };\n  }\n  const code = node.value ?? \"\";\n  const firstLine = firstNonBlankLine(code);\n  if (firstLine !== undefined && PRAGMA_NO_CHECK_PATTERN.test(firstLine)) {\n    return { skipped: true, reason: \"pragma:@no-check\" };\n  }\n  return { skipped: false, reason: \"\" };\n}\n\nfunction firstNonBlankLine(source: string): string | undefined {\n  for (const line of source.split(\"\\n\")) {\n    if (line.trim().length > 0) {\n      return line;\n    }\n  }\n  return undefined;\n}\n\nfunction toPosix(p: string): string {\n  return p.split(path.sep).join(\"/\");\n}\n\n/**\n * Strip leading YAML frontmatter (`--- ... ---`) from a markdown\n * source while preserving line numbers. Without the dedicated\n * frontmatter micromark extension, `mdast-util-from-markdown`\n * parses `---` as a thematic break and the YAML body as a heading +\n * paragraph — which can cause the parser to misreport positions for\n * subsequent fenced blocks. The fence-content lines are replaced\n * with blank lines (not removed) so reported `line` numbers continue\n * to point at the correct position in the original source.\n */\nfunction stripYamlFrontmatter(source: string): string {\n  if (!source.startsWith(\"---\")) {\n    return source;\n  }\n  const lines = source.split(\"\\n\");\n  if (lines[0] !== \"---\") {\n    return source;\n  }\n  let endIndex = -1;\n  for (let i = 1; i < lines.length; i++) {\n    if (lines[i] === \"---\") {\n      endIndex = i;\n      break;\n    }\n  }\n  if (endIndex < 0) {\n    return source;\n  }\n  for (let i = 0; i <= endIndex; i++) {\n    lines[i] = \"\";\n  }\n  return lines.join(\"\\n\");\n}\n","/**\n * Schema definitions for the docs-sync scan-phase audit report.\n *\n * The report is the durable output of Phase 1 (Scan) of the docs-sync\n * pipeline (parent epic #448). Phase 1 walks the repo, runs every\n * registered drift check, and persists a single combined report to\n * `.state/docs-sync/<N>-audit.json` (where `<N>` is the\n * tracking-issue number). Phase 2 (Fix) reads the persisted report\n * and applies mechanical fixes — the two phases never share an\n * in-memory handle, so the JSON shape on disk is the contract\n * between them.\n *\n * #518 ships the **schema and the orchestrator skeleton only**. The\n * actual drift checks (API/TSDoc/reference, link, fenced-sample) are\n * wired in by children #519 and #520 by passing additional\n * `AuditCheckRunner` instances to {@link runScan}. An empty\n * runner list is the supported scaffold-time configuration and\n * produces a schema-compliant report with empty findings in every\n * category.\n *\n * The schema is intentionally **keyed by drift-check category** at\n * the top level (`apiDiff`, `tsdocCoverage`, `referenceMismatches`,\n * `linkFailures`, `sampleFailures`) so consumers can render or\n * filter by category without re-grouping a flat list. Each\n * category-keyed array carries category-specific finding shapes,\n * and a flat `findings` array re-aggregates the same records with\n * `category` and `severity` fields attached so the report doubles\n * as a backlog source for downstream tooling.\n */\n\n/**\n * Drift-check categories the docs-sync scan phase can produce\n * findings in. Exhaustive — adding a new category here is a schema\n * change that requires bumping {@link DOCS_SYNC_AUDIT_SCHEMA_VERSION}\n * and updating every consumer that switches on the literal.\n */\nexport const AuditCategory = {\n  /**\n   * Findings produced by the public-API diff check that surfaces\n   * added, renamed, or removed exports between the current branch\n   * and the recorded baseline. Wired in by child issue #519.\n   */\n  ApiDiff: \"apiDiff\",\n\n  /**\n   * Findings produced by the TSDoc-coverage check that flags public\n   * exports without a one-sentence summary. Wired in by child issue\n   * #519.\n   */\n  TsdocCoverage: \"tsdocCoverage\",\n\n  /**\n   * Findings produced by the doc-reference cross-index check that\n   * flags inline-code symbol mentions whose target is missing or\n   * has changed. Wired in by child issue #519.\n   */\n  ReferenceMismatches: \"referenceMismatches\",\n\n  /**\n   * Findings produced by the link-integrity check (internal via\n   * `astro check`, external via `lychee`). Wired in by child issue\n   * #520.\n   */\n  LinkFailures: \"linkFailures\",\n\n  /**\n   * Findings produced by the fenced-sample compilation check that\n   * flags `ts`, `typescript`, and `tsx` fenced code blocks in the\n   * docs that fail `tsc`. Wired in by child issue #520.\n   */\n  SampleFailures: \"sampleFailures\",\n} as const;\n\n/**\n * String-literal type matching the values of {@link AuditCategory}.\n */\nexport type AuditCategory = (typeof AuditCategory)[keyof typeof AuditCategory];\n\n/**\n * Severity ladder applied to every finding before persistence. The\n * ladder mirrors the parent epic's behavior-on-drift contract —\n * mechanical fixes auto-apply, advisory findings post a non-blocking\n * note, blocking findings hand off to `pr-reviewer` via\n * `review:human-required`.\n */\nexport const AuditSeverity = {\n  /**\n   * The finding has a deterministic mechanical fix that the Phase 2\n   * (Fix) agent will auto-apply (TSDoc stubs, dead-link updates,\n   * registry sync, etc.).\n   */\n  Mechanical: \"mechanical\",\n\n  /**\n   * The finding deserves human attention but does not block the PR.\n   * Surfaced as a non-blocking note on the sticky `## Docs sync`\n   * comment.\n   */\n  Advisory: \"advisory\",\n\n  /**\n   * The finding blocks the PR. Per the parent epic this is reserved\n   * for the two narrow cases of confirmed broken external links and\n   * fenced TS samples that fail to compile.\n   */\n  Blocking: \"blocking\",\n} as const;\n\n/**\n * String-literal type matching the values of {@link AuditSeverity}.\n */\nexport type AuditSeverity = (typeof AuditSeverity)[keyof typeof AuditSeverity];\n\n/**\n * Invocation mode of the scan phase. Determines how downstream\n * tooling treats the report — `pr` reports run against a single\n * branch and feed `pr-reviewer`; `audit` reports walk the whole\n * repo and feed the prioritized `docs:write` backlog.\n */\nexport const AuditMode = {\n  Pr: \"pr\",\n  Audit: \"audit\",\n} as const;\n\n/**\n * String-literal type matching the values of {@link AuditMode}.\n */\nexport type AuditMode = (typeof AuditMode)[keyof typeof AuditMode];\n\n/**\n * File-and-line location attached to most finding shapes. The\n * `file` field is always a path relative to the repo root so reports\n * are portable across machines; absolute paths must be normalized\n * before they reach the report.\n */\nexport interface AuditLocation {\n  /**\n   * Path relative to {@link AuditReport.repoRoot}. Empty string is\n   * permitted for findings that have no associated file (e.g. an\n   * `apiDiff` removed-export finding that lost its source location).\n   */\n  readonly file: string;\n\n  /**\n   * 1-indexed line number when known. `0` means \"line is not known\"\n   * — downstream consumers must treat `0` as missing rather than as\n   * the literal first line.\n   */\n  readonly line: number;\n}\n\n/**\n * Common fields every finding shape carries. The category-specific\n * record types below extend this interface with additional fields.\n */\nexport interface AuditFindingBase {\n  /**\n   * Drift-check category that produced the finding. Mirrors the key\n   * on the {@link AuditReport} that the finding is filed under.\n   */\n  readonly category: AuditCategory;\n\n  /**\n   * Severity classification per the {@link AuditSeverity} ladder.\n   */\n  readonly severity: AuditSeverity;\n\n  /**\n   * Source location the finding is anchored at. Empty location is\n   * tolerated for findings with no concrete anchor.\n   */\n  readonly location: AuditLocation;\n\n  /**\n   * Stable subject identifier. For symbol findings this is the\n   * exported symbol name; for link findings the URL; for sample\n   * findings the docPath plus fence index. Used by Phase 2 to\n   * deduplicate findings across runs.\n   */\n  readonly subject: string;\n\n  /**\n   * One-sentence human-readable description of the finding.\n   * Phase 2 surfaces this directly in the sticky PR comment, so\n   * keep it short and self-contained — no markdown links to\n   * external context, and never includes generated prose over the\n   * 100-word stub budget.\n   */\n  readonly details: string;\n\n  /**\n   * Optional hint for the Phase 2 fix agent. When present and the\n   * severity is `mechanical`, Phase 2 may use this string to\n   * compute the auto-applied edit. Free-form; downstream consumers\n   * should treat unknown hints as no-op.\n   */\n  readonly fixHint?: string;\n}\n\n/**\n * Finding produced by the public-API diff check. Wired in by #519.\n */\nexport interface ApiDiffFinding extends AuditFindingBase {\n  readonly category: typeof AuditCategory.ApiDiff;\n\n  /**\n   * Kind of API change observed. The literal `added` covers a new\n   * export; `removed` covers a deletion; `changed` covers a\n   * signature change that does not rename or remove the symbol.\n   */\n  readonly change: \"added\" | \"removed\" | \"changed\";\n\n  /**\n   * Public name of the symbol whose surface changed.\n   */\n  readonly symbol: string;\n}\n\n/**\n * Finding produced by the TSDoc-coverage check. Wired in by #519.\n */\nexport interface TsdocCoverageFinding extends AuditFindingBase {\n  readonly category: typeof AuditCategory.TsdocCoverage;\n\n  /**\n   * Public name of the symbol that is missing or has thin TSDoc.\n   */\n  readonly symbol: string;\n\n  /**\n   * Coverage shortfall the finding reports. `missing-summary`\n   * means no TSDoc at all; `thin-summary` means the summary exists\n   * but is shorter than the configured threshold; `missing-params`\n   * / `missing-returns` mean the signature has parameters or a\n   * return value with no matching block tag.\n   */\n  readonly shortfall:\n    \"missing-summary\" | \"thin-summary\" | \"missing-params\" | \"missing-returns\";\n}\n\n/**\n * Finding produced by the doc-reference cross-index check. Wired in\n * by #519.\n */\nexport interface ReferenceMismatchFinding extends AuditFindingBase {\n  readonly category: typeof AuditCategory.ReferenceMismatches;\n\n  /**\n   * Inline-code symbol referenced in the markdown source.\n   */\n  readonly symbol: string;\n\n  /**\n   * Why the reference is flagged. `unknown-symbol` means the\n   * symbol does not appear in the supplied known-symbols set;\n   * `signature-changed` means the symbol still resolves but its\n   * type signature differs from the cached snapshot.\n   */\n  readonly mismatch: \"unknown-symbol\" | \"signature-changed\";\n}\n\n/**\n * Finding produced by the link-integrity check. Wired in by #520.\n */\nexport interface LinkFailureFinding extends AuditFindingBase {\n  readonly category: typeof AuditCategory.LinkFailures;\n\n  /**\n   * URL or relative path that failed integrity checks.\n   */\n  readonly url: string;\n\n  /**\n   * Whether the link is internal (resolved by `astro check`) or\n   * external (resolved by `lychee`).\n   */\n  readonly kind: \"internal\" | \"external\";\n\n  /**\n   * Short tool-supplied diagnostic explaining the failure.\n   */\n  readonly reason: string;\n}\n\n/**\n * Finding produced by the fenced-sample compilation check. Wired in\n * by #520.\n */\nexport interface SampleFailureFinding extends AuditFindingBase {\n  readonly category: typeof AuditCategory.SampleFailures;\n\n  /**\n   * 0-indexed position of the fenced block within the markdown file.\n   */\n  readonly fenceIndex: number;\n\n  /**\n   * Language tag the sample carried (e.g. `ts`, `typescript`,\n   * `tsx`, `typescriptreact`).\n   */\n  readonly lang: string;\n\n  /**\n   * Compiler diagnostics produced by `tsc` against the sample.\n   */\n  readonly diagnostics: ReadonlyArray<string>;\n}\n\n/**\n * Discriminated union of every category-specific finding shape.\n */\nexport type AuditFinding =\n  | ApiDiffFinding\n  | TsdocCoverageFinding\n  | ReferenceMismatchFinding\n  | LinkFailureFinding\n  | SampleFailureFinding;\n\n/**\n * Schema version embedded on every persisted audit report. Bump on\n * any breaking change to the report shape so downstream consumers\n * can refuse incompatible files rather than mis-parsing them.\n *\n * Versioning is **integer-monotonic**: the producer of a v2 report\n * is responsible for keeping the v1 fields parseable when\n * possible, but a v1 reader must reject a v2 report it does not\n * understand.\n */\nexport const DOCS_SYNC_AUDIT_SCHEMA_VERSION = 1;\n\n/**\n * Top-level audit-report shape persisted to\n * `.state/docs-sync/<N>-audit.json`. The category-keyed\n * arrays are the durable surface; the flat `findings` array is a\n * convenience aggregation of the same records.\n */\nexport interface AuditReport {\n  /**\n   * Schema version embedded on every persisted report. Always\n   * equal to {@link DOCS_SYNC_AUDIT_SCHEMA_VERSION} at write time.\n   */\n  readonly schemaVersion: number;\n\n  /**\n   * Tracking-issue number the scan ran for. Determines the\n   * filename when persisted (`<issueNumber>-audit.json`).\n   */\n  readonly issueNumber: number;\n\n  /**\n   * Invocation mode — `pr` for diff-scoped runs invoked through\n   * `/docs-sync-pr`, `audit` for full-repo runs invoked through\n   * `/docs-sync-audit`.\n   */\n  readonly mode: AuditMode;\n\n  /**\n   * ISO 8601 UTC timestamp the scan completed at. Always written\n   * with `Z` suffix; consumers parse with `Date(...)`.\n   */\n  readonly generatedAt: string;\n\n  /**\n   * Absolute path to the repository root the scan ran against.\n   * Persisted so a downstream consumer reading the report on a\n   * different checkout can rewrite paths relative to its own\n   * root.\n   */\n  readonly repoRoot: string;\n\n  /**\n   * Optional free-form scope label attached at the issue level\n   * (e.g. `pr:feat/518-foo`, `audit:packages/configulator`).\n   * Empty string when no scope was supplied.\n   */\n  readonly scope: string;\n\n  /**\n   * Findings grouped by drift-check category. Every category key\n   * is always present and always an array — empty arrays are\n   * persisted explicitly so consumers never have to test for\n   * presence.\n   */\n  readonly categories: {\n    readonly apiDiff: ReadonlyArray<ApiDiffFinding>;\n    readonly tsdocCoverage: ReadonlyArray<TsdocCoverageFinding>;\n    readonly referenceMismatches: ReadonlyArray<ReferenceMismatchFinding>;\n    readonly linkFailures: ReadonlyArray<LinkFailureFinding>;\n    readonly sampleFailures: ReadonlyArray<SampleFailureFinding>;\n  };\n\n  /**\n   * Flat re-aggregation of every category-keyed finding into a\n   * single deterministically-ordered array. Sorted by `severity`\n   * (`blocking` first, then `advisory`, then `mechanical`), then\n   * `category` (alphabetical), then `location.file`,\n   * `location.line`, `subject`. Provided so consumers that don't\n   * need the category grouping can iterate one array and see the\n   * merge-blocking findings at the top.\n   */\n  readonly findings: ReadonlyArray<AuditFinding>;\n}\n\n/**\n * JSON-Schema-shaped descriptor for {@link AuditReport}. Returned by\n * {@link auditReportJsonSchema} so downstream tooling (e.g. ajv)\n * can validate persisted reports without re-importing the TS\n * types. The shape is hand-authored and deliberately permissive on\n * forward-compatible additions (extra category keys are forbidden;\n * extra finding fields are permitted).\n *\n * Returned as a plain JSON-shaped record — callers that want to\n * feed it into ajv or another validator pass it through directly.\n */\nexport function auditReportJsonSchema(): Record<string, unknown> {\n  const locationSchema = {\n    type: \"object\",\n    additionalProperties: false,\n    required: [\"file\", \"line\"],\n    properties: {\n      file: { type: \"string\" },\n      line: { type: \"integer\", minimum: 0 },\n    },\n  };\n\n  const findingBaseProperties = {\n    severity: { type: \"string\", enum: [\"mechanical\", \"advisory\", \"blocking\"] },\n    location: locationSchema,\n    subject: { type: \"string\" },\n    details: { type: \"string\" },\n    fixHint: { type: \"string\" },\n  };\n\n  const apiDiffFindingSchema = {\n    type: \"object\",\n    required: [\n      \"category\",\n      \"severity\",\n      \"location\",\n      \"subject\",\n      \"details\",\n      \"change\",\n      \"symbol\",\n    ],\n    properties: {\n      ...findingBaseProperties,\n      category: { type: \"string\", const: \"apiDiff\" },\n      change: { type: \"string\", enum: [\"added\", \"removed\", \"changed\"] },\n      symbol: { type: \"string\" },\n    },\n  };\n\n  const tsdocCoverageFindingSchema = {\n    type: \"object\",\n    required: [\n      \"category\",\n      \"severity\",\n      \"location\",\n      \"subject\",\n      \"details\",\n      \"shortfall\",\n      \"symbol\",\n    ],\n    properties: {\n      ...findingBaseProperties,\n      category: { type: \"string\", const: \"tsdocCoverage\" },\n      shortfall: {\n        type: \"string\",\n        enum: [\n          \"missing-summary\",\n          \"thin-summary\",\n          \"missing-params\",\n          \"missing-returns\",\n        ],\n      },\n      symbol: { type: \"string\" },\n    },\n  };\n\n  const referenceMismatchFindingSchema = {\n    type: \"object\",\n    required: [\n      \"category\",\n      \"severity\",\n      \"location\",\n      \"subject\",\n      \"details\",\n      \"mismatch\",\n      \"symbol\",\n    ],\n    properties: {\n      ...findingBaseProperties,\n      category: { type: \"string\", const: \"referenceMismatches\" },\n      mismatch: {\n        type: \"string\",\n        enum: [\"unknown-symbol\", \"signature-changed\"],\n      },\n      symbol: { type: \"string\" },\n    },\n  };\n\n  const linkFailureFindingSchema = {\n    type: \"object\",\n    required: [\n      \"category\",\n      \"severity\",\n      \"location\",\n      \"subject\",\n      \"details\",\n      \"url\",\n      \"kind\",\n      \"reason\",\n    ],\n    properties: {\n      ...findingBaseProperties,\n      category: { type: \"string\", const: \"linkFailures\" },\n      url: { type: \"string\" },\n      kind: { type: \"string\", enum: [\"internal\", \"external\"] },\n      reason: { type: \"string\" },\n    },\n  };\n\n  const sampleFailureFindingSchema = {\n    type: \"object\",\n    required: [\n      \"category\",\n      \"severity\",\n      \"location\",\n      \"subject\",\n      \"details\",\n      \"fenceIndex\",\n      \"lang\",\n      \"diagnostics\",\n    ],\n    properties: {\n      ...findingBaseProperties,\n      category: { type: \"string\", const: \"sampleFailures\" },\n      fenceIndex: { type: \"integer\", minimum: 0 },\n      lang: { type: \"string\" },\n      diagnostics: { type: \"array\", items: { type: \"string\" } },\n    },\n  };\n\n  return {\n    $schema: \"http://json-schema.org/draft-07/schema#\",\n    title: \"DocsSyncAuditReport\",\n    type: \"object\",\n    additionalProperties: false,\n    required: [\n      \"schemaVersion\",\n      \"issueNumber\",\n      \"mode\",\n      \"generatedAt\",\n      \"repoRoot\",\n      \"scope\",\n      \"categories\",\n      \"findings\",\n    ],\n    properties: {\n      schemaVersion: { type: \"integer\", const: DOCS_SYNC_AUDIT_SCHEMA_VERSION },\n      issueNumber: { type: \"integer\", minimum: 0 },\n      mode: { type: \"string\", enum: [\"pr\", \"audit\"] },\n      generatedAt: { type: \"string\", format: \"date-time\" },\n      repoRoot: { type: \"string\" },\n      scope: { type: \"string\" },\n      categories: {\n        type: \"object\",\n        additionalProperties: false,\n        required: [\n          \"apiDiff\",\n          \"tsdocCoverage\",\n          \"referenceMismatches\",\n          \"linkFailures\",\n          \"sampleFailures\",\n        ],\n        properties: {\n          apiDiff: { type: \"array\", items: apiDiffFindingSchema },\n          tsdocCoverage: { type: \"array\", items: tsdocCoverageFindingSchema },\n          referenceMismatches: {\n            type: \"array\",\n            items: referenceMismatchFindingSchema,\n          },\n          linkFailures: { type: \"array\", items: linkFailureFindingSchema },\n          sampleFailures: { type: \"array\", items: sampleFailureFindingSchema },\n        },\n      },\n      findings: {\n        type: \"array\",\n        items: {\n          oneOf: [\n            apiDiffFindingSchema,\n            tsdocCoverageFindingSchema,\n            referenceMismatchFindingSchema,\n            linkFailureFindingSchema,\n            sampleFailureFindingSchema,\n          ],\n        },\n      },\n    },\n  };\n}\n","import {\n  AuditCategory,\n  AuditFinding,\n  AuditSeverity,\n  ApiDiffFinding,\n} from \"../audit-report\";\nimport { AuditCheckRunner, AuditCheckRunnerContext } from \"../run-scan\";\n\n/**\n * One public export parsed out of an `.api.md` rollup. The signature\n * is the verbatim declaration text from the rollup (TypeScript\n * declaration form), with internal whitespace normalized to single\n * spaces so cosmetic re-formatting between runs does not surface as\n * a `changed` finding.\n */\nexport interface ApiSurfaceEntry {\n  /**\n   * Public name of the export (function name, class name, etc.).\n   */\n  readonly name: string;\n\n  /**\n   * Verbatim declaration line from the rollup with whitespace\n   * collapsed. Used as the equality comparison for `added` /\n   * `removed` / `changed` classification.\n   */\n  readonly signature: string;\n}\n\n/**\n * Result of diffing a baseline rollup against a current rollup. Each\n * field carries the API entries that fall into that change bucket.\n * Used by {@link createApiDiffCheck} to emit one finding per entry,\n * but exported separately so callers that want to render or\n * post-process the diff outside the audit-report shape can.\n */\nexport interface ApiDiffResult {\n  /** Exports present in the current rollup but not the baseline. */\n  readonly added: ReadonlyArray<ApiSurfaceEntry>;\n\n  /** Exports present in the baseline but not the current rollup. */\n  readonly removed: ReadonlyArray<ApiSurfaceEntry>;\n\n  /**\n   * Exports present in both rollups but whose declaration text\n   * differs (signature change, type-parameter change, etc.). The\n   * carried entry is the **current** rollup's view of the symbol so\n   * downstream consumers can show the new signature.\n   */\n  readonly changed: ReadonlyArray<ApiSurfaceEntry>;\n}\n\n/**\n * Options accepted by {@link createApiDiffCheck}. The runner\n * consumes already-fetched rollup contents — the orchestrator is\n * responsible for running the `extract-api.sh` helper against the\n * current ref and against the configured baseline ref before\n * dispatching to the runner. Passing the rollups in as strings keeps\n * tests cheap (inline fixtures) and lets the same runner shape\n * cover the audit-mode case where the baseline is an empty rollup\n * (every export shows up as `added`).\n */\nexport interface ApiDiffCheckOptions {\n  /**\n   * Verbatim contents of the `.api.md` rollup the orchestrator\n   * extracted against the **baseline** ref (typically `origin/main`\n   * for `pr` mode or empty for `audit` mode). May be the empty\n   * string when no baseline is available — every current export\n   * then surfaces as `added`.\n   */\n  readonly baselineRollup: string;\n\n  /**\n   * Verbatim contents of the `.api.md` rollup the orchestrator\n   * extracted against the **current** ref (the working tree the\n   * scan is running over).\n   */\n  readonly currentRollup: string;\n\n  /**\n   * Path attached to every finding's `location.file`. Conventionally\n   * the path to the `.api.md` file relative to the repo root (e.g.\n   * `packages/@codedrifters/configulator/.api-extractor/configulator.api.md`)\n   * so consumers can jump from a finding back to the source rollup.\n   * Defaults to the empty string, meaning the finding has no\n   * concrete file anchor.\n   *\n   * @default \"\"\n   */\n  readonly rollupPath?: string;\n\n  /**\n   * Stable name surfaced via {@link AuditCheckRunner.name}. Defaults\n   * to `\"apiDiff\"` so logs match the audit-report category key.\n   *\n   * @default \"apiDiff\"\n   */\n  readonly name?: string;\n}\n\n/**\n * Parse a `.api.md` rollup into the set of public-API entries it\n * declares. The parser is intentionally line-oriented and tolerant\n * of api-extractor's exact formatting:\n *\n * 1. Find the first fenced `ts` code block (api-extractor wraps the\n *    rollup in one). Lines outside the block are ignored.\n * 2. Walk the block linewise. Every line that begins with `export`\n *    is the start of a declaration; subsequent lines that do not\n *    begin with `export`, `//`, `}`, or `import` are appended until\n *    a terminator (`;`, top-level `}`) closes the declaration.\n * 3. Extract the public name from the start of the declaration —\n *    the first identifier after `export {function|class|interface|...}`\n *    (or the first name in an `export { A, B }` clause).\n * 4. Normalize whitespace inside the captured signature to a single\n *    space so re-flowing the rollup does not produce spurious\n *    `changed` findings.\n *\n * Lines containing only `// @public`, `// @beta`, etc. are stripped\n * — they are release-tag annotations the extractor emits, and they\n * change independently of the signature itself.\n */\nexport function parseApiRollup(rollup: string): ReadonlyArray<ApiSurfaceEntry> {\n  const fenceContents = extractFirstTsFence(rollup);\n  if (fenceContents === undefined) {\n    return [];\n  }\n\n  const lines = fenceContents.split(\"\\n\");\n  const entries: Array<ApiSurfaceEntry> = [];\n\n  let i = 0;\n  while (i < lines.length) {\n    const line = lines[i];\n    const trimmed = line.trim();\n    if (!trimmed.startsWith(\"export \")) {\n      i += 1;\n      continue;\n    }\n\n    // Capture this declaration. Multi-line declarations are joined\n    // with a single space so signature comparison is order-stable.\n    const startIndex = i;\n    let buffer = trimmed;\n    let braceDepth = countBraceDelta(trimmed);\n    let endsWithSemicolon = trimmed.endsWith(\";\");\n    i += 1;\n    while (\n      i < lines.length &&\n      !isComplete(buffer, braceDepth, endsWithSemicolon)\n    ) {\n      const next = lines[i];\n      const nextTrimmed = next.trim();\n      if (nextTrimmed.length === 0 || nextTrimmed.startsWith(\"//\")) {\n        i += 1;\n        continue;\n      }\n      buffer = `${buffer} ${nextTrimmed}`;\n      braceDepth += countBraceDelta(nextTrimmed);\n      endsWithSemicolon = nextTrimmed.endsWith(\";\");\n      i += 1;\n    }\n\n    const normalized = normalizeWhitespace(buffer);\n    const name = extractDeclarationName(normalized);\n    if (name) {\n      entries.push({ name, signature: normalized });\n    }\n\n    // Guard against an `export { … }` block that contains multiple\n    // names — split it into one entry per name.\n    if (name && normalized.startsWith(\"export {\")) {\n      const names = extractExportListNames(normalized);\n      if (names.length > 1) {\n        // Replace the single entry with one per name.\n        entries.pop();\n        for (const exportName of names) {\n          entries.push({ name: exportName, signature: normalized });\n        }\n      }\n    }\n\n    // Defensive: never fail to advance.\n    if (i === startIndex) {\n      i += 1;\n    }\n  }\n\n  // Deduplicate by name — api-extractor emits one declaration per\n  // public symbol, but in pathological inputs a name could repeat.\n  const dedup = new Map<string, ApiSurfaceEntry>();\n  for (const entry of entries) {\n    if (!dedup.has(entry.name)) {\n      dedup.set(entry.name, entry);\n    }\n  }\n  return Array.from(dedup.values()).sort((a, b) =>\n    a.name.localeCompare(b.name),\n  );\n}\n\n/**\n * Diff a baseline rollup against a current rollup and bucket every\n * public export into `added`, `removed`, or `changed`. Exported so\n * callers can compute the diff without going through the runner\n * shape.\n */\nexport function diffApiRollups(\n  baselineRollup: string,\n  currentRollup: string,\n): ApiDiffResult {\n  const baseline = new Map<string, ApiSurfaceEntry>();\n  for (const entry of parseApiRollup(baselineRollup)) {\n    baseline.set(entry.name, entry);\n  }\n  const current = new Map<string, ApiSurfaceEntry>();\n  for (const entry of parseApiRollup(currentRollup)) {\n    current.set(entry.name, entry);\n  }\n\n  const added: Array<ApiSurfaceEntry> = [];\n  const removed: Array<ApiSurfaceEntry> = [];\n  const changed: Array<ApiSurfaceEntry> = [];\n\n  for (const [name, entry] of current.entries()) {\n    const before = baseline.get(name);\n    if (!before) {\n      added.push(entry);\n      continue;\n    }\n    if (before.signature !== entry.signature) {\n      changed.push(entry);\n    }\n  }\n  for (const [name, entry] of baseline.entries()) {\n    if (!current.has(name)) {\n      removed.push(entry);\n    }\n  }\n\n  added.sort((a, b) => a.name.localeCompare(b.name));\n  removed.sort((a, b) => a.name.localeCompare(b.name));\n  changed.sort((a, b) => a.name.localeCompare(b.name));\n\n  return { added, removed, changed };\n}\n\n/**\n * Build an {@link AuditCheckRunner} that emits API-diff findings by\n * comparing a baseline rollup to a current rollup. Severity mapping\n * (per the parent epic's drift-handling matrix):\n *\n * - **added** — `mechanical`. A new public export is purely\n *   additive; Phase 2 can stub TSDoc and add reference-doc rows\n *   without human input.\n * - **removed** — `advisory`. A removed public export likely needs\n *   a deprecation note in prose; Phase 2 cannot mechanically rewrite\n *   conceptual prose.\n * - **changed** — `advisory`. A signature change may invalidate\n *   inline-code references in docs and warrants human review of any\n *   surrounding prose.\n */\nexport function createApiDiffCheck(\n  options: ApiDiffCheckOptions,\n): AuditCheckRunner {\n  const baseline = options.baselineRollup;\n  const current = options.currentRollup;\n  const rollupPath = options.rollupPath ?? \"\";\n  return {\n    name: options.name ?? \"apiDiff\",\n    run(_context: AuditCheckRunnerContext): ReadonlyArray<AuditFinding> {\n      const diff = diffApiRollups(baseline, current);\n      const findings: Array<ApiDiffFinding> = [];\n\n      for (const entry of diff.added) {\n        findings.push({\n          category: AuditCategory.ApiDiff,\n          severity: AuditSeverity.Mechanical,\n          location: { file: rollupPath, line: 0 },\n          subject: entry.name,\n          details: `New public export \\`${entry.name}\\` not present in baseline rollup.`,\n          change: \"added\",\n          symbol: entry.name,\n          fixHint: \"stub-tsdoc\",\n        });\n      }\n      for (const entry of diff.removed) {\n        findings.push({\n          category: AuditCategory.ApiDiff,\n          severity: AuditSeverity.Advisory,\n          location: { file: rollupPath, line: 0 },\n          subject: entry.name,\n          details: `Public export \\`${entry.name}\\` was present in baseline rollup but is gone in the current rollup.`,\n          change: \"removed\",\n          symbol: entry.name,\n        });\n      }\n      for (const entry of diff.changed) {\n        findings.push({\n          category: AuditCategory.ApiDiff,\n          severity: AuditSeverity.Advisory,\n          location: { file: rollupPath, line: 0 },\n          subject: entry.name,\n          details: `Public export \\`${entry.name}\\` signature changed since baseline rollup.`,\n          change: \"changed\",\n          symbol: entry.name,\n        });\n      }\n\n      return findings;\n    },\n  };\n}\n\nfunction extractFirstTsFence(rollup: string): string | undefined {\n  // Match the first ```ts ... ``` block. api-extractor always uses\n  // ```ts (not ```typescript) per its emitted format.\n  const lines = rollup.split(\"\\n\");\n  let start = -1;\n  for (let i = 0; i < lines.length; i++) {\n    const line = lines[i].trim();\n    if (line === \"```ts\" || line === \"```typescript\") {\n      start = i + 1;\n      break;\n    }\n  }\n  if (start < 0) {\n    return undefined;\n  }\n  for (let j = start; j < lines.length; j++) {\n    if (lines[j].trim() === \"```\") {\n      return lines.slice(start, j).join(\"\\n\");\n    }\n  }\n  // Unterminated fence — return everything after the opener.\n  return lines.slice(start).join(\"\\n\");\n}\n\nfunction countBraceDelta(line: string): number {\n  let delta = 0;\n  for (const ch of line) {\n    if (ch === \"{\") {\n      delta += 1;\n    } else if (ch === \"}\") {\n      delta -= 1;\n    }\n  }\n  return delta;\n}\n\nfunction isComplete(\n  buffer: string,\n  braceDepth: number,\n  endsWithSemicolon: boolean,\n): boolean {\n  // A declaration is complete when brace depth has returned to zero\n  // and we ended on a semicolon (function / variable signatures) or\n  // on a closing brace (interface / class / type bodies).\n  if (braceDepth > 0) {\n    return false;\n  }\n  if (endsWithSemicolon) {\n    return true;\n  }\n  return buffer.trimEnd().endsWith(\"}\");\n}\n\nfunction normalizeWhitespace(s: string): string {\n  // Collapse runs of whitespace to a single space, then strip\n  // spaces immediately inside parentheses, brackets, and braces\n  // and around commas / semicolons / colons. This is what makes\n  // the tight `(input: string)` and the loose `( input: string )`\n  // compare equal — the cosmetic re-flow produced by api-extractor\n  // when a signature wraps to multiple lines should not surface as\n  // a `changed` finding.\n  return s\n    .replace(/\\s+/g, \" \")\n    .replace(/\\(\\s+/g, \"(\")\n    .replace(/\\s+\\)/g, \")\")\n    .replace(/\\[\\s+/g, \"[\")\n    .replace(/\\s+\\]/g, \"]\")\n    .replace(/\\{\\s+/g, \"{\")\n    .replace(/\\s+\\}/g, \"}\")\n    .replace(/\\s+,/g, \",\")\n    .replace(/\\s+;/g, \";\")\n    .replace(/\\s+:/g, \":\")\n    .trim();\n}\n\nconst DECLARATION_KEYWORDS: ReadonlyArray<string> = [\n  \"function\",\n  \"class\",\n  \"interface\",\n  \"type\",\n  \"enum\",\n  \"const\",\n  \"let\",\n  \"var\",\n  \"namespace\",\n  \"abstract\",\n  \"default\",\n  \"async\",\n];\n\nfunction extractDeclarationName(declaration: string): string | undefined {\n  const tokens = declaration.split(/\\s+/);\n  if (tokens.length === 0 || tokens[0] !== \"export\") {\n    return undefined;\n  }\n  let cursor = 1;\n  while (\n    cursor < tokens.length &&\n    DECLARATION_KEYWORDS.includes(tokens[cursor])\n  ) {\n    cursor += 1;\n  }\n  if (cursor >= tokens.length) {\n    return undefined;\n  }\n  const candidate = tokens[cursor];\n  if (candidate.startsWith(\"{\")) {\n    // `export { Foo, Bar }`. Return the first name; the caller may\n    // expand the list separately when more than one is present.\n    const stripped = candidate.replace(/^\\{/, \"\").replace(/[},].*$/, \"\");\n    return stripped || undefined;\n  }\n  // Strip trailing punctuation that may attach to the name in\n  // function declarations (`fooApi(...): void;`).\n  const cleaned = candidate.replace(/[<(:;].*$/, \"\");\n  return cleaned || undefined;\n}\n\nfunction extractExportListNames(declaration: string): Array<string> {\n  // Captures the contents between `{` and the first `}` in an\n  // `export { A, B as C }` clause. Re-exports with `as` aliasing\n  // surface the alias as the public name.\n  const open = declaration.indexOf(\"{\");\n  const close = declaration.indexOf(\"}\", open);\n  if (open < 0 || close < 0) {\n    return [];\n  }\n  const inside = declaration.slice(open + 1, close);\n  const names: Array<string> = [];\n  for (const part of inside.split(\",\")) {\n    const token = part.trim();\n    if (!token) {\n      continue;\n    }\n    const asMatch = token.match(/\\sas\\s+(\\S+)$/);\n    if (asMatch) {\n      names.push(asMatch[1]);\n    } else {\n      names.push(token);\n    }\n  }\n  return names;\n}\n","import { DocReferenceRecord } from \"../../reference-extraction/extraction\";\nimport {\n  AuditCategory,\n  AuditFinding,\n  AuditSeverity,\n  ReferenceMismatchFinding,\n} from \"../audit-report\";\nimport { AuditCheckRunner, AuditCheckRunnerContext } from \"../run-scan\";\n\n/**\n * Options accepted by {@link createReferenceMismatchCheck}.\n *\n * The runner consumes already-computed reference records produced by\n * `extractDocReferences()`. The factory deliberately does not invoke\n * the extractor — that keeps the runner cheap to test with inline\n * fixtures and lets the orchestrator extract references once and\n * feed multiple checks from the same input.\n */\nexport interface ReferenceMismatchCheckOptions {\n  /**\n   * The reference records to translate into findings. Each record\n   * carries the `isKnown` flag the extractor computed against the\n   * supplied known-symbols set; the runner produces a finding for\n   * every record where `isKnown` is `false`.\n   */\n  readonly records: ReadonlyArray<DocReferenceRecord>;\n\n  /**\n   * Stable name surfaced via {@link AuditCheckRunner.name}. Defaults\n   * to `\"referenceMismatches\"` so logs match the audit-report\n   * category key.\n   *\n   * @default \"referenceMismatches\"\n   */\n  readonly name?: string;\n\n  /**\n   * Optional set of symbols whose signature changed between the\n   * baseline and the current revision. References to one of these\n   * symbols produce a `signature-changed` finding rather than the\n   * default `unknown-symbol` finding (the symbol resolves but its\n   * type signature differs from the cached snapshot, per the\n   * audit-report schema). Empty / omitted means no signature-change\n   * findings are produced.\n   */\n  readonly signatureChangedSymbols?: ReadonlyArray<string>;\n}\n\n/**\n * Map a single {@link DocReferenceRecord} to zero or one audit\n * findings. Exported so callers can reuse the record-to-finding\n * mapping without going through a runner.\n *\n * Severity mapping:\n *\n * - `unknown-symbol` (record carries `isKnown: false`) — `advisory`.\n *   The doc mentions a symbol that does not appear in the supplied\n *   known-symbols set; a human reviewer should rename the mention or\n *   remove it. The matching `signature-changed` case only fires when\n *   the caller passes the symbol via `signatureChangedSymbols`.\n * - Records with `isKnown: true` and no signature change produce no\n *   findings.\n */\nexport function referenceRecordToFinding(\n  record: DocReferenceRecord,\n  signatureChangedSymbols: ReadonlySet<string>,\n): ReferenceMismatchFinding | undefined {\n  if (signatureChangedSymbols.has(record.symbol)) {\n    return {\n      category: AuditCategory.ReferenceMismatches,\n      severity: AuditSeverity.Advisory,\n      location: { file: record.docPath, line: record.line },\n      subject: record.symbol,\n      details: `Inline reference \\`${record.symbol}\\` resolves to a symbol whose signature has changed; review the surrounding prose.`,\n      mismatch: \"signature-changed\",\n      symbol: record.symbol,\n    };\n  }\n  if (!record.isKnown) {\n    return {\n      category: AuditCategory.ReferenceMismatches,\n      severity: AuditSeverity.Advisory,\n      location: { file: record.docPath, line: record.line },\n      subject: record.symbol,\n      details: `Inline reference \\`${record.symbol}\\` does not match any known public export.`,\n      mismatch: \"unknown-symbol\",\n      symbol: record.symbol,\n    };\n  }\n  return undefined;\n}\n\n/**\n * Build an {@link AuditCheckRunner} that emits doc-reference\n * mismatch findings from a precomputed list of\n * {@link DocReferenceRecord}. The runner is synchronous and\n * idempotent — calling `run()` twice produces identical findings.\n */\nexport function createReferenceMismatchCheck(\n  options: ReferenceMismatchCheckOptions,\n): AuditCheckRunner {\n  const records = options.records;\n  const signatureChangedSymbols = new Set(\n    options.signatureChangedSymbols ?? [],\n  );\n  return {\n    name: options.name ?? \"referenceMismatches\",\n    run(_context: AuditCheckRunnerContext): ReadonlyArray<AuditFinding> {\n      const findings: Array<ReferenceMismatchFinding> = [];\n      for (const record of records) {\n        const finding = referenceRecordToFinding(\n          record,\n          signatureChangedSymbols,\n        );\n        if (finding !== undefined) {\n          findings.push(finding);\n        }\n      }\n      return findings;\n    },\n  };\n}\n","import * as path from \"node:path\";\nimport { TsDocCoverageRecord } from \"../../tsdoc-coverage/coverage\";\nimport {\n  AuditCategory,\n  AuditFinding,\n  AuditSeverity,\n  TsdocCoverageFinding,\n} from \"../audit-report\";\nimport { AuditCheckRunner, AuditCheckRunnerContext } from \"../run-scan\";\n\n/**\n * Options accepted by {@link createTsdocCoverageCheck}.\n *\n * The runner consumes already-computed coverage records produced by\n * `analyzeTsDocCoverage()`. The factory deliberately does not invoke\n * the analyzer itself — that keeps the runner cheap to test (pass an\n * inline records array) and keeps the orchestrator free to compute\n * coverage once and feed multiple checks from the same input.\n */\nexport interface TsdocCoverageCheckOptions {\n  /**\n   * The coverage records to translate into findings. Typically the\n   * concatenated output of `analyzeTsDocCoverage()` for every public\n   * package the orchestrator is scanning. The factory may be called\n   * with an empty array when no public exports were inspected — the\n   * resulting runner produces no findings.\n   */\n  readonly records: ReadonlyArray<TsDocCoverageRecord>;\n\n  /**\n   * Stable name surfaced via {@link AuditCheckRunner.name}. Defaults\n   * to `\"tsdocCoverage\"` so logs match the audit-report category key.\n   *\n   * @default \"tsdocCoverage\"\n   */\n  readonly name?: string;\n}\n\n/**\n * Map a single {@link TsDocCoverageRecord} to zero, one, or more\n * audit findings. Exported so callers can reuse the\n * record-to-finding mapping without going through a runner (e.g. the\n * audit-mode walker in #526 may compose findings differently).\n *\n * Severity mapping (per the parent epic's drift-handling matrix):\n *\n * - `missing-summary` — `mechanical` (Phase 2 can auto-stub).\n * - `thin-summary` — `advisory` (a human should rewrite).\n * - `missing-params` / `missing-returns` — `advisory` (the symbol\n *   does carry a summary; the missing block tag is signal but does\n *   not block).\n *\n * A record with `hasSummary && !hasThinSummary` and no missing block\n * tags produces no findings — fully-documented exports are reported\n * by their absence in the result.\n */\nexport function tsdocRecordToFindings(\n  record: TsDocCoverageRecord,\n  context: AuditCheckRunnerContext,\n): Array<TsdocCoverageFinding> {\n  const findings: Array<TsdocCoverageFinding> = [];\n  const file = relativizeFile(record.location.file, context.repoRoot);\n  const line = record.location.line;\n  const symbol = record.symbol;\n\n  if (!record.hasSummary) {\n    findings.push({\n      category: AuditCategory.TsdocCoverage,\n      severity: AuditSeverity.Mechanical,\n      location: { file, line },\n      subject: symbol,\n      details: `Public export \\`${symbol}\\` is missing a TSDoc summary.`,\n      shortfall: \"missing-summary\",\n      symbol,\n      fixHint: \"stub-tsdoc\",\n    });\n    // When the summary is missing entirely the missing-params /\n    // missing-returns shortfalls are subsumed — the stub Phase 2\n    // emits will scaffold the block tags too. Skip the noise.\n    return findings;\n  }\n\n  if (record.hasThinSummary) {\n    findings.push({\n      category: AuditCategory.TsdocCoverage,\n      severity: AuditSeverity.Advisory,\n      location: { file, line },\n      subject: symbol,\n      details: `Public export \\`${symbol}\\` carries a thin TSDoc summary; consider expanding it.`,\n      shortfall: \"thin-summary\",\n      symbol,\n    });\n  }\n\n  // Only flag missing block tags on kinds that can carry them. The\n  // coverage utility already returns `false` for kinds without\n  // params or returns (TypeAlias, Variable, etc.) so this logic\n  // collapses naturally.\n  if (!record.hasParams && isParamCarryingKind(record)) {\n    findings.push({\n      category: AuditCategory.TsdocCoverage,\n      severity: AuditSeverity.Advisory,\n      location: { file, line },\n      subject: symbol,\n      details: `Public export \\`${symbol}\\` has parameters with no \\`@param\\` block tag.`,\n      shortfall: \"missing-params\",\n      symbol,\n    });\n  }\n\n  if (!record.hasReturns && isReturnCarryingKind(record)) {\n    findings.push({\n      category: AuditCategory.TsdocCoverage,\n      severity: AuditSeverity.Advisory,\n      location: { file, line },\n      subject: symbol,\n      details: `Public export \\`${symbol}\\` has a return value with no \\`@returns\\` block tag.`,\n      shortfall: \"missing-returns\",\n      symbol,\n    });\n  }\n\n  return findings;\n}\n\n/**\n * Build an {@link AuditCheckRunner} that emits TSDoc-coverage\n * findings from a precomputed list of {@link TsDocCoverageRecord}.\n * The runner is synchronous and idempotent; calling `run()` twice\n * produces identical findings.\n */\nexport function createTsdocCoverageCheck(\n  options: TsdocCoverageCheckOptions,\n): AuditCheckRunner {\n  const records = options.records;\n  return {\n    name: options.name ?? \"tsdocCoverage\",\n    run(context: AuditCheckRunnerContext): ReadonlyArray<AuditFinding> {\n      const findings: Array<TsdocCoverageFinding> = [];\n      for (const record of records) {\n        for (const finding of tsdocRecordToFindings(record, context)) {\n          findings.push(finding);\n        }\n      }\n      return findings;\n    },\n  };\n}\n\n/**\n * Compiler kinds that carry a parameter list. `Function` covers\n * function and method declarations; classes carry constructors but\n * the coverage utility already records the class itself, so we\n * intentionally do not request `@param` on class declarations here.\n */\nfunction isParamCarryingKind(record: TsDocCoverageRecord): boolean {\n  return record.kind === \"Function\";\n}\n\n/**\n * Compiler kinds that carry a return value worth documenting. Same\n * scope as {@link isParamCarryingKind} — `Function` only.\n */\nfunction isReturnCarryingKind(record: TsDocCoverageRecord): boolean {\n  return record.kind === \"Function\";\n}\n\nfunction relativizeFile(file: string, repoRoot: string): string {\n  if (!file) {\n    return \"\";\n  }\n  if (!path.isAbsolute(file)) {\n    return toPosix(file);\n  }\n  const rel = path.relative(repoRoot, file);\n  return toPosix(rel);\n}\n\nfunction toPosix(p: string): string {\n  return p.split(path.sep).join(\"/\");\n}\n","import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport {\n  AuditCategory,\n  AuditFinding,\n  AuditMode,\n  AuditReport,\n  AuditSeverity,\n  DOCS_SYNC_AUDIT_SCHEMA_VERSION,\n} from \"./audit-report\";\n\n/**\n * Default subdirectory beneath the repo root where audit reports are\n * persisted. Mirrors the path declared on issue #518's acceptance\n * criteria: `.state/docs-sync/<N>-audit.json`.\n */\nexport const DEFAULT_AUDIT_REPORT_DIR = \".state/docs-sync\";\n\n/**\n * Severity-ordering rank used when sorting the flat `findings`\n * array. Lower number = higher rank in the report. Keeps blocking\n * issues at the top so consumers reading the array top-to-bottom\n * see the merge-blocking findings first.\n */\nconst SEVERITY_RANK: Record<AuditSeverity, number> = {\n  blocking: 0,\n  advisory: 1,\n  mechanical: 2,\n};\n\n/**\n * Stable iteration order for category keys. Matches the order they\n * appear in the persisted report and the order they ran during the\n * scan (API surface diff first, then TSDoc, then references, then\n * the docs-only checks). The order is part of the contract — a\n * consumer that walks `Object.keys(report.categories)` sees this\n * order on every read.\n */\nexport const AUDIT_CATEGORY_ORDER: ReadonlyArray<AuditCategory> = [\n  AuditCategory.ApiDiff,\n  AuditCategory.TsdocCoverage,\n  AuditCategory.ReferenceMismatches,\n  AuditCategory.LinkFailures,\n  AuditCategory.SampleFailures,\n];\n\n/**\n * One drift-check runner. The scan orchestrator invokes each\n * runner in registration order, collects the findings, and merges\n * them into the persisted report. Runners are intentionally\n * synchronous to keep the scaffold simple — children #519 and\n * #520 may introduce async runners by adding a parallel\n * `AsyncAuditCheckRunner` shape if needed.\n *\n * Runners are pure functions: given the same context they should\n * produce the same finding list. The scan orchestrator does not\n * sandbox them — a runner that mutates the filesystem or shells\n * out is on its own honor.\n */\nexport interface AuditCheckRunner {\n  /**\n   * Stable name used in diagnostics and logs. Conventionally\n   * matches the category the runner produces findings in (e.g.\n   * `apiDiff`, `tsdocCoverage`).\n   */\n  readonly name: string;\n\n  /**\n   * Compute the findings for this check. Runners must return\n   * already-validated finding records — the orchestrator does not\n   * post-process category, severity, or location.\n   */\n  run(context: AuditCheckRunnerContext): ReadonlyArray<AuditFinding>;\n}\n\n/**\n * Context passed to every check runner. Carries the same fields\n * the orchestrator needs to populate the report header so runners\n * can consult them when computing their findings (e.g. resolve\n * relative paths against `repoRoot`).\n */\nexport interface AuditCheckRunnerContext {\n  readonly repoRoot: string;\n  readonly mode: AuditMode;\n  readonly scope: string;\n  readonly issueNumber: number;\n}\n\n/**\n * Options accepted by {@link runScan}.\n */\nexport interface RunScanOptions {\n  /**\n   * Absolute path to the repository root the scan runs against.\n   * The audit report's `repoRoot` field is set to this value\n   * verbatim — pass an absolute path so consumers reading the\n   * report on a different checkout can rewrite paths reliably.\n   */\n  readonly repoRoot: string;\n\n  /**\n   * Tracking-issue number the scan ran for. Determines the\n   * persisted filename (`<issueNumber>-audit.json`).\n   */\n  readonly issueNumber: number;\n\n  /**\n   * Invocation mode — `pr` for diff-scoped runs, `audit` for\n   * full-repo runs.\n   */\n  readonly mode: AuditMode;\n\n  /**\n   * Optional free-form scope label. Persisted on the report and\n   * forwarded to every runner. Defaults to the empty string.\n   */\n  readonly scope?: string;\n\n  /**\n   * Drift-check runners to invoke in order. Empty by default —\n   * #518 ships the orchestrator skeleton without any wired\n   * checks; #519 and #520 plug them in.\n   */\n  readonly checks?: ReadonlyArray<AuditCheckRunner>;\n\n  /**\n   * Override the timestamp embedded on the report. Used in tests\n   * to make output deterministic. Defaults to `new Date()` at\n   * scan start.\n   */\n  readonly now?: Date;\n\n  /**\n   * When `true`, persist the report to disk under\n   * `<repoRoot>/<reportDir>/<issueNumber>-audit.json`. When\n   * `false` (the default), the report is returned in memory only.\n   *\n   * @default false\n   */\n  readonly persist?: boolean;\n\n  /**\n   * Override the directory the report is written to (relative to\n   * {@link RunScanOptions.repoRoot}). Defaults to\n   * {@link DEFAULT_AUDIT_REPORT_DIR}.\n   *\n   * @default \".state/docs-sync\"\n   */\n  readonly reportDir?: string;\n}\n\n/**\n * Result returned by {@link runScan}. Always carries the report;\n * `reportPath` is non-empty only when persistence was requested.\n */\nexport interface RunScanResult {\n  /**\n   * The report produced by the scan. Schema-compliant whether or\n   * not any checks ran — empty `categories` arrays are persisted\n   * explicitly.\n   */\n  readonly report: AuditReport;\n\n  /**\n   * Absolute path the report was persisted to. Empty string when\n   * `persist` was `false`.\n   */\n  readonly reportPath: string;\n}\n\n/**\n * Run the docs-sync scan phase. Invokes every registered check\n * runner in order, merges the findings into a single\n * schema-compliant {@link AuditReport}, and optionally persists\n * the report to `<repoRoot>/<reportDir>/<issueNumber>-audit.json`.\n *\n * #518 ships this function with an **empty default check list**:\n * invoking `runScan({ repoRoot, issueNumber, mode: \"pr\" })`\n * produces a report whose `findings` and per-category arrays are\n * all empty. Children #519 and #520 register the real checks by\n * passing them via the `checks` option.\n */\nexport function runScan(options: RunScanOptions): RunScanResult {\n  const repoRoot = path.resolve(options.repoRoot);\n  const mode = options.mode;\n  const scope = options.scope ?? \"\";\n  const issueNumber = options.issueNumber;\n  const checks = options.checks ?? [];\n  const now = options.now ?? new Date();\n  const persist = options.persist ?? false;\n  const reportDir = options.reportDir ?? DEFAULT_AUDIT_REPORT_DIR;\n\n  const context: AuditCheckRunnerContext = {\n    repoRoot,\n    mode,\n    scope,\n    issueNumber,\n  };\n\n  const collected: Array<AuditFinding> = [];\n  for (const check of checks) {\n    const result = check.run(context);\n    for (const finding of result) {\n      collected.push(finding);\n    }\n  }\n\n  const report = buildReport({\n    issueNumber,\n    mode,\n    scope,\n    repoRoot,\n    generatedAt: now,\n    findings: collected,\n  });\n\n  let reportPath = \"\";\n  if (persist) {\n    reportPath = persistAuditReport({\n      report,\n      repoRoot,\n      reportDir,\n    });\n  }\n\n  return { report, reportPath };\n}\n\n/**\n * Compute the final {@link AuditReport} from a flat list of\n * findings. Group by category, sort each bucket deterministically,\n * and produce the flat `findings` aggregation in the documented\n * order. Exported so #519 / #520 can build reports incrementally\n * without re-running the whole scan.\n */\nexport function buildReport(args: {\n  readonly issueNumber: number;\n  readonly mode: AuditMode;\n  readonly scope: string;\n  readonly repoRoot: string;\n  readonly generatedAt: Date;\n  readonly findings: ReadonlyArray<AuditFinding>;\n}): AuditReport {\n  const buckets = emptyCategoryBuckets();\n  for (const finding of args.findings) {\n    pushIntoBucket(buckets, finding);\n  }\n\n  buckets.apiDiff.sort(compareFindings);\n  buckets.tsdocCoverage.sort(compareFindings);\n  buckets.referenceMismatches.sort(compareFindings);\n  buckets.linkFailures.sort(compareFindings);\n  buckets.sampleFailures.sort(compareFindings);\n\n  const flat: Array<AuditFinding> = [];\n  for (const key of AUDIT_CATEGORY_ORDER) {\n    const bucket = buckets[key] as ReadonlyArray<AuditFinding>;\n    for (const finding of bucket) {\n      flat.push(finding);\n    }\n  }\n  flat.sort(compareFindings);\n\n  return {\n    schemaVersion: DOCS_SYNC_AUDIT_SCHEMA_VERSION,\n    issueNumber: args.issueNumber,\n    mode: args.mode,\n    generatedAt: args.generatedAt.toISOString(),\n    repoRoot: args.repoRoot,\n    scope: args.scope,\n    categories: {\n      apiDiff: buckets.apiDiff,\n      tsdocCoverage: buckets.tsdocCoverage,\n      referenceMismatches: buckets.referenceMismatches,\n      linkFailures: buckets.linkFailures,\n      sampleFailures: buckets.sampleFailures,\n    },\n    findings: flat,\n  };\n}\n\n/**\n * Persist an {@link AuditReport} to disk. The directory is created\n * recursively when missing; the file is written atomically via a\n * temp-file + rename so a partial write never produces a corrupt\n * report.\n */\nexport function persistAuditReport(args: {\n  readonly report: AuditReport;\n  readonly repoRoot: string;\n  readonly reportDir?: string;\n}): string {\n  const repoRoot = path.resolve(args.repoRoot);\n  const reportDir = args.reportDir ?? DEFAULT_AUDIT_REPORT_DIR;\n  const targetDir = path.resolve(repoRoot, reportDir);\n  fs.mkdirSync(targetDir, { recursive: true });\n\n  const targetFile = path.join(\n    targetDir,\n    `${args.report.issueNumber}-audit.json`,\n  );\n  const tempFile = `${targetFile}.tmp-${process.pid}-${Date.now()}`;\n\n  const serialized = `${JSON.stringify(args.report, null, 2)}\\n`;\n  fs.writeFileSync(tempFile, serialized, \"utf-8\");\n  fs.renameSync(tempFile, targetFile);\n  return targetFile;\n}\n\n/**\n * Build an empty {@link AuditReport.categories} record with every\n * key explicitly set to an empty array. Exported so callers that\n * stub the report shape in tests don't have to repeat the keys.\n */\nexport function emptyCategoryBuckets(): {\n  apiDiff: Array<AuditFinding & { category: typeof AuditCategory.ApiDiff }>;\n  tsdocCoverage: Array<\n    AuditFinding & { category: typeof AuditCategory.TsdocCoverage }\n  >;\n  referenceMismatches: Array<\n    AuditFinding & { category: typeof AuditCategory.ReferenceMismatches }\n  >;\n  linkFailures: Array<\n    AuditFinding & { category: typeof AuditCategory.LinkFailures }\n  >;\n  sampleFailures: Array<\n    AuditFinding & { category: typeof AuditCategory.SampleFailures }\n  >;\n} {\n  return {\n    apiDiff: [],\n    tsdocCoverage: [],\n    referenceMismatches: [],\n    linkFailures: [],\n    sampleFailures: [],\n  };\n}\n\nfunction pushIntoBucket(\n  buckets: ReturnType<typeof emptyCategoryBuckets>,\n  finding: AuditFinding,\n): void {\n  switch (finding.category) {\n    case AuditCategory.ApiDiff:\n      buckets.apiDiff.push(finding);\n      return;\n    case AuditCategory.TsdocCoverage:\n      buckets.tsdocCoverage.push(finding);\n      return;\n    case AuditCategory.ReferenceMismatches:\n      buckets.referenceMismatches.push(finding);\n      return;\n    case AuditCategory.LinkFailures:\n      buckets.linkFailures.push(finding);\n      return;\n    case AuditCategory.SampleFailures:\n      buckets.sampleFailures.push(finding);\n      return;\n    default: {\n      // Exhaustiveness guard — typed against the discriminated\n      // union; an unhandled category is a programming error\n      // surfaced as a thrown exception rather than silent drop.\n      const exhaustive: never = finding;\n      throw new Error(\n        `runScan: unrecognized finding category: ${JSON.stringify(exhaustive)}`,\n      );\n    }\n  }\n}\n\nfunction compareFindings(a: AuditFinding, b: AuditFinding): number {\n  // Severity first so consumers walking the flat findings array\n  // top-to-bottom see merge-blocking findings before advisories\n  // and mechanical fixes. Category, file, line, and subject act\n  // as deterministic tie-breakers.\n  const sevDelta = SEVERITY_RANK[a.severity] - SEVERITY_RANK[b.severity];\n  if (sevDelta !== 0) {\n    return sevDelta;\n  }\n  if (a.category !== b.category) {\n    return a.category.localeCompare(b.category);\n  }\n  if (a.location.file !== b.location.file) {\n    return a.location.file.localeCompare(b.location.file);\n  }\n  if (a.location.line !== b.location.line) {\n    return a.location.line - b.location.line;\n  }\n  return a.subject.localeCompare(b.subject);\n}\n","import * as path from \"node:path\";\nimport { TSDocParser, DocComment } from \"@microsoft/tsdoc\";\nimport * as ts from \"typescript\";\n\n/**\n * One row in the TSDoc-coverage report — describes a single public\n * symbol exported (transitively) from the package's entry point and\n * the TSDoc presence flags computed for it.\n */\nexport interface TsDocCoverageRecord {\n  /**\n   * The public name of the symbol as it is exported from the package\n   * entry point (post-rename for `export { X as Y }` re-exports).\n   */\n  readonly symbol: string;\n\n  /**\n   * Compiler kind label for the declaration backing the symbol — one\n   * of `Class`, `Interface`, `TypeAlias`, `Enum`, `Function`,\n   * `Variable`, `Module`, `Default`, or `Other`. Useful for grouping\n   * findings in the audit report.\n   */\n  readonly kind: TsDocCoverageKind;\n\n  /**\n   * Source location of the underlying declaration (1-indexed line\n   * number, file path absolute on disk).\n   */\n  readonly location: { readonly file: string; readonly line: number };\n\n  /**\n   * `true` when the declaration carries a TSDoc block whose\n   * `summarySection` is non-empty (i.e. there is at least one\n   * paragraph of summary prose).\n   */\n  readonly hasSummary: boolean;\n\n  /**\n   * `true` when the declaration carries a summary that exists but is\n   * shorter than the configured `thinSummaryWordThreshold` — useful\n   * for advisory-level findings that do not block.\n   */\n  readonly hasThinSummary: boolean;\n\n  /**\n   * `true` when the declaration carries at least one `@param` block\n   * tag. Always `false` for kinds that have no parameters\n   * (`Variable`, `TypeAlias`, etc.).\n   */\n  readonly hasParams: boolean;\n\n  /**\n   * `true` when the declaration carries a `@returns` block tag.\n   * Always `false` for kinds without a return value.\n   */\n  readonly hasReturns: boolean;\n}\n\n/**\n * Compiler-kind label attached to each coverage record.\n */\nexport const TsDocCoverageKind = {\n  Class: \"Class\",\n  Interface: \"Interface\",\n  TypeAlias: \"TypeAlias\",\n  Enum: \"Enum\",\n  Function: \"Function\",\n  Variable: \"Variable\",\n  Module: \"Module\",\n  Default: \"Default\",\n  Other: \"Other\",\n} as const;\n\n/**\n * String-literal type matching the values of {@link TsDocCoverageKind}.\n */\nexport type TsDocCoverageKind =\n  (typeof TsDocCoverageKind)[keyof typeof TsDocCoverageKind];\n\n/**\n * Options accepted by `analyzeTsDocCoverage`.\n */\nexport interface AnalyzeTsDocCoverageOptions {\n  /**\n   * Absolute path to the package root (the directory that contains\n   * `tsconfig.json` and `src/`).\n   */\n  readonly packageRoot: string;\n\n  /**\n   * Entry point relative to `packageRoot`. Defaults to\n   * `src/index.ts` — the convention used by every package in the\n   * monorepo.\n   *\n   * @default \"src/index.ts\"\n   */\n  readonly entryPoint?: string;\n\n  /**\n   * Word threshold below which a TSDoc summary is flagged as\n   * \"thin\" (advisory only — does not zero-out `hasSummary`). A\n   * summary with exactly this many words is considered thin.\n   *\n   * @default 4\n   */\n  readonly thinSummaryWordThreshold?: number;\n\n  /**\n   * Optional explicit path to a `tsconfig.json`. When omitted, the\n   * utility runs with a built-in compiler-options set tailored for\n   * AST analysis (no emit, ESNext target, NodeNext module\n   * resolution). The built-in options are sufficient for every\n   * coverage scan in the docs-sync pipeline; consumers only set\n   * this when their package uses an unusual module-resolution\n   * strategy that affects symbol resolution.\n   */\n  readonly tsconfigPath?: string;\n}\n\nconst DEFAULT_THIN_SUMMARY_WORD_THRESHOLD = 4;\nconst DEFAULT_ENTRY_POINT = \"src/index.ts\";\n\n/**\n * Walks a package's public exports, transitively resolving\n * `export *` and `export { X } from \"...\"` re-exports through the\n * TypeScript compiler API, and reports TSDoc presence flags for\n * every public symbol.\n *\n * Internal symbols (anything not transitively re-exported from\n * `entryPoint`) never appear in the result — the report describes\n * the package's *public surface area*, not its internal modules.\n *\n * @param options - Either an options object or, as a shorthand, the\n *                  absolute path to the package root.\n */\nexport function analyzeTsDocCoverage(\n  options: AnalyzeTsDocCoverageOptions | string,\n): Array<TsDocCoverageRecord> {\n  const resolvedOptions: AnalyzeTsDocCoverageOptions =\n    typeof options === \"string\" ? { packageRoot: options } : options;\n\n  const packageRoot = path.resolve(resolvedOptions.packageRoot);\n  const entryPoint = path.resolve(\n    packageRoot,\n    resolvedOptions.entryPoint ?? DEFAULT_ENTRY_POINT,\n  );\n  const thinThreshold =\n    resolvedOptions.thinSummaryWordThreshold ??\n    DEFAULT_THIN_SUMMARY_WORD_THRESHOLD;\n\n  const compilerOptions = resolveCompilerOptions(\n    packageRoot,\n    resolvedOptions.tsconfigPath,\n  );\n\n  const program = ts.createProgram({\n    rootNames: [entryPoint],\n    options: compilerOptions,\n  });\n  const checker = program.getTypeChecker();\n\n  const entrySource = program.getSourceFile(entryPoint);\n  if (!entrySource) {\n    throw new Error(\n      `analyzeTsDocCoverage: entry point not found in program: ${entryPoint}`,\n    );\n  }\n\n  const moduleSymbol = checker.getSymbolAtLocation(entrySource);\n  if (!moduleSymbol) {\n    // No module symbol means the entry file declared no exports.\n    return [];\n  }\n\n  const tsdocParser = new TSDocParser();\n  const records: Array<TsDocCoverageRecord> = [];\n\n  for (const exportSymbol of checker.getExportsOfModule(moduleSymbol)) {\n    const resolved = resolveAlias(exportSymbol, checker);\n    const declaration = pickPrimaryDeclaration(resolved);\n    if (!declaration) {\n      continue;\n    }\n\n    const kind = classifyDeclaration(declaration);\n    const location = resolveLocation(declaration);\n    const tsdoc = parseTsDocFor(declaration, tsdocParser);\n    const summaryWordCount = tsdoc ? countSummaryWords(tsdoc) : 0;\n\n    const hasSummary = summaryWordCount > 0;\n    const hasThinSummary = hasSummary && summaryWordCount <= thinThreshold;\n    const hasParams = tsdoc ? hasBlockTag(tsdoc, \"@param\") : false;\n    const hasReturns = tsdoc\n      ? hasBlockTag(tsdoc, \"@returns\") || hasBlockTag(tsdoc, \"@return\")\n      : false;\n\n    records.push({\n      symbol: exportSymbol.getName(),\n      kind,\n      location,\n      hasSummary,\n      hasThinSummary,\n      hasParams,\n      hasReturns,\n    });\n  }\n\n  // Sort by file then line so the report is deterministic across runs.\n  records.sort((a, b) => {\n    if (a.location.file !== b.location.file) {\n      return a.location.file.localeCompare(b.location.file);\n    }\n    if (a.location.line !== b.location.line) {\n      return a.location.line - b.location.line;\n    }\n    return a.symbol.localeCompare(b.symbol);\n  });\n\n  return records;\n}\n\nfunction resolveCompilerOptions(\n  packageRoot: string,\n  tsconfigPath: string | undefined,\n): ts.CompilerOptions {\n  if (tsconfigPath) {\n    const absoluteTsconfig = path.resolve(packageRoot, tsconfigPath);\n    const configFile = ts.readConfigFile(absoluteTsconfig, ts.sys.readFile);\n    if (configFile.error) {\n      throw new Error(\n        `analyzeTsDocCoverage: failed to read tsconfig at ${absoluteTsconfig}: ${ts.flattenDiagnosticMessageText(configFile.error.messageText, \"\\n\")}`,\n      );\n    }\n    const parsed = ts.parseJsonConfigFileContent(\n      configFile.config,\n      ts.sys,\n      path.dirname(absoluteTsconfig),\n    );\n    return { ...parsed.options, noEmit: true };\n  }\n\n  return {\n    target: ts.ScriptTarget.ESNext,\n    module: ts.ModuleKind.NodeNext,\n    moduleResolution: ts.ModuleResolutionKind.NodeNext,\n    allowJs: false,\n    declaration: false,\n    noEmit: true,\n    skipLibCheck: true,\n    strict: false,\n    esModuleInterop: true,\n    resolveJsonModule: true,\n  };\n}\n\nfunction resolveAlias(symbol: ts.Symbol, checker: ts.TypeChecker): ts.Symbol {\n  // `ts.SymbolFlags.Alias` covers `export { X } from`, `export * as ns`,\n  // and `import` re-export chains. Walk the alias chain to the underlying\n  // declaration so we read TSDoc from the original symbol, not the alias.\n  let current = symbol;\n  // Bound the loop to avoid pathological cycles in malformed graphs.\n  for (let i = 0; i < 32; i++) {\n    if (!isAlias(current)) {\n      return current;\n    }\n    const next = checker.getAliasedSymbol(current);\n    if (!next || next === current) {\n      return current;\n    }\n    current = next;\n  }\n  return current;\n}\n\nfunction isAlias(symbol: ts.Symbol): boolean {\n  // ts.SymbolFlags is a bit-field. The lint config bans bitwise\n  // operators, so encapsulate the single bit-test in a tiny helper\n  // and disable the rule for this one expression.\n  // eslint-disable-next-line no-bitwise\n  return (symbol.flags & ts.SymbolFlags.Alias) !== 0;\n}\n\nfunction pickPrimaryDeclaration(symbol: ts.Symbol): ts.Declaration | undefined {\n  const declarations = symbol.getDeclarations();\n  if (!declarations || declarations.length === 0) {\n    return undefined;\n  }\n  // Prefer a declaration that is not just a re-export specifier — those\n  // carry no TSDoc themselves; the underlying class/function does.\n  const concrete = declarations.find(\n    (d) =>\n      !ts.isExportSpecifier(d) &&\n      !ts.isExportAssignment(d) &&\n      !ts.isExportDeclaration(d),\n  );\n  return concrete ?? declarations[0];\n}\n\nfunction classifyDeclaration(declaration: ts.Declaration): TsDocCoverageKind {\n  if (ts.isClassDeclaration(declaration)) {\n    return TsDocCoverageKind.Class;\n  }\n  if (ts.isInterfaceDeclaration(declaration)) {\n    return TsDocCoverageKind.Interface;\n  }\n  if (ts.isTypeAliasDeclaration(declaration)) {\n    return TsDocCoverageKind.TypeAlias;\n  }\n  if (ts.isEnumDeclaration(declaration)) {\n    return TsDocCoverageKind.Enum;\n  }\n  if (\n    ts.isFunctionDeclaration(declaration) ||\n    ts.isMethodDeclaration(declaration)\n  ) {\n    return TsDocCoverageKind.Function;\n  }\n  if (\n    ts.isVariableDeclaration(declaration) ||\n    ts.isVariableStatement(declaration)\n  ) {\n    return TsDocCoverageKind.Variable;\n  }\n  if (ts.isModuleDeclaration(declaration)) {\n    return TsDocCoverageKind.Module;\n  }\n  if (ts.isExportAssignment(declaration)) {\n    return TsDocCoverageKind.Default;\n  }\n  return TsDocCoverageKind.Other;\n}\n\nfunction resolveLocation(declaration: ts.Declaration): {\n  readonly file: string;\n  readonly line: number;\n} {\n  // For variable declarations we want the line of the enclosing\n  // `VariableStatement` (which is where the leading TSDoc lives).\n  const target: ts.Node = ts.isVariableDeclaration(declaration)\n    ? (declaration.parent.parent ?? declaration)\n    : declaration;\n  const source = target.getSourceFile();\n  const { line } = source.getLineAndCharacterOfPosition(target.getStart());\n  return { file: source.fileName, line: line + 1 };\n}\n\nfunction parseTsDocFor(\n  declaration: ts.Declaration,\n  parser: TSDocParser,\n): DocComment | undefined {\n  // For `VariableDeclaration` the leading TSDoc lives on the parent\n  // `VariableStatement` — `getJSDocCommentRanges` walks back to the\n  // statement-level comment block automatically when given the\n  // statement node.\n  const target: ts.Node = ts.isVariableDeclaration(declaration)\n    ? (declaration.parent.parent ?? declaration)\n    : declaration;\n\n  const sourceText = target.getSourceFile().getFullText();\n  const ranges = ts.getLeadingCommentRanges(sourceText, target.getFullStart());\n  if (!ranges || ranges.length === 0) {\n    return undefined;\n  }\n\n  // Pick the last block comment that opens with `/**` — that is the\n  // declaration's TSDoc by convention.\n  for (let i = ranges.length - 1; i >= 0; i--) {\n    const range = ranges[i];\n    if (range.kind !== ts.SyntaxKind.MultiLineCommentTrivia) {\n      continue;\n    }\n    const text = sourceText.slice(range.pos, range.end);\n    if (!text.startsWith(\"/**\")) {\n      continue;\n    }\n    const parsed = parser.parseString(text);\n    return parsed.docComment;\n  }\n  return undefined;\n}\n\nfunction countSummaryWords(doc: DocComment): number {\n  let words = 0;\n  doc.summarySection.nodes.forEach((node) => {\n    words += countWordsInNode(node);\n  });\n  return words;\n}\n\nfunction countWordsInNode(node: { kind: string } & object): number {\n  // `DocPlainText` nodes carry the prose; everything else is\n  // structural (paragraphs, soft breaks). Walk the tree shallowly.\n  const anyNode = node as {\n    kind: string;\n    text?: string;\n    getChildNodes?: () => ReadonlyArray<{ kind: string } & object>;\n  };\n  if (anyNode.kind === \"PlainText\" && typeof anyNode.text === \"string\") {\n    return anyNode.text.split(/\\s+/).filter((token) => token.trim().length > 0)\n      .length;\n  }\n  let words = 0;\n  const children = anyNode.getChildNodes?.() ?? [];\n  for (const child of children) {\n    words += countWordsInNode(child);\n  }\n  return words;\n}\n\nfunction hasBlockTag(doc: DocComment, tagName: string): boolean {\n  if (tagName === \"@param\") {\n    return doc.params.count > 0;\n  }\n  if (tagName === \"@returns\" || tagName === \"@return\") {\n    return doc.returnsBlock !== undefined;\n  }\n  return doc.customBlocks.some((block) => block.blockTag.tagName === tagName);\n}\n","const NPM_REGISTRY = \"https://registry.npmjs.org\";\n\n/**\n * Metadata for a package from the npm registry. Only the fields we use are typed.\n *\n * @see https://github.com/npm/registry/blob/master/docs/responses/package-metadata.md\n */\ninterface NpmPackageMetadata {\n  name?: string;\n  \"dist-tags\"?: { latest?: string };\n  time?: Record<string, string>;\n  versions?: Record<string, unknown>;\n}\n\n/**\n * Returns true if the version has a semver prerelease segment (e.g. -canary, -alpha, -beta).\n * Full releases like 1.2.3 or 1.2.3+build.1 return false.\n */\nfunction isPrerelease(version: string): boolean {\n  const v = version.replace(/^v/, \"\");\n  return /^\\d+\\.\\d+\\.\\d+-/.test(v);\n}\n\n/**\n * Compares two semver-like version strings (e.g. \"1.2.3\").\n * Returns negative if `a < b`, positive if `a > b`, 0 if equal.\n * Prerelease segments are treated as less than release.\n */\nfunction compareVersions(a: string, b: string): number {\n  const parse = (v: string): number[] => {\n    const parts = v.replace(/^v/, \"\").split(/[-+]/)[0].split(\".\");\n    return parts.map((p) => {\n      const n = parseInt(p, 10);\n      return Number.isNaN(n) ? 0 : n;\n    });\n  };\n  const pa = parse(a);\n  const pb = parse(b);\n  const len = Math.max(pa.length, pb.length);\n  for (let i = 0; i < len; i++) {\n    const na = pa[i] ?? 0;\n    const nb = pb[i] ?? 0;\n    if (na !== nb) return na - nb;\n  }\n  return 0;\n}\n\n/**\n * Returns the latest full-release version of an npm package that has been\n * published for at least `minimumReleaseAgeMinutes` minutes. Prefers the\n * version indicated by the registry's \"latest\" dist-tag when it is a full\n * release: if that version's publish time is in the registry and old enough,\n * it is used; if it is not in the registry's \"time\" object (e.g. truncated\n * for large packages), the dist-tag is still used so npm's \"latest\" is\n * followed. When the dist-tag version is too new (in time but not old enough),\n * we fall back to the highest full-release version that is old enough and\n * ≤ latest (e.g. latest 2.x that's old enough, not 3.0.0). Prerelease\n * versions are excluded. Returns null if `time` is missing or no version is\n * eligible.\n *\n * @param packageName - npm package name (e.g. \"projen\").\n * @param minimumReleaseAgeMinutes - minimum age in minutes (e.g. 1440 for 24h).\n * @returns The latest eligible version string, or null.\n */\nexport async function getLatestEligibleVersion(\n  packageName: string,\n  minimumReleaseAgeMinutes: number,\n): Promise<string | null> {\n  const url = `${NPM_REGISTRY}/${encodeURIComponent(packageName)}`;\n  let res: Response;\n  try {\n    res = await fetch(url, {\n      headers: { Accept: \"application/json\" },\n    });\n  } catch {\n    return null;\n  }\n  if (!res.ok) return null;\n  let data: NpmPackageMetadata;\n  try {\n    data = (await res.json()) as NpmPackageMetadata;\n  } catch {\n    return null;\n  }\n  const time = data.time;\n  if (!time || typeof time !== \"object\") return null;\n\n  const nowMs = Date.now();\n  const minAgeMs = minimumReleaseAgeMinutes * 60 * 1000;\n\n  const distTagLatest = data[\"dist-tags\"]?.latest;\n  if (distTagLatest && !isPrerelease(distTagLatest)) {\n    const publishedAtStr = time[distTagLatest];\n    if (typeof publishedAtStr === \"string\") {\n      const publishedAt = Date.parse(publishedAtStr);\n      if (!Number.isNaN(publishedAt) && nowMs - publishedAt >= minAgeMs) {\n        return distTagLatest;\n      }\n    } else {\n      return distTagLatest;\n    }\n  }\n\n  const versionTimestamps: { version: string; publishedAt: number }[] = [];\n  for (const [key, value] of Object.entries(time)) {\n    if (key === \"created\" || key === \"modified\" || typeof value !== \"string\") {\n      continue;\n    }\n    if (isPrerelease(key)) continue;\n    const publishedAt = Date.parse(value);\n    if (Number.isNaN(publishedAt)) continue;\n    const ageMs = nowMs - publishedAt;\n    if (ageMs >= minAgeMs) {\n      versionTimestamps.push({ version: key, publishedAt });\n    }\n  }\n\n  if (versionTimestamps.length === 0) return null;\n\n  let candidates = versionTimestamps;\n  if (distTagLatest && !isPrerelease(distTagLatest)) {\n    candidates = versionTimestamps.filter(\n      (e) => compareVersions(e.version, distTagLatest) <= 0,\n    );\n  }\n  if (candidates.length === 0) return null;\n\n  candidates.sort((a, b) => compareVersions(b.version, a.version));\n  return candidates[0].version;\n}\n","import { VERSION } from \"./versions\";\n\n/**\n * Keys of the VERSION object in versions.ts.\n */\nexport type VersionKey = keyof typeof VERSION;\n\n/**\n * Mapping of VERSION keys that are backed by an npm package and eligible\n * for auto-update. Only these keys should be updated by version-update\n * automation; others (e.g. NODE_WORKFLOWS) are skipped.\n *\n * @see {@link VERSION_KEYS_SKIP} for keys that must not be auto-updated.\n */\nexport const VERSION_NPM_PACKAGES: ReadonlyArray<{\n  key: VersionKey;\n  npmPackage: string;\n}> = [\n  { key: \"ASTRO_VERSION\", npmPackage: \"astro\" },\n  { key: \"AWS_CDK_CLI_VERSION\", npmPackage: \"aws-cdk\" },\n  { key: \"AWS_CDK_LIB_VERSION\", npmPackage: \"aws-cdk-lib\" },\n  { key: \"AWS_CONSTRUCTS_VERSION\", npmPackage: \"constructs\" },\n  { key: \"PNPM_VERSION\", npmPackage: \"pnpm\" },\n  { key: \"PROJEN_VERSION\", npmPackage: \"projen\" },\n  { key: \"SHARP_VERSION\", npmPackage: \"sharp\" },\n  { key: \"STARLIGHT_VERSION\", npmPackage: \"@astrojs/starlight\" },\n  { key: \"TURBO_VERSION\", npmPackage: \"turbo\" },\n  { key: \"TYPES_NODE_VERSION\", npmPackage: \"@types/node\" },\n  { key: \"VITEST_VERSION\", npmPackage: \"vitest\" },\n] as const;\n\n/**\n * VERSION keys that are not backed by npm or must be skipped by\n * auto-update (e.g. runtime versions like Node.js).\n */\nexport const VERSION_KEYS_SKIP: ReadonlyArray<VersionKey> = [\"NODE_WORKFLOWS\"];\n","import * as spec from \"@jsii/spec\";\nimport { Component, JsonFile } from \"projen\";\nimport { TypeScriptProject } from \"projen/lib/typescript\";\nimport { ValueOf } from \"type-fest\";\n\n/**\n * The FQNs for the base classes and options used by Jsii.\n *\n * These are the defaults used by Projen's TypeScriptProject.\n */\nconst ProjenBaseFqn = {\n  TYPESCRIPT_PROJECT: \"projen.typescript.TypeScriptProject\",\n  TYPESCRIPT_PROJECT_OPTIONS: \"projen.typescript.TypeScriptProjectOptions\",\n} as const;\n\nexport interface ClassTypeOptions {\n  /**\n   * The name of the class.\n   *\n   * @example \"MyProject\"\n   */\n  name: string;\n\n  /**\n   * The FQN for the base class this class is extending.\n   *\n   * @default ProjenBaseFqn.TYPESCRIPT_PROJECT\n   */\n  baseFqn?: ValueOf<typeof ProjenBaseFqn> | string;\n\n  /**\n   * The FQN for the options for this class.\n   *\n   * @default ProjenBaseFqn.TYPESCRIPT_PROJECT_OPTIONS\n   */\n  optionsFqn?: ValueOf<typeof ProjenBaseFqn> | string;\n}\n\nexport class JsiiFaker extends Component {\n  // find project singleton\n  public static of(project: TypeScriptProject): JsiiFaker | undefined {\n    const isDefined = (c: Component): c is JsiiFaker => c instanceof JsiiFaker;\n    return project.components.find(isDefined);\n  }\n\n  private _assemblyName: string;\n  private _types: { [name: string]: spec.Type } = {};\n\n  constructor(public readonly project: TypeScriptProject) {\n    super(project);\n\n    /**\n     * In JSII, the assembly name is essentially the package name. It's used as a\n     * scope when targeting types and metadata in other \"jsii assemblies\" that\n     * might be in sub-packages used by the project.\n     *\n     * For this case, we'll just use the package name from Projen.\n     */\n    this._assemblyName = this.project.package.packageName;\n\n    new JsonFile(project, \".jsii\", {\n      obj: () => {\n        return {\n          name: this._assemblyName,\n          types: this._types,\n        };\n      },\n    });\n  }\n\n  public toJSON = () => {\n    return {\n      types: this._types,\n    };\n  };\n\n  public addClassType(options: ClassTypeOptions) {\n    const fqn = [this._assemblyName, options.name].join(\".\");\n    const type: spec.ClassType = {\n      assembly: this._assemblyName,\n      base: options.baseFqn ?? ProjenBaseFqn.TYPESCRIPT_PROJECT,\n      fqn,\n      kind: spec.TypeKind.Class,\n      name: options.name,\n      initializer: {\n        parameters: [\n          {\n            name: \"options\",\n            type: {\n              fqn:\n                options.optionsFqn ?? ProjenBaseFqn.TYPESCRIPT_PROJECT_OPTIONS,\n            },\n          },\n        ],\n      },\n    };\n\n    this._types[fqn] = type;\n  }\n}\n","import { SampleFile } from \"projen\";\nimport { NodeProject } from \"projen/lib/javascript\";\n\n/**\n * Wire Playwright E2E tests into a {@link NodeProject}.\n *\n * Adds `@playwright/test` as a dev dep, registers the standard\n * `e2e:install` / `e2e` / `e2e:ui` / `e2e:report` projen tasks (with\n * matching package scripts), emits a minimal `playwright.config.ts`\n * pointing at `http://localhost:5173` (Vite's default dev port), and\n * gitignores Playwright's output directories.\n *\n * Designed to be called against a `ReactViteSiteProject`, but accepts\n * any `NodeProject` — the integration is intentionally framework-light\n * so it can layer onto adjacent React + Vite scaffolds without\n * subclassing.\n *\n * @param project - The project to wire Playwright into.\n */\nexport function addPlaywright(project: NodeProject): void {\n  project.addDevDeps(\"@playwright/test\");\n\n  /**\n   * Tasks.\n   */\n  project.tasks.addTask(\"e2e:install\", {\n    description: \"Install Playwright browsers\",\n    steps: [{ exec: \"npx playwright install --with-deps\" }],\n  });\n  project.tasks.addTask(\"e2e\", {\n    description: \"Run Playwright E2E tests (headless)\",\n    steps: [{ exec: \"npx playwright test\" }],\n  });\n  project.tasks.addTask(\"e2e:ui\", {\n    description: \"Run Playwright in UI mode\",\n    steps: [{ exec: \"npx playwright test --ui\" }],\n  });\n  project.tasks.addTask(\"e2e:report\", {\n    description: \"Open last HTML report\",\n    steps: [{ exec: \"npx playwright show-report\" }],\n  });\n\n  /**\n   * Package scripts.\n   */\n  project.setScript(\"e2e:install\", \"npx projen e2e:install\");\n  project.setScript(\"e2e\", \"npx projen e2e\");\n  project.setScript(\"e2e:ui\", \"npx projen e2e:ui\");\n  project.setScript(\"e2e:report\", \"npx projen e2e:report\");\n\n  /**\n   * Config + ignores. Defaults `baseURL` to Vite's local dev server,\n   * overridable via the `PLAYWRIGHT_BASE_URL` env var.\n   */\n  new SampleFile(project, \"playwright.config.ts\", {\n    contents: `import { defineConfig, devices } from '@playwright/test';\n\nexport default defineConfig({\n  testDir: './tests',\n  reporter: [['html', { open: 'never' }]],\n  use: {\n    baseURL: process.env.PLAYWRIGHT_BASE_URL || 'http://localhost:5173',\n    trace: 'on-first-retry',\n  },\n  projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }],\n});\n`,\n  });\n\n  project.gitignore.addPatterns(\"test-results/\", \"playwright-report/\");\n}\n","import { SampleFile } from \"projen\";\nimport { NodeProject } from \"projen/lib/javascript\";\n\n/**\n * Options for {@link addStorybook}.\n */\nexport interface AddStorybookOptions {\n  /**\n   * Install `@storybook/addon-docs` and register it in\n   * `.storybook/main.ts`.\n   *\n   * @default true\n   */\n  readonly withDocs?: boolean;\n}\n\n/**\n * Wire Storybook 9 (Vite framework) into a {@link NodeProject}.\n *\n * Adds the Storybook + `@storybook/react-vite` dev deps, registers\n * `storybook` and `build-storybook` projen tasks (with matching package\n * scripts), and emits the canonical `.storybook/main.ts` /\n * `.storybook/preview.ts` config pair. The preview imports the React\n * site's Tailwind entry (`src/index.css`) so stories pick up the same\n * theme as the running app.\n *\n * Designed to be called against a `ReactViteSiteProject`, but accepts\n * any `NodeProject` — the integration is intentionally framework-light\n * so it can layer onto adjacent React + Vite scaffolds without\n * subclassing.\n *\n * @param project - The project to wire Storybook into.\n * @param options - Optional configuration. Defaults to `withDocs: true`.\n */\nexport function addStorybook(\n  project: NodeProject,\n  options: AddStorybookOptions = {},\n): void {\n  const withDocs = options.withDocs ?? true;\n\n  project.addDevDeps(\n    \"storybook\",\n    \"@storybook/react@^9\",\n    \"@storybook/react-vite@^9\",\n    ...(withDocs ? [\"@storybook/addon-docs@^9\"] : []),\n  );\n\n  /**\n   * Tasks\n   */\n  project.tasks.addTask(\"storybook\", {\n    description: \"Run Storybook (Vite)\",\n    steps: [{ exec: \"storybook dev -p 6006\" }],\n  });\n  project.tasks.addTask(\"build-storybook\", {\n    description: \"Build static Storybook\",\n    steps: [{ exec: \"storybook build\" }],\n  });\n\n  /**\n   * Package scripts so `pnpm storybook` / `pnpm build-storybook` work\n   * inside the app.\n   */\n  project.setScript(\"storybook\", \"npx projen storybook\");\n  project.setScript(\"build-storybook\", \"npx projen build-storybook\");\n\n  /**\n   * Config files.\n   */\n  new SampleFile(project, \".storybook/main.ts\", {\n    contents: `import type { StorybookConfig } from '@storybook/react-vite';\n\nconst config: StorybookConfig = {\n  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],\n  addons: [${withDocs ? `'@storybook/addon-docs'` : \"\"}],\n  framework: { name: '@storybook/react-vite', options: {} },\n};\nexport default config;\n`,\n  });\n\n  new SampleFile(project, \".storybook/preview.ts\", {\n    contents: `import '../src/index.css';\nconst preview = { parameters: { controls: { expanded: true } } };\nexport default preview;\n`,\n  });\n}\n","import { SampleFile } from \"projen\";\nimport { merge } from \"ts-deepmerge\";\nimport { resolveAstroProjectOutdir } from \"./resolve-outdir\";\nimport {\n  TestRunner,\n  TypeScriptProject,\n  TypeScriptProjectOptions,\n} from \"./typescript-project\";\nimport { AstroConfig } from \"../astro/astro-config\";\nimport {\n  AstroConfigOptions,\n  AstroIntegrationSpec,\n} from \"../astro/astro-config-options\";\nimport { TurboRepo } from \"../turbo\";\nimport { VERSION } from \"../versions\";\n\n/**\n * Configuration options for AstroProject.\n */\nexport interface AstroProjectOptions\n  extends TypeScriptProjectOptions, AstroConfigOptions {\n  /**\n   * Astro package version.\n   *\n   * @default VERSION.ASTRO_VERSION\n   */\n  readonly astroVersion?: string;\n\n  /**\n   * Emit sample Astro starter files (`src/pages/index.astro`, `public/favicon.svg`).\n   *\n   * @default false\n   */\n  readonly sampleCode?: boolean;\n\n  /**\n   * Astro tsconfig preset to extend.\n   *\n   * @default \"astro/tsconfigs/strict\"\n   */\n  readonly astroTsconfigExtends?: string;\n}\n\n/**\n * Minimal Astro site scaffolded on top of {@link TypeScriptProject}.\n *\n * Replaces the `tsc` compile step with `astro check && astro build`, writes\n * `astro.config.mjs`, sets `\"type\": \"module\"`, and wires dev/preview tasks.\n */\nexport class AstroProject extends TypeScriptProject {\n  /**\n   * Rendered Astro config component.\n   */\n  public readonly astroConfig: AstroConfig;\n\n  constructor(userOptions: AstroProjectOptions) {\n    /*************************************************************************\n     *\n     * Resolve outdir\n     *\n     * When the caller omits `outdir`, derive it from the scoped package\n     * name (`packageName ?? name`) as `sites/<scope>/<name>`. This enforces\n     * the monorepo-layout contract (ADR-006) without requiring every\n     * Astro sub-project to restate its own path. Resolution runs before\n     * `super()` so the derived value is passed explicitly — otherwise the\n     * TypeScriptProject base class would see `outdir: undefined` and place\n     * the project directly under the monorepo root.\n     *\n     ************************************************************************/\n\n    const resolvedOutdir =\n      userOptions.outdir ??\n      resolveAstroProjectOutdir(userOptions.packageName ?? userOptions.name);\n\n    /**\n     * Default to Vitest — Astro's native test runner — exclude `astro`\n     * from projen's per-package ncu upgrade workflow so only the\n     * configulator VERSION-driven update path owns it, and default\n     * `tsconfig.compilerOptions.declaration` to `false` so `astro check`\n     * (which runs `tsc --noEmit`) doesn't trip TS2742 on re-exported\n     * third-party types under pnpm's hoisted node_modules layout.\n     *\n     * Use `ts-deepmerge`'s `merge()` (not a shallow spread) so a default\n     * nested object like\n     * `tsconfig: { compilerOptions: { declaration: false } }` survives a\n     * user override that only sets unrelated tsconfig fields. `merge()`\n     * also concatenates arrays, which gives the right semantics for\n     * `depsUpgradeOptions.exclude`.\n     */\n    const defaultOptions: Partial<AstroProjectOptions> = {\n      testRunner: TestRunner.VITEST,\n      // Astro sites don't expose a library API surface — skip the\n      // `@microsoft/api-extractor` wiring the TypeScriptProject base adds\n      // by default. Callers can opt in with `apiExtractor: { ... }` if a\n      // given site genuinely ships typed re-exports.\n      apiExtractor: false,\n      tsconfig: {\n        compilerOptions: {\n          declaration: false,\n        },\n      },\n      depsUpgradeOptions: {\n        exclude: [\"astro\"],\n      },\n    };\n    const merged = merge(defaultOptions, userOptions) as AstroProjectOptions;\n    const options: AstroProjectOptions = {\n      ...merged,\n      outdir: resolvedOutdir,\n    };\n\n    super(options);\n\n    const astroVersion = options.astroVersion ?? VERSION.ASTRO_VERSION;\n    const astroTsconfigExtends =\n      options.astroTsconfigExtends ?? \"astro/tsconfigs/strict\";\n\n    /**\n     * Astro ships as ESM; the site package must be a module.\n     */\n    this.package.addField(\"type\", \"module\");\n\n    /**\n     * Extend Astro's tsconfig preset so `astro check` and IDE tooling\n     * understand `.astro` files, JSX, and bundler-style resolution.\n     */\n    this.tsconfig?.file.addOverride(\"extends\", astroTsconfigExtends);\n    this.tsconfig?.addInclude(\".astro/types.d.ts\");\n    this.tsconfig?.addInclude(\"src/**/*.astro\");\n\n    /**\n     * Replace projen's tsc-driven compile with Astro's build pipeline.\n     */\n    this.compileTask.reset();\n    this.compileTask.exec(\"astro check\");\n    this.compileTask.exec(\"astro build\");\n\n    /**\n     * Point `watch` at Astro's dev server (projen's default runs `tsc -w`,\n     * which is meaningless for an Astro site).\n     */\n    this.tasks.tryFind(\"watch\")?.reset(\"astro dev\");\n\n    /**\n     * A website is not an npm tarball — reset `package` to a no-op so the\n     * inherited `build` task does not emit `dist/js/*.tgz` alongside the\n     * actual site output.\n     */\n    this.packageTask.reset();\n\n    /**\n     * Astro CLI tasks. `build` already exists on projen; add only the\n     * Astro-specific lifecycle tasks.\n     */\n    if (!this.tasks.tryFind(\"dev\")) {\n      this.addTask(\"dev\", {\n        description: \"Start the Astro dev server\",\n        exec: \"astro dev\",\n        receiveArgs: true,\n      });\n    }\n    if (!this.tasks.tryFind(\"preview\")) {\n      this.addTask(\"preview\", {\n        description: \"Preview the built site locally\",\n        exec: \"astro preview\",\n        receiveArgs: true,\n      });\n    }\n    if (!this.tasks.tryFind(\"check\")) {\n      this.addTask(\"check\", {\n        description: \"Run Astro's type and content checks\",\n        exec: \"astro check\",\n      });\n    }\n\n    /**\n     * Runtime and tooling dependencies.\n     */\n    this.addDeps(`astro@${astroVersion}`);\n    this.addDevDeps(\n      \"@astrojs/check\",\n      \"astro-eslint-parser\",\n      \"eslint-plugin-astro\",\n      \"prettier-plugin-astro\",\n    );\n\n    /**\n     * Register the Astro prettier plugin so `.astro` files are formatted.\n     */\n    const prettierConfig = this.tryFindObjectFile(\".prettierrc.json\");\n    prettierConfig?.addOverride(\"plugins\", [\"prettier-plugin-astro\"]);\n    prettierConfig?.addOverride(\"overrides\", [\n      { files: \"*.astro\", options: { parser: \"astro\" } },\n    ]);\n\n    /**\n     * Wire eslint-plugin-astro so `.astro` files are actually linted.\n     * Projen's default `fileExtensions` is constructor-only and set to `.ts`,\n     * so we add an explicit lint pattern to force `.astro` paths onto the\n     * generated eslint command line.\n     */\n    this.eslint?.addPlugins(\"astro\");\n    this.eslint?.addExtends(\"plugin:astro/recommended\");\n    this.eslint?.addOverride({\n      files: [\"*.astro\"],\n      parser: \"astro-eslint-parser\",\n    });\n    this.eslint?.addLintPattern(\"src/**/*.astro\");\n\n    /**\n     * Astro exposes its API surface via virtual modules (`astro:content`,\n     * `astro:assets`, `astro:env`, etc.). `import/no-unresolved` cannot\n     * resolve them, so ignore the `astro:*` namespace.\n     */\n    this.eslint?.addRules({\n      \"import/no-unresolved\": [\"error\", { ignore: [\"^astro:\"] }],\n    });\n\n    /**\n     * Astro-specific gitignore entries. `dist` is already handled by the\n     * base TypeScriptProject.\n     */\n    this.gitignore.addPatterns(\".astro\", \".vercel\", \".netlify\");\n\n    /**\n     * Extend turbo inputs so the compile task invalidates on Astro-specific\n     * source paths. Outputs (`dist/**`) are already added by the base class.\n     */\n    const turbo = TurboRepo.of(this);\n    if (turbo?.compileTask) {\n      turbo.compileTask.inputs.push(\"public/**\", \"astro.config.mjs\");\n    }\n\n    /**\n     * Render astro.config.mjs.\n     */\n    const integrations: Array<AstroIntegrationSpec> =\n      options.integrations ?? [];\n    this.astroConfig = new AstroConfig(this, {\n      site: options.site,\n      base: options.base,\n      output: options.output,\n      integrations,\n      adapter: options.adapter,\n    });\n\n    /**\n     * Optional starter files.\n     */\n    if (options.sampleCode === true) {\n      new SampleFile(this, \"src/pages/index.astro\", {\n        contents: DEFAULT_INDEX_ASTRO,\n      });\n      new SampleFile(this, \"public/favicon.svg\", {\n        contents: DEFAULT_FAVICON_SVG,\n      });\n    }\n  }\n}\n\nconst DEFAULT_INDEX_ASTRO = `---\n// Welcome to Astro!\n---\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <link rel=\"icon\" type=\"image/svg+xml\" href=\"/favicon.svg\" />\n    <meta name=\"viewport\" content=\"width=device-width\" />\n    <title>Astro</title>\n  </head>\n  <body>\n    <h1>Hello, Astro!</h1>\n  </body>\n</html>\n`;\n\nconst DEFAULT_FAVICON_SVG = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 128 128\"><path d=\"M64 8a56 56 0 1 0 0 112A56 56 0 0 0 64 8Z\" fill=\"#ff5d01\"/></svg>\n`;\n","import { Project } from \"projen\";\n\n/**\n * Canonical top-level folders for a configulator monorepo (ADR-006).\n *\n * Every sub-project must live under one of these roots. `DOCS` is a\n * singleton (the single Starlight site at `/docs`); `APPS`, `PACKAGES`,\n * and `SITES` are parents for `@scope/<name>` sub-projects.\n *\n * @see docs/src/content/docs/requirements/architectural-decisions/ADR-006-monorepo-layout.md\n */\nexport const MONOREPO_LAYOUT = {\n  DOCS: \"docs\",\n  APPS: \"apps\",\n  PACKAGES: \"packages\",\n  SITES: \"sites\",\n} as const;\n\nexport type MonorepoLayoutRoot =\n  (typeof MONOREPO_LAYOUT)[keyof typeof MONOREPO_LAYOUT];\n\n/**\n * How `MonorepoProject` reacts when a sub-project's `outdir` falls outside\n * the root expected for its project type (see ADR-006 §4).\n *\n * - `\"off\"` — no validation runs.\n * - `\"warn\"` — log a console warning per offending sub-project; synth proceeds.\n * - `\"error\"` — throw on the first offending sub-project; synth fails.\n */\nexport const LAYOUT_ENFORCEMENT = {\n  OFF: \"off\",\n  WARN: \"warn\",\n  ERROR: \"error\",\n} as const;\n\nexport type LayoutEnforcement =\n  (typeof LAYOUT_ENFORCEMENT)[keyof typeof LAYOUT_ENFORCEMENT];\n\n/**\n * Mapping from configulator project-type class name to the root folder its\n * `outdir` must live under.\n *\n * We key by class name (not class reference) so this module stays free of\n * import cycles with the project-type files that validate against it.\n * `StarlightProject` maps to `DOCS` by default because the docs-singleton\n * rule says a default-role Starlight project is the monorepo-wide docs\n * site. Site-role Starlight projects override this mapping at validate\n * time via their instance `role` property.\n *\n * @see ADR-006 §4 — Configulator project-type → `outdir` mapping\n */\nexport const LAYOUT_ROOT_BY_PROJECT_TYPE: Readonly<\n  Record<string, MonorepoLayoutRoot>\n> = {\n  TypeScriptProject: MONOREPO_LAYOUT.PACKAGES,\n  AwsCdkProject: MONOREPO_LAYOUT.APPS,\n  AstroProject: MONOREPO_LAYOUT.SITES,\n  ReactViteSiteProject: MONOREPO_LAYOUT.SITES,\n  StarlightProject: MONOREPO_LAYOUT.DOCS,\n};\n\n/**\n * A single offender reported by {@link validateMonorepoLayout}. One entry\n * per sub-project whose `outdir` falls outside its expected root.\n */\nexport interface LayoutViolation {\n  readonly projectName: string;\n  readonly projectType: string;\n  readonly outdir: string;\n  readonly expectedRoot: MonorepoLayoutRoot;\n}\n\n/**\n * Violation reported by {@link validateStarlightSingleton} when a\n * `MonorepoProject` tree contains more than one `StarlightProject`\n * carrying `role: \"docs\"` (the docs-singleton rule — ADR-006 §3).\n */\nexport interface StarlightSingletonViolation {\n  readonly projectNames: ReadonlyArray<string>;\n}\n\n/**\n * Inspect every sub-project of `root` and collect those whose `outdir` does\n * not live under the root expected for their project class (ADR-006 §4).\n *\n * - Sub-projects whose class name is not in\n *   {@link LAYOUT_ROOT_BY_PROJECT_TYPE} are skipped — the contract only\n *   covers the four documented project types.\n * - The root project itself is skipped (it *is* the monorepo root, not a\n *   sub-project).\n * - `outdir` comparison is done in POSIX form against the project root so\n *   absolute paths synthesised on Windows still match.\n * - A `StarlightProject` carrying `role: \"site\"` is validated against the\n *   `sites/` root rather than the default `docs/` root. This keeps the\n *   class-to-root mapping static while still honouring the ADR-006 §3\n *   docs-singleton carve-out for docs-role projects.\n */\nexport function validateMonorepoLayout(root: Project): Array<LayoutViolation> {\n  const violations: Array<LayoutViolation> = [];\n  const rootOutdir = toPosix(root.outdir);\n\n  for (const sub of root.subprojects) {\n    const className = sub.constructor.name;\n    const expectedRoot = expectedRootFor(sub, className);\n\n    if (expectedRoot === undefined) {\n      // Unknown project type — outside the layout contract.\n      continue;\n    }\n\n    const relOutdir = relativeOutdir(rootOutdir, toPosix(sub.outdir));\n\n    if (!outdirMatchesRoot(relOutdir, expectedRoot)) {\n      violations.push({\n        projectName: sub.name,\n        projectType: className,\n        outdir: relOutdir,\n        expectedRoot,\n      });\n    }\n  }\n\n  return violations;\n}\n\n/**\n * Inspect every sub-project of `root` and flag cases where more than one\n * `StarlightProject` claims `role: \"docs\"` (ADR-006 §3 — there is\n * exactly one Starlight docs site per monorepo, and it lives at `/docs`).\n *\n * Returns `undefined` when the singleton rule is satisfied (zero or one\n * docs-role Starlight project). Returns a single violation whose\n * `projectNames` list contains every offending project when two or more\n * docs-role Starlight projects are present — the caller reports the\n * whole set so authors can see every candidate at once rather than\n * fixing them one at a time.\n *\n * Site-role Starlight projects never count toward the singleton limit\n * and are not flagged.\n */\nexport function validateStarlightSingleton(\n  root: Project,\n): StarlightSingletonViolation | undefined {\n  const docsRoleProjects: Array<string> = [];\n\n  for (const sub of root.subprojects) {\n    if (sub.constructor.name !== \"StarlightProject\") {\n      continue;\n    }\n    if (getStarlightRole(sub) === \"docs\") {\n      docsRoleProjects.push(sub.name);\n    }\n  }\n\n  if (docsRoleProjects.length <= 1) {\n    return undefined;\n  }\n\n  return { projectNames: docsRoleProjects };\n}\n\n/**\n * Decide which canonical root a given sub-project's `outdir` must live\n * under. For most project types this is a static class-to-root lookup.\n * `StarlightProject` is the one instance-sensitive case: site-role\n * projects live under `sites/` while docs-role projects live at\n * `docs/`.\n */\nfunction expectedRootFor(\n  sub: Project,\n  className: string,\n): MonorepoLayoutRoot | undefined {\n  if (className === \"StarlightProject\") {\n    return getStarlightRole(sub) === \"site\"\n      ? MONOREPO_LAYOUT.SITES\n      : MONOREPO_LAYOUT.DOCS;\n  }\n  return LAYOUT_ROOT_BY_PROJECT_TYPE[className];\n}\n\n/**\n * Read the `role` property off a `StarlightProject` instance without\n * importing the class (which would create a cycle between this module\n * and `starlight-project.ts`). Returns the raw role string\n * (`\"docs\"` or `\"site\"`), falling back to `\"docs\"` when the property is\n * missing — mirrors the `StarlightProjectOptions.role` default and\n * preserves backward compatibility with older consumers that predate\n * the role field.\n */\nfunction getStarlightRole(sub: Project): \"docs\" | \"site\" {\n  const role = (sub as unknown as { readonly role?: string }).role;\n  return role === \"site\" ? \"site\" : \"docs\";\n}\n\n/**\n * Render one {@link LayoutViolation} as an actionable, single-line error\n * message pointing the reader at ADR-006.\n */\nexport function formatLayoutViolation(violation: LayoutViolation): string {\n  const { projectName, projectType, outdir, expectedRoot } = violation;\n  const expectedExample =\n    expectedRoot === MONOREPO_LAYOUT.DOCS\n      ? \"docs/\"\n      : `${expectedRoot}/<scope>/<name>`;\n  return (\n    `[monorepo-layout] ${projectType} \"${projectName}\" has outdir \"${outdir}\", ` +\n    `which is outside the expected root \"${expectedRoot}/\" ` +\n    `(expected e.g. \"${expectedExample}\"). ` +\n    \"See docs/src/content/docs/requirements/architectural-decisions/ADR-006-monorepo-layout.md.\"\n  );\n}\n\n/**\n * Render a {@link StarlightSingletonViolation} as an actionable,\n * single-line error message pointing the reader at ADR-006 §3\n * (docs-singleton carve-out).\n */\nexport function formatStarlightSingletonViolation(\n  violation: StarlightSingletonViolation,\n): string {\n  const names = violation.projectNames.map((n) => `\"${n}\"`).join(\", \");\n  return (\n    `[monorepo-layout] Multiple StarlightProject instances with role: \"docs\" found (${names}). ` +\n    `ADR-006 allows exactly one docs-role Starlight project per MonorepoProject. ` +\n    `Either remove the duplicates or set role: \"site\" on the additional ones so they land under sites/. ` +\n    \"See docs/src/content/docs/requirements/architectural-decisions/ADR-006-monorepo-layout.md.\"\n  );\n}\n\n/**\n * Compare a sub-project `outdir` (expressed relative to the monorepo root,\n * POSIX-separated) to its expected top-level root.\n *\n * The `DOCS` root is a singleton: the sub-project must live at exactly\n * `docs/` (or a nested path under it — e.g. `docs/packages/foo`). For the\n * other roots, the outdir must begin with `<root>/` and carry at least one\n * path segment after it.\n */\nfunction outdirMatchesRoot(\n  relOutdir: string,\n  expectedRoot: MonorepoLayoutRoot,\n): boolean {\n  const segments = relOutdir.split(\"/\").filter((s) => s.length > 0);\n  if (segments.length === 0) {\n    return false;\n  }\n\n  if (segments[0] !== expectedRoot) {\n    return false;\n  }\n\n  if (expectedRoot === MONOREPO_LAYOUT.DOCS) {\n    // `docs/` singleton — anything at or below docs/ is allowed.\n    return true;\n  }\n\n  // `apps/`, `packages/`, `sites/` — must have at least one segment after the root.\n  return segments.length >= 2;\n}\n\n/**\n * Normalise a path to use forward slashes so Windows absolute paths\n * (`C:\\...`) compare cleanly against POSIX-style outdir values.\n */\nfunction toPosix(p: string): string {\n  return p.replace(/\\\\/g, \"/\");\n}\n\n/**\n * Convert an absolute sub-project `outdir` into a path relative to the root\n * project. If the two paths are unrelated (which shouldn't happen in\n * practice — projen nests sub-projects under their parent), we fall back to\n * the raw sub-outdir so the violation message still points somewhere\n * meaningful.\n */\nfunction relativeOutdir(rootOutdir: string, subOutdir: string): string {\n  if (subOutdir === rootOutdir) {\n    return \"\";\n  }\n  const prefix = rootOutdir.endsWith(\"/\") ? rootOutdir : `${rootOutdir}/`;\n  if (subOutdir.startsWith(prefix)) {\n    return subOutdir.slice(prefix.length);\n  }\n  return subOutdir;\n}\n","import { MONOREPO_LAYOUT, MonorepoLayoutRoot } from \"./monorepo-layout\";\n\n/**\n * Parsed shape of an npm-style scoped package name (`@scope/name`).\n */\ninterface ParsedScopedName {\n  readonly scope: string;\n  readonly name: string;\n}\n\n/**\n * Parse `@scope/name` into its two halves. Returns `undefined` when the\n * input is unscoped or otherwise not a valid scoped package name.\n *\n * Matches the npm package-name grammar loosely: the scope must start with\n * `@`, both scope and name must be non-empty, and neither may contain a\n * slash. This is good enough to decide whether to derive an `outdir` —\n * projen itself already validates the full name elsewhere.\n */\nfunction parseScopedName(input: string): ParsedScopedName | undefined {\n  if (!input.startsWith(\"@\")) {\n    return undefined;\n  }\n  const slashIndex = input.indexOf(\"/\");\n  if (slashIndex < 2) {\n    // Either no slash, or the scope portion is empty (`@/foo`).\n    return undefined;\n  }\n  const scope = input.slice(0, slashIndex);\n  const name = input.slice(slashIndex + 1);\n  if (name.length === 0 || name.includes(\"/\")) {\n    return undefined;\n  }\n  return { scope, name };\n}\n\n/**\n * Resolve a sub-project's `outdir` from its package name.\n *\n * Given a scoped package name like `@codedrifters/foo`, returns\n * `<root>/@codedrifters/foo` where `<root>` comes from\n * {@link MONOREPO_LAYOUT}. The scope segment is preserved verbatim —\n * including the leading `@` — so the resulting path mirrors the npm\n * name exactly (e.g. `packages/@codedrifters/foo`).\n *\n * Throws when the package name is unscoped or empty. Callers must\n * either supply a scoped name or pass `outdir` explicitly.\n *\n * @param packageName - The npm package name. Typically sourced from\n *   `userOptions.packageName ?? userOptions.name` — both are valid\n *   inputs because projen itself falls back from `packageName` to\n *   `name` when rendering `package.json`.\n * @param root - Which top-level monorepo folder to place the\n *   sub-project under (e.g. `packages`, `apps`, `sites`).\n */\nexport function resolveOutdirFromPackageName(\n  packageName: string | undefined,\n  root: MonorepoLayoutRoot,\n): string {\n  if (packageName === undefined || packageName.length === 0) {\n    throw new Error(\n      \"Cannot derive outdir: packageName (or name) is required when outdir is omitted. \" +\n        \"Either pass a scoped `packageName` / `name` like `@scope/foo`, or set `outdir` explicitly.\",\n    );\n  }\n\n  const parsed = parseScopedName(packageName);\n  if (parsed === undefined) {\n    throw new Error(\n      `Cannot derive outdir from unscoped packageName \"${packageName}\". ` +\n        \"Either use a scoped name like `@scope/foo`, or set `outdir` explicitly. \" +\n        `Configulator places sub-projects at \"${root}/<scope>/<name>\".`,\n    );\n  }\n\n  return `${root}/${parsed.scope}/${parsed.name}`;\n}\n\n/**\n * Convenience wrapper that resolves an `outdir` for a `TypeScriptProject`\n * under the canonical `packages/` root.\n */\nexport function resolveTypeScriptProjectOutdir(\n  packageName: string | undefined,\n): string {\n  return resolveOutdirFromPackageName(packageName, MONOREPO_LAYOUT.PACKAGES);\n}\n\n/**\n * Convenience wrapper that resolves an `outdir` for an `AwsCdkProject`\n * under the canonical `apps/` root.\n */\nexport function resolveAwsCdkProjectOutdir(\n  packageName: string | undefined,\n): string {\n  return resolveOutdirFromPackageName(packageName, MONOREPO_LAYOUT.APPS);\n}\n\n/**\n * Convenience wrapper that resolves an `outdir` for an `AstroProject`\n * under the canonical `sites/` root.\n */\nexport function resolveAstroProjectOutdir(\n  packageName: string | undefined,\n): string {\n  return resolveOutdirFromPackageName(packageName, MONOREPO_LAYOUT.SITES);\n}\n\n/**\n * Convenience wrapper that resolves an `outdir` for a\n * `ReactViteSiteProject` under the canonical `sites/` root.\n */\nexport function resolveReactViteSiteProjectOutdir(\n  packageName: string | undefined,\n): string {\n  return resolveOutdirFromPackageName(packageName, MONOREPO_LAYOUT.SITES);\n}\n","import { ReleasableCommits, typescript } from \"projen\";\nimport {\n  NodePackageManager,\n  Transform,\n  UpgradeDependenciesSchedule,\n} from \"projen/lib/javascript\";\nimport { ReleaseTrigger } from \"projen/lib/release\";\nimport { merge } from \"ts-deepmerge\";\nimport { CHANGELOG_TYPES, resolveVersionrcOptions } from \"./changelog-types\";\nimport { MonorepoProject } from \"./monorepo-project\";\nimport { applyPackagePrivate, PackagePrivateOptions } from \"./package-private\";\nimport { resolveTypeScriptProjectOutdir } from \"./resolve-outdir\";\nimport { AgentConfig } from \"../agent/agent-config\";\nimport { AgentConfigOptions } from \"../agent/agent-config-options\";\nimport { ApiExtractor, ApiExtractorOptions } from \"../api-extractor\";\nimport { PnpmWorkspace } from \"../pnpm\";\nimport { ResetTask, ResetTaskOptions } from \"../tasks/reset-task\";\nimport { TurboRepo } from \"../turbo\";\nimport { TsdocConfig, TsdocConfigOptions } from \"../typescript\";\nimport { Vitest, VitestOptions } from \"../vitest\";\n\n/**\n * Test runner for TypeScript projects.\n */\nexport const TestRunner = {\n  JEST: \"jest\",\n  VITEST: \"vitest\",\n} as const;\n\nexport type TestRunner = (typeof TestRunner)[keyof typeof TestRunner];\n\n/**\n * Configuration options for TypeScriptProject.\n */\nexport interface TypeScriptProjectOptions\n  extends\n    Omit<typescript.TypeScriptProjectOptions, \"defaultReleaseBranch\">,\n    PackagePrivateOptions {\n  /**\n   * Test runner to use.\n   *\n   * @default TestRunner.JEST\n   */\n  readonly testRunner?: TestRunner;\n\n  /**\n   * Options for Vitest (only used when testRunner is 'vitest').\n   */\n  readonly vitestOptions?: VitestOptions;\n\n  /**\n   * Enable the reset task that deletes all build artifacts.\n   *\n   * @default true\n   */\n  readonly resetTask?: boolean;\n\n  /**\n   * Options for the reset task.\n   */\n  readonly resetTaskOptions?: ResetTaskOptions;\n\n  /**\n   * AI agent configuration (Cursor, Claude Code rules).\n   * Generates rule files with auto-detected bundles based on project tooling.\n   *\n   * - `true` or `{}`: enable with auto-detected defaults\n   * - `AgentConfigOptions`: enable with explicit configuration\n   * - `false` or `undefined`: disabled (default)\n   *\n   * Sub-projects do not inherit `AgentConfig` from their parent\n   * `MonorepoProject`. Agent rule files are rendered only on projects that\n   * explicitly opt in, so a monorepo's root `AgentConfig` does not duplicate\n   * `.cursor/`, `.claude/`, or `CLAUDE.md` into each sub-project's `outdir`.\n   *\n   * @default false\n   */\n  readonly agentConfig?: AgentConfigOptions | boolean;\n\n  /**\n   * Configure the `@microsoft/api-extractor` runner used by the\n   * docs-sync pipeline for public-API drift detection. When omitted\n   * the extractor is enabled with default options (rollups write to\n   * `.api-extractor/` and are gitignored). Set to `false` to opt a\n   * package out of drift detection entirely.\n   *\n   * @default `{}`\n   */\n  readonly apiExtractor?: ApiExtractorOptions | false;\n\n  /**\n   * Configure the emitted `tsdoc.json` so `eslint-plugin-tsdoc` recognises\n   * workspace-scope package references (`@codedrifters/...`, `@openhi/...`,\n   * etc.) and common JSDoc convention tags such as default, defaultValue,\n   * experimental, and the internal-marker tag.\n   *\n   * Pass `false` to opt out of emitting `tsdoc.json` entirely. The\n   * `tsdoc-at-sign-in-word` and `tsdoc-undefined-tag` lint warnings will\n   * return at full volume in that case.\n   *\n   * Note: the tag names above are intentionally written without their\n   * leading at-sign. `tsc --stripInternal` (which configulator enables)\n   * strips any declaration whose JSDoc contains the bare at-sign-prefixed\n   * `internal` tag — even when the token sits inside a backtick code span\n   * — and that strips this field from the published `.d.ts` rollup.\n   *\n   * @default `{}`\n   */\n  readonly tsdocConfig?: TsdocConfigOptions | false;\n\n  /**\n   * Control the `jsdoc/require-jsdoc` lint rule applied to `src/**` files.\n   *\n   * `eslint-plugin-jsdoc`'s `require-jsdoc` rule emits one warning per\n   * un-documented function / method / variable / interface / type / enum\n   * declaration. On a typical consuming repo that's ~1,000 warnings — the\n   * cost-benefit doesn't justify forcing prose comments on every internal\n   * helper.\n   *\n   * - `\"off\"` (default) — the rule is disabled. Consumers rely on\n   *   `tsdoc/syntax`, `jsdoc/check-tag-names`, and `jsdoc/check-types` for\n   *   the comment-quality value `eslint-plugin-jsdoc` actually adds.\n   * - `\"public\"` — the rule is enabled at `warn` level and scoped to\n   *   exported declarations only (`publicOnly: true`). Restores the\n   *   previous behaviour for projects that want it.\n   * - `\"all\"` — the rule is enabled at `warn` level on every function /\n   *   method declaration in `src/**`, public or private. Reserved for\n   *   strict documentation regimes.\n   *\n   * Tests, spec files, and `*.generated.ts` are always excluded.\n   *\n   * @default \"off\"\n   */\n  readonly requireJsdoc?: \"off\" | \"public\" | \"all\";\n}\n\nexport class TypeScriptProject extends typescript.TypeScriptProject {\n  constructor(userOptions: TypeScriptProjectOptions) {\n    /**\n     * Configulator requires every project to live inside a MonorepoProject.\n     * The catalog-based `@types/node` pin and the workspace install hook both\n     * assume the parent exists.\n     */\n    if (!(userOptions.parent instanceof MonorepoProject)) {\n      throw new Error(\n        \"TypeScriptProject must be parented to a MonorepoProject. Pass `parent: <MonorepoProject>` in the project options.\",\n      );\n    }\n\n    const parent = userOptions.parent;\n    const pnpmVersion = parent.pnpmVersion;\n    const pnpmWorkspace = PnpmWorkspace.of(parent);\n\n    /*************************************************************************\n     *\n     * Resolve outdir\n     *\n     * When the caller omits `outdir`, derive it from the scoped package\n     * name (`packageName ?? name`) as `packages/<scope>/<name>`. This\n     * enforces the monorepo-layout contract (ADR-006) without requiring\n     * every sub-project to restate its own path.\n     *\n     ************************************************************************/\n\n    const resolvedOutdir =\n      userOptions.outdir ??\n      resolveTypeScriptProjectOutdir(\n        userOptions.packageName ?? userOptions.name,\n      );\n\n    /*************************************************************************\n     *\n     * Default Options\n     *\n     ************************************************************************/\n\n    const testRunner = userOptions.testRunner ?? TestRunner.JEST;\n    const useJest = testRunner === TestRunner.JEST;\n\n    const defaultOptions: Omit<TypeScriptProjectOptions, \"name\"> & {\n      defaultReleaseBranch: string;\n    } = {\n      /**\n       * This is a standard, so don't require it to passed in everywhere.\n       */\n      defaultReleaseBranch: \"main\",\n\n      /**\n       * Outdir defaults to `packages/<scope>/<name>` when the caller\n       * omits it. Explicit overrides in `userOptions` always win via\n       * the merge below.\n       */\n      outdir: resolvedOutdir,\n\n      /**\n       * Enable reset task by default.\n       */\n      resetTask: true,\n\n      /**\n       * Packaging options\n       */\n      packageManager: NodePackageManager.PNPM,\n      pnpmVersion: pnpmVersion,\n      licensed: userOptions.license !== undefined || false,\n      copyrightOwner: \"CodeDrifters\",\n      release: false,\n\n      /**\n       * Don't add sample code.\n       */\n      sampleCode: false,\n\n      ...(useJest\n        ? {\n            /**\n             * Make sure jest config is stored outside of package.json\n             */\n            jestOptions: {\n              configFilePath: \"jest.config.json\",\n              jestConfig: {\n                roots: [`<rootDir>/src`],\n                transform: {\n                  [\"^.+\\\\.[t]sx?$\"]: new Transform(\"@swc/jest\"),\n                },\n                moduleFileExtensions: [\"js\", \"ts\"],\n              },\n            },\n            /**\n             * SWC for faster testing\n             */\n            devDeps: [\"@swc/jest\", \"@swc/core\"] as string[],\n          }\n        : {\n            jest: false,\n            devDeps: [] as string[],\n          }),\n\n      /**\n       * Turn on prettier formatting\n       */\n      prettier: true,\n\n      /**\n       * Don't package test files.\n       */\n      npmIgnoreOptions: {\n        ignorePatterns: [\"*.spec.*\", \"*.test.*\"],\n      },\n\n      /**\n       * Tests are co-located in `src`, so projen 0.100.4+'s test-directory\n       * tsconfig would only ever create an empty `test/` folder holding a\n       * lone `test/tsconfig.json`. Disable it — the main `tsconfig.json`\n       * already covers the co-located tests for the typescript-eslint\n       * project service (see #830), so a separate dev/test config is dead\n       * weight.\n       */\n      disableTsconfigDev: true,\n\n      /**\n       * Options for the automated dependency upgrade task / workflow\n       * Automatically exclude any packages that are managed by the root\n       * project as default catalog dependencies since we want to let the\n       * catalog manage those dependencies.\n       */\n      depsUpgrade: true,\n      depsUpgradeOptions: {\n        workflow: false,\n        exclude: Object.keys(pnpmWorkspace?.defaultCatalog || {}),\n        ...(userOptions.parent && userOptions.parent instanceof MonorepoProject\n          ? {\n              workflowOptions: {\n                schedule: UpgradeDependenciesSchedule.WEEKLY,\n              },\n              cooldown: 7,\n            }\n          : {}),\n      },\n\n      /**\n       * Only release when the package's own sources or `package.json`\n       * (version, dependencies) change.\n       *\n       * Deliberately narrower than the `\".\"` pathspec the bump decision and\n       * the changelog use below. Widening this to `<outdir>/**` would make\n       * all three filters select exactly the same files, but it also makes\n       * every package-local edit releasable — a test-only change, or the\n       * `.projen/` regeneration that a sibling package's change produces. In\n       * this monorepo that regeneration is routine, so the aligned trigger\n       * publishes versions whose tarballs are byte-identical to the previous\n       * one.\n       *\n       * The asymmetry that remains is benign: a package-local commit outside\n       * `src` cannot start a release on its own, but is still described in\n       * the notes of the next release that something else triggers. Notes\n       * covering slightly more than the trigger is the right direction for\n       * the two to disagree in.\n       */\n      releaseTrigger: ReleaseTrigger.continuous({\n        paths: [`${resolvedOutdir}/src/**`, `${resolvedOutdir}/package.json`],\n      }),\n\n      /**\n       * Scope the other two release filters to the package folder, the same\n       * slice of history the trigger above reads from.\n       *\n       * `versionrcOptions.path` reaches `commit-and-tag-version`, which\n       * forwards it to `conventional-changelog` as a `git log` pathspec —\n       * without it the changelog between two package-scoped tags spans every\n       * commit in the monorepo. `releasableCommits` appends the same pathspec\n       * to the command that decides whether to bump at all; without it a\n       * package with no relevant changes still cuts a release, just with an\n       * empty changelog.\n       *\n       * `\".\"` rather than `resolvedOutdir`: both commands run with their\n       * working directory already set to the package outdir. A single string\n       * is all `path` accepts — `git-raw-commits` splices it into `git log`\n       * as one argv entry (`push(\"--\", path)`), so the pathspec cannot be a\n       * list, so it cannot be narrowed to `src` plus `package.json` to match\n       * the trigger exactly.\n       *\n       * `types` gives every conventional-commit type a visible section. The\n       * preset hides or discards everything but `feat` and `fix` by default,\n       * while still bumping for them, which is what makes a package-local\n       * churn release ship notes holding nothing but a version heading. See\n       * `CHANGELOG_TYPES`.\n       */\n      versionrcOptions: { path: \".\", types: [...CHANGELOG_TYPES] },\n      releasableCommits: ReleasableCommits.everyCommit(\".\"),\n    };\n\n    /*************************************************************************\n     *\n     * Merge defaults into user options\n     *\n     ************************************************************************/\n\n    const mergedOptions = merge(defaultOptions, userOptions);\n\n    const options: TypeScriptProjectOptions &\n      typescript.TypeScriptProjectOptions = {\n      ...mergedOptions,\n\n      /**\n       * `ts-deepmerge` concatenates arrays, so a supplied changelog `types`\n       * arrives appended to `CHANGELOG_TYPES` — and the preset resolves each\n       * commit with `types.find(...)`, so our entry would win every lookup\n       * and the consumer's list would be inert. Replace, don't concatenate.\n       */\n      versionrcOptions: resolveVersionrcOptions(\n        mergedOptions.versionrcOptions,\n        userOptions.versionrcOptions,\n      ),\n    };\n\n    super(options);\n\n    /**\n     * Use catalog version for `@types/node` so all packages share a single\n     * pinned version (overrides projen's default `@types/node@*`).\n     */\n    this.addDevDeps(\"@types/node@catalog:\");\n\n    /**\n     * The main tsconfig now includes co-located `src/**` test files (no\n     * `**\\/*.test.*` exclude) so projen 0.100.4+'s typescript-eslint project\n     * service can resolve them (issue #830). Because `tsc --build` also uses\n     * the main tsconfig, skip type-checking of dependency declaration files\n     * so the compile doesn't fail on test-runner types — Vitest pulls in\n     * Vite's `.d.ts`, which don't type-check under the package's classic\n     * `node` moduleResolution.\n     */\n    this.tsconfig?.file.addOverride(\"compilerOptions.skipLibCheck\", true);\n\n    /**\n     * When using Jest, remove ts-jest since we use `@swc/jest`.\n     * When using Vitest, add the Vitest component (test task + config + deps).\n     */\n    if (options.testRunner === TestRunner.VITEST) {\n      new Vitest(this, {\n        ...options.vitestOptions,\n        config: {\n          include: [\"src/**/*.{test,spec}.?(c|m)[jt]s?(x)\"],\n          ...options.vitestOptions?.config,\n        },\n      });\n    } else {\n      this.deps.removeDependency(\"ts-jest\");\n    }\n\n    /**\n     * Specify package manager\n     */\n    this.package.file.addOverride(\n      \"packageManager\",\n      `pnpm@${options.pnpmVersion}`,\n    );\n\n    /**\n     * Mark the package private unless it is actually released to a\n     * registry. Removing `releaseToNpm` deletes the release workflow but\n     * leaves a package anyone with scope auth can `npm publish` by hand;\n     * `\"private\": true` makes npm itself refuse. Pass\n     * `packagePrivate: false` to opt out.\n     */\n    applyPackagePrivate(this, options);\n\n    /**\n     *\n     * Disable this rule for all test files.\n     *\n     * Unless we turn this off, ESLint will suggest that anything found in a test\n     * needs to be a dep instead of a devDep. Projen actually already turns off\n     * the rule for files in the tests/* folder but since we commonly put tests\n     * next to the code it's testing, we need to do this ourselves.\n     *\n     */\n    this.eslint?.addOverride({\n      files: [\"**/*.test.*\", \"**/*.spec.*\"],\n      rules: {\n        \"import/no-extraneous-dependencies\": \"off\",\n      },\n    });\n\n    /**\n     * TSDoc / public-export documentation enforcement. Wires\n     * `eslint-plugin-tsdoc` (for the `tsdoc/syntax` rule) and\n     * `eslint-plugin-jsdoc` into the shared ESLint config.\n     *\n     * `tsdoc/syntax` ships as a warning. `jsdoc/require-jsdoc` defaults\n     * to off — see the `requireJsdoc` option on\n     * {@link TypeScriptProjectOptions} to opt back in.\n     */\n    this.addDevDeps(\"eslint-plugin-tsdoc\", \"eslint-plugin-jsdoc\");\n    this.eslint?.addPlugins(\"tsdoc\", \"jsdoc\");\n    this.eslint?.addRules({\n      \"tsdoc/syntax\": \"warn\",\n    });\n\n    /**\n     * Apply the requireJsdoc knob. The default is `\"off\"`, matching the\n     * lint-noise mitigation in issue #645 — `jsdoc/require-jsdoc` was\n     * firing on every un-documented function in consuming code (~1,000\n     * warnings per build). Consumers that want the previous behaviour\n     * pass `requireJsdoc: \"public\"` to scope it to exports only.\n     */\n    const requireJsdoc = options.requireJsdoc ?? \"off\";\n    if (requireJsdoc !== \"off\") {\n      const publicOnly = requireJsdoc === \"public\";\n      this.eslint?.addOverride({\n        files: [\"src/**/*.ts\"],\n        excludedFiles: [\"**/*.test.*\", \"**/*.spec.*\", \"**/*.generated.ts\"],\n        rules: {\n          \"jsdoc/require-jsdoc\": [\n            \"warn\",\n            {\n              publicOnly,\n              require: {\n                FunctionDeclaration: true,\n                ClassDeclaration: true,\n              },\n              ...(publicOnly\n                ? {\n                    contexts: [\n                      \"ExportNamedDeclaration > FunctionDeclaration\",\n                      \"ExportNamedDeclaration > ClassDeclaration\",\n                      \"ExportNamedDeclaration > VariableDeclaration\",\n                      \"ExportNamedDeclaration > TSInterfaceDeclaration\",\n                      \"ExportNamedDeclaration > TSTypeAliasDeclaration\",\n                      \"ExportNamedDeclaration > TSEnumDeclaration\",\n                    ],\n                  }\n                : {}),\n              checkConstructors: false,\n              checkGetters: false,\n              checkSetters: false,\n              enableFixer: false,\n            },\n          ],\n        },\n      });\n    }\n\n    /**\n     * Emit `tsdoc.json` so `eslint-plugin-tsdoc` recognises workspace\n     * scopes (`@codedrifters`, `@openhi`, etc.) and common JSDoc\n     * convention tags (`@default`, `@experimental`, etc.). Without this,\n     * downstream consumers see ~1,250 `tsdoc-at-sign-in-word` warnings\n     * and ~17 `tsdoc-undefined-tag` warnings per build.\n     *\n     * Pass `tsdocConfig: false` to opt out (the file is not emitted and\n     * the lint warnings return at full volume).\n     */\n    if (options.tsdocConfig !== false) {\n      new TsdocConfig(\n        this,\n        typeof options.tsdocConfig === \"object\" ? options.tsdocConfig : {},\n      );\n    }\n\n    /**\n     * Wire `@microsoft/api-extractor` so the docs-sync pipeline can\n     * produce a public-API rollup per package for drift detection.\n     * Rollups are regenerated on scan (not committed to git) per the\n     * docs-sync epic resolved decision #3. Pass `apiExtractor: false`\n     * to opt out.\n     */\n    if (options.apiExtractor !== false) {\n      new ApiExtractor(\n        this,\n        typeof options.apiExtractor === \"object\" ? options.apiExtractor : {},\n      );\n    }\n\n    /**\n     * Some standard ignores for all projects.\n     */\n    this.gitignore?.addPatterns(\".DS_Store\", \"test-reports\");\n    this.npmignore?.addPatterns(\"*.spec.*\", \"*.test.*\", \"__fixtures__\");\n\n    /**\n     * If turbo is active in the parent project, configure it here.\n     */\n    const turboActive =\n      userOptions.parent && TurboRepo.of(userOptions.parent) !== undefined;\n    if (turboActive) {\n      const turbo = new TurboRepo(this);\n      turbo.compileTask?.outputs.push(\"dist/**\");\n      turbo.compileTask?.outputs.push(\"lib/**\");\n      //turbo.testTask?.inputs.push(\"src/**\");\n    }\n\n    /**\n     * AI agent configuration — opt-in per project. Does not propagate from\n     * parent MonorepoProject, so sub-projects don't render duplicate\n     * `.cursor/` / `.claude/` / `CLAUDE.md` files into their own outdir.\n     */\n    if (\n      options.agentConfig === true ||\n      typeof options.agentConfig === \"object\"\n    ) {\n      new AgentConfig(\n        this,\n        typeof options.agentConfig === \"object\" ? options.agentConfig : {},\n      );\n    }\n\n    /**\n     * Add reset task if enabled.\n     */\n    if (options.resetTask !== false) {\n      const defaultResetTaskOptions: ResetTaskOptions = {\n        pathsToRemove: [\n          \"node_modules\",\n          \"dist\",\n          \"lib\",\n          \"coverage\",\n          \"test-reports\",\n          \".turbo\",\n          \"tsconfig.tsbuildinfo\",\n          this.artifactsDirectory,\n        ],\n      };\n      const userResetTaskOptions = options.resetTaskOptions ?? {};\n      const resetTaskOptions: ResetTaskOptions = merge(\n        defaultResetTaskOptions,\n        {\n          ...userResetTaskOptions,\n          pathsToRemove: [\n            ...(defaultResetTaskOptions.pathsToRemove ?? []),\n            ...(userResetTaskOptions.pathsToRemove ?? []),\n          ],\n        },\n      );\n      new ResetTask(this, resetTaskOptions);\n    }\n\n    /**\n     *\n     */\n\n    if (options.parent && options.parent instanceof MonorepoProject) {\n      // Install dependencies via the parent project\n      /* @ts-ignore access private method */\n      const originalResolve = this.package.resolveDepsAndWritePackageJson;\n      /* @ts-ignore access private method */\n      this.package.installDependencies = () => {\n        (options.parent as MonorepoProject).requestInstallDependencies({\n          resolveDepsAndWritePackageJson: () =>\n            originalResolve.apply(this.package),\n        });\n      };\n      /* @ts-ignore access private method */\n      this.package.resolveDepsAndWritePackageJson = () => {};\n    }\n  }\n}\n","/**\n * Changelog `types` shared by every configulator project that releases.\n *\n * `commit-and-tag-version` defaults to the **conventionalcommits** preset,\n * whose stock type list marks `chore`, `docs`, `style`, `refactor`, `perf`\n * and `test` as `hidden` and has no entry at all for `build`, `ci` or\n * `revert`. Only `feat` and `fix` produce a visible section, so a release\n * whose range holds nothing else ships notes containing just the version\n * heading.\n *\n * That emptiness is not cosmetic. Hiding is a changelog-*writer* concern and\n * never reaches the bump decision: the preset's `whatBump` starts at patch\n * and only moves up for a `feat` or a breaking change — it has no \"no bump\"\n * outcome. The only thing that yields `bump: none` is `releasableCommits`\n * returning an empty list. A range of nothing but `chore:` commits therefore\n * publishes a patch release that cannot say why it exists.\n *\n * Listing every type with a section makes the notes account for the whole\n * range instead. It deliberately does not change any version number — the\n * bump ignores `types` entirely.\n */\nexport const CHANGELOG_TYPES: readonly ChangelogType[] = [\n  { type: \"feat\", section: \"Features\" },\n  { type: \"fix\", section: \"Bug Fixes\" },\n  { type: \"perf\", section: \"Performance Improvements\" },\n  { type: \"revert\", section: \"Reverts\" },\n  { type: \"refactor\", section: \"Code Refactoring\" },\n  { type: \"docs\", section: \"Documentation\" },\n  { type: \"test\", section: \"Tests\" },\n  { type: \"build\", section: \"Build System\" },\n  { type: \"ci\", section: \"Continuous Integration\" },\n  { type: \"style\", section: \"Styles\" },\n  { type: \"chore\", section: \"Miscellaneous Chores\" },\n];\n\n/**\n * One entry in a changelog `types` list.\n */\nexport interface ChangelogType {\n  /**\n   * The conventional-commit type this entry matches, e.g. `\"feat\"`.\n   */\n  readonly type: string;\n\n  /**\n   * Heading the matching commits are grouped under. Section order in the\n   * rendered notes follows the order of the list itself.\n   */\n  readonly section?: string;\n\n  /**\n   * Whether to omit matching commits from the notes. Omitted entirely by\n   * `CHANGELOG_TYPES` — every type it lists is visible.\n   */\n  readonly hidden?: boolean;\n}\n\n/**\n * Resolve `versionrcOptions` for a project, given the already-merged options\n * and what the consumer actually passed.\n *\n * `ts-deepmerge` concatenates arrays rather than replacing them, so a\n * consumer-supplied `types` would arrive appended to `CHANGELOG_TYPES`. The\n * preset resolves a commit's entry with `types.find(...)`, so the default\n * entry would win every lookup and the consumer's list would be silently\n * inert. A supplied list replaces ours outright instead.\n *\n * Replacing is also the safer half of the trade: a consumer who passes a\n * partial list gets exactly that list, which is visibly wrong the first time\n * they look at their notes, rather than a silently ignored override.\n */\nexport function resolveVersionrcOptions(\n  merged: Record<string, any> | undefined,\n  userSupplied: Record<string, any> | undefined,\n): Record<string, any> | undefined {\n  if (!userSupplied?.types) {\n    return merged;\n  }\n\n  return { ...merged, types: userSupplied.types };\n}\n","import { BuildWorkflowOptions } from \"projen/lib/build\";\nimport { WorkflowSteps } from \"projen/lib/github\";\nimport { JobStep } from \"projen/lib/github/workflows-model\";\nimport {\n  NodePackageManager,\n  PnpmOptions,\n  UpgradeDependenciesSchedule,\n} from \"projen/lib/javascript\";\nimport {\n  TypeScriptAppProject,\n  TypeScriptProjectOptions,\n} from \"projen/lib/typescript\";\nimport { merge } from \"ts-deepmerge\";\nimport {\n  formatLayoutViolation,\n  formatStarlightSingletonViolation,\n  LAYOUT_ENFORCEMENT,\n  type LayoutEnforcement,\n  validateMonorepoLayout,\n  validateStarlightSingleton,\n} from \"./monorepo-layout\";\nimport { Nvmrc } from \"./nvmrc\";\nimport { applyPackagePrivate, PackagePrivateOptions } from \"./package-private\";\nimport { ProjectMetadata } from \"./project-metadata\";\nimport { ProjectMetadataOptions } from \"./project-metadata-options\";\nimport { AgentConfig } from \"../agent/agent-config\";\nimport { AgentConfigOptions } from \"../agent/agent-config-options\";\nimport { PnpmWorkspace, PnpmWorkspaceOptions } from \"../pnpm/pnpm-workspace\";\nimport { ResetTask, ResetTaskOptions } from \"../tasks/reset-task\";\nimport {\n  ROOT_CI_TASK_NAME,\n  TurboRepo,\n  TurboRepoOptions,\n} from \"../turbo/turbo-repo\";\nimport { VERSION } from \"../versions\";\nimport { VSCodeConfig } from \"../vscode/vscode\";\nimport {\n  addApproveMergeUpgradeWorkflow,\n  type ApproveMergeUpgradeOptions,\n} from \"../workflows/approve-merge-upgrade\";\nimport { addBuildCompleteJob } from \"../workflows/build-complete-job\";\nimport { includeHiddenFilesInBuildArtifact } from \"../workflows/include-hidden-files-in-build-artifact\";\nimport { pinPnpmActionSetup } from \"../workflows/pin-pnpm-action-setup\";\nimport { pinSetupNodeVersion } from \"../workflows/pin-setup-node-version\";\nimport {\n  RequirementIssueTemplate,\n  type RequirementIssueTemplateOptions,\n} from \"../workflows/requirement-issue-template\";\nimport {\n  addSyncLabelsWorkflow,\n  type SyncLabelsOptions,\n} from \"../workflows/sync-labels\";\n\nconst CONFIGULATOR_PACKAGE_NAME = \"@codedrifters/configulator\";\n\n/**\n * Step-level env that opts an upgrade-workflow step out of CI mode.\n *\n * GitHub Actions always sets `CI=true`, which makes projen's\n * `NodePackage.postSynthesize` pick the **frozen** `install:ci` task\n * (`pnpm i --frozen-lockfile`) for its synth-time install. That is wrong for\n * a step whose whole job is to move dependencies forward: synth rewrites\n * `pnpm-workspace.yaml`'s `catalog:` from `versions.ts`, so the freshly\n * written workspace no longer matches the lockfile's `catalogs` block and the\n * frozen install dies with `ERR_PNPM_LOCKFILE_CONFIG_MISMATCH`. The upgrade\n * job then produces no patch, the consumer's lockfile never advances, and\n * every subsequent scheduled run re-hits the same wall with a larger gap.\n *\n * The value must be the literal string `\"false\"`, **not** `\"0\"`:\n *\n * - projen's `isTruthy` treats both `\"0\"` and `\"false\"` as falsy, so either\n *   would satisfy projen's `isAutomatedBuild` check on its own.\n * - pnpm's CI detection (ci-info) bypasses **only** on `env.CI !== \"false\"` —\n *   the string `\"0\"` is truthy there. With `CI=0`, pnpm's pre-exec\n *   `verifyDepsBeforeRun` deps-status check still spawns a *frozen*\n *   `pnpm install` before projen even starts, and fails identically.\n *\n * `\"false\"` is the only value that satisfies both tools. Do not \"simplify\" it\n * to `\"0\"` — projen's own `upgrade` task uses `CI: \"0\"`, but it does not have\n * to survive pnpm's pre-run deps check the way these steps do.\n *\n * Applied at **step** level rather than job level to keep the override\n * surgical: only the steps that legitimately mutate the lockfile opt out of\n * CI mode, while the projen-generated steps around them keep Actions'\n * default `CI=true`.\n *\n * `Run subproject upgrades` needs this as much as `Synthesize` does — it is\n * inserted for consumers and non-consumers alike, and pnpm's pre-run deps\n * check re-runs a frozen install there whenever the lockfile is still stale.\n *\n * This complements — and does not replace — `installDependenciesNonFrozen()`,\n * which covers the other synth-time install path (see #570).\n *\n * @see https://github.com/codedrifters/packages/issues/1006\n * @see https://github.com/codedrifters/packages/issues/570\n */\nconst NON_CI_STEP_ENV: Record<string, string> = { CI: \"false\" };\n\n/*******************************************************************************\n *\n * Monorepo Root Project.\n *\n * This project should be used as the base project for other projects in a\n * monorepo. The Monorepo root project generally won't contain any code, but it\n * will contain configuration for the monorepo, such as package management,\n * linting, testing, and other project-wide settings.\n *\n ******************************************************************************/\n\nexport interface IDependencyResolver {\n  resolveDepsAndWritePackageJson(): boolean;\n}\n\n/**\n * Consolidated PNPM options for the monorepo.\n *\n * Extends projen's native {@link PnpmOptions} (so projen's `workspaceYamlOptions`\n * stays available and type-compatible with the inherited\n * `TypeScriptProjectOptions.pnpmOptions`) and adds configulator's\n * monorepo-specific controls. Configulator's `PnpmWorkspace` component remains\n * the single writer of `pnpm-workspace.yaml`; see `src/pnpm/pnpm-workspace.ts`.\n */\nexport interface MonorepoPnpmOptions extends PnpmOptions {\n  /**\n   * Options for the monorepo workspace file (`pnpm-workspace.yaml`).\n   */\n  pnpmWorkspaceOptions?: PnpmWorkspaceOptions;\n}\n\n/**\n * Configuration options for the monorepo.\n */\nexport interface MonorepoProjectOptions\n  extends\n    Omit<TypeScriptProjectOptions, \"defaultReleaseBranch\">,\n    PackagePrivateOptions {\n  /**\n   * Turn on Turborepo support.\n   *\n   * @default true\n   */\n  turbo?: boolean;\n\n  /**\n   * Optionsal options for turborepo config\n   */\n  turboOptions?: TurboRepoOptions;\n\n  /**\n   * Steps to run in `build.yml` after the projen build, replacing the default\n   * \"Build Sub Projects\" step that runs `pnpm exec projen build:all`.\n   *\n   * When omitted, behavior is unchanged: a single step runs the root\n   * `build:all` task. Useful for repos whose CI wants a cheaper PR-time\n   * check than the full turbo build (e.g. an Astro `sync` + `check`).\n   *\n   * The follow-on `Upload Turbo runs` artifact step is always emitted and\n   * is a no-op when `.turbo/runs` is absent.\n   *\n   * @default - one step: `pnpm exec projen build:all`\n   */\n  readonly ciBuildSteps?: Array<JobStep>;\n\n  /**\n   * Enable the reset task that deletes all build artifacts.\n   *\n   * @default true\n   */\n  resetTask?: boolean;\n\n  /**\n   * Options for the reset task.\n   */\n  resetTaskOptions?: ResetTaskOptions;\n\n  /**\n   * PNPM options for the monorepo.\n   */\n  pnpmOptions?: MonorepoPnpmOptions;\n\n  /**\n   * When set, adds the approve-and-merge-upgrade workflow (ADR 0001 §2).\n   * Uses a second GitHub App to approve and merge the dependency-upgrade PR\n   * when it has the auto-approve label and head branch matches. Trigger types\n   * exclude `opened` to prevent double approval.\n   *\n   * @see ApproveMergeUpgradeOptions\n   */\n  readonly approveMergeUpgradeOptions?: ApproveMergeUpgradeOptions;\n\n  /**\n   * Whether this monorepo consumes `@codedrifters/configulator` from a registry (npm).\n   * When true, the upgrade workflow adds steps to sync configulator and synthesize.\n   * Set to false when configulator is developed in this repo (e.g. workspace dependency).\n   *\n   * @default true\n   */\n  readonly configulatorRegistryConsumer?: boolean;\n\n  /**\n   * Project metadata configuration. Provides repository identity,\n   * GitHub project context, and organizational details consumed by\n   * AgentConfig and other features at synthesis time.\n   *\n   * - `undefined` or `{}`: auto-instantiate with auto-detection (default)\n   * - `ProjectMetadataOptions`: explicit metadata configuration\n   * - `false`: disable ProjectMetadata entirely\n   *\n   * @default `{}` (auto-detect from package.json)\n   */\n  readonly projectMetadata?: ProjectMetadataOptions | false;\n\n  /**\n   * AI agent configuration (Cursor, Claude Code rules).\n   * Generates rule files at the monorepo root with auto-detected bundles\n   * based on project and subproject introspection.\n   *\n   * - `true` or `{}`: enable with auto-detected defaults\n   * - `AgentConfigOptions`: enable with explicit configuration\n   * - `false` or `undefined`: disabled (default)\n   *\n   * @default false\n   */\n  readonly agentConfig?: AgentConfigOptions | boolean;\n\n  /**\n   * Sync GitHub labels from a config file using EndBug/label-sync.\n   * Generates `.github/labels.yml` and a sync workflow.\n   *\n   * - `true` or `undefined`: enable with default priority labels (default)\n   * - `SyncLabelsOptions`: enable with custom label configuration\n   * - `false`: disable label syncing\n   *\n   * @default true\n   */\n  readonly syncLabels?: SyncLabelsOptions | boolean;\n\n  /**\n   * Emit a GitHub markdown issue template\n   * (`.github/ISSUE_TEMPLATE/requirement-impl.md`) carrying the canonical\n   * cross-repo `## Requirement` traceability block (ID, spec URL, tier,\n   * customer) plus a prompt to add a `req:<ID>` label.\n   *\n   * Opt-in — **off by default**. Enable it on code repositories whose\n   * issues trace back to canonical requirements maintained in a separate\n   * planning repo, so a human filing an implementation issue records the\n   * same requirement metadata a fan-out bot would. Repos with no\n   * requirement-traceability story leave it off and emit no template.\n   *\n   * - `true`: enable with defaults (template at the default path,\n   *   `type:feat` front-matter label).\n   * - `RequirementIssueTemplateOptions`: enable with a custom output path\n   *   and/or front-matter labels.\n   * - `false` or `undefined`: disabled (default) — no issue template file\n   *   is emitted.\n   *\n   * @default false\n   * @see docs/src/content/docs/packages/\\@codedrifters/configulator/requirement-traceability.md\n   */\n  readonly requirementIssueTemplate?: RequirementIssueTemplateOptions | boolean;\n\n  /**\n   * How to react when a sub-project's `outdir` falls outside the root\n   * expected for its project type (ADR-006 §4).\n   *\n   * - `\"off\"` — skip validation entirely.\n   * - `\"warn\"` — log a console warning per violation; synth proceeds.\n   * - `\"error\"` — throw on the first violation; synth fails.\n   *\n   * Defaults to `\"warn\"` during the ADR-006 rollout so existing consumers\n   * with legacy outdirs see actionable warnings but do not break. A future\n   * release will flip the default to `\"error\"`.\n   *\n   * @default \"warn\"\n   * @see docs/src/content/docs/requirements/architectural-decisions/ADR-006-monorepo-layout.md\n   */\n  readonly layoutEnforcement?: LayoutEnforcement;\n}\n\n// Intersection (not `extends`) so the `pnpmOptions` types from projen and\n// configulator merge coherently: `PnpmOptions & MonorepoPnpmOptions` resolves\n// to `MonorepoPnpmOptions` (which extends `PnpmOptions`) rather than tripping\n// the \"not identical\" interface-extension error.\ntype AppliedOptions = TypeScriptProjectOptions & MonorepoProjectOptions;\n\n/**\n * Per-instance list of post-install dependency resolvers. Stored in a WeakMap\n * so MonorepoProject has no private instance property and its type remains\n * structural across package versions (avoids TS2322 when two configulator\n * versions are in the dependency tree).\n */\nconst postInstallDependenciesMap = new WeakMap<\n  MonorepoProject,\n  Array<() => boolean>\n>();\n\nexport class MonorepoProject extends TypeScriptAppProject {\n  /**\n   * Version of PNPM which the whole monorepo should use.\n   */\n  readonly pnpmVersion: string;\n\n  /**\n   * Whether this monorepo consumes configulator from a registry (drives upgrade workflow steps).\n   */\n  readonly configulatorRegistryConsumer: boolean;\n\n  /**\n   * Layout-enforcement mode for sub-project `outdir` validation (ADR-006).\n   */\n  readonly layoutEnforcement: LayoutEnforcement;\n\n  constructor(userOptions: MonorepoProjectOptions) {\n    /***************************************************************************\n     *\n     * BUILD WORKFLOW OPTIONS\n     *\n     * discover some turbo options for build workflow, if needed.\n     *\n     **************************************************************************/\n\n    const buildWorkflowOptions: Partial<BuildWorkflowOptions> = userOptions\n      .turboOptions?.remoteCacheOptions\n      ? TurboRepo.buildWorkflowOptions(\n          userOptions.turboOptions.remoteCacheOptions,\n        )\n      : {};\n\n    /***************************************************************************\n     *\n     * DEFAULT OPTIONS\n     *\n     * These are the default options unless you override with option inputs.\n     *\n     **************************************************************************/\n\n    const defaultOptions: Omit<\n      MonorepoProjectOptions,\n      \"name\" | \"defaultReleaseBranch\"\n    > = {\n      /**\n       * Use typescript based config file.\n       */\n      projenrcTs: true,\n\n      /**\n       * Projen version should be pinned to the local specified version.\n       */\n      projenVersion: \"catalog:\",\n\n      /**\n       * Use Prettier for code formatting.\n       */\n      prettier: true,\n\n      /**\n       * Not licensed by default.\n       */\n      licensed: false,\n\n      /**\n       * GitHub options for the monorepo.\n       * Don't enable mergify by default.\n       */\n      githubOptions: {\n        mergify: false,\n\n        /**\n         * Configure pull request linting to validate PR titles follow Conventional Commits.\n         * By default, all conventional commit types are allowed, providing flexibility\n         * for different types of changes (features, fixes, documentation, refactoring, etc.).\n         */\n        pullRequestLintOptions: {\n          semanticTitleOptions: {\n            /**\n             * Allowed conventional commit types for PR titles.\n             * This includes all standard types from the Conventional Commits specification:\n             * - feat: New features\n             * - fix: Bug fixes\n             * - docs: Documentation changes\n             * - style: Code style changes (formatting, etc.)\n             * - refactor: Code refactoring\n             * - perf: Performance improvements\n             * - test: Test additions or changes\n             * - build: Build system changes\n             * - ci: CI configuration changes\n             * - chore: Maintenance tasks\n             * - revert: Revert commits\n             */\n            types: [\n              \"feat\",\n              \"fix\",\n              \"docs\",\n              \"style\",\n              \"refactor\",\n              \"perf\",\n              \"test\",\n              \"build\",\n              \"ci\",\n              \"chore\",\n              \"revert\",\n            ],\n          },\n        },\n      },\n\n      /**\n       * Default PNPM version to use in the monorepo.\n       */\n      pnpmVersion: VERSION.PNPM_VERSION,\n\n      /**\n       * Node.js version used in GitHub Actions workflows (build, upgrade, etc.).\n       * Pinning this inserts an `actions/setup-node` step before dependency\n       * install so CI does not fall back to whatever Node the `ubuntu-latest`\n       * runner ships with (currently Node 20.x, which is below the floor\n       * required by Astro 6 / Starlight).\n       *\n       * @see {@link VERSION.NODE_WORKFLOWS}\n       */\n      workflowNodeVersion: VERSION.NODE_WORKFLOWS,\n\n      /**\n       * By default treat as a registry consumer (upgrade workflow syncs configulator).\n       */\n      configulatorRegistryConsumer: true,\n\n      /**\n       * ADR-006 layout enforcement defaults to \"warn\" during rollout so\n       * legacy outdirs log actionable warnings but do not break synth.\n       */\n      layoutEnforcement: LAYOUT_ENFORCEMENT.WARN,\n\n      /**\n       * We don't want sample code generated for the root project.\n       */\n      sampleCode: false,\n\n      /**\n       * Jest is not required in the root project.\n       */\n      jest: false,\n\n      /**\n       * Don't release the root project.\n       */\n      release: false,\n\n      /**\n       * Uppgrade dependencies automatically unless otherwise instructed.\n       * Exclude `@codedrifters/configulator` so the default upgrade task does not\n       * upgrade it (version is often managed in-repo or via a separate sync step).\n       */\n      depsUpgrade: true,\n      depsUpgradeOptions: {\n        exclude: [\"@codedrifters/configulator\"],\n        workflowOptions: {\n          schedule: UpgradeDependenciesSchedule.DAILY,\n        },\n        cooldown: 7,\n      },\n\n      /**\n       * Disable tsconfig.dev.json in the root since we aren't going to be\n       * developing any code here. It's just a task runner and configuration\n       * tool for sub-projects.\n       */\n      disableTsconfigDev: true,\n\n      /**\n       * Kill the srcdir in the root since we aren't using one. Projen's\n       * default `tsconfig.include` still points at `src/**\\/*.ts`, so\n       * callers that want to treat the monorepo root as a pure shell\n       * should see an empty include — consumers add their own entries via\n       * `tsconfig.addInclude(...)` (e.g. `.projenrc.ts`, `projenrc/**\\/*.ts`).\n       */\n      tsconfig: {\n        compilerOptions: {\n          rootDir: undefined,\n        },\n        exclude: [\"node_modules\"],\n      },\n\n      /**\n       * Enable turborepo by default.\n       */\n      turbo: true,\n\n      /**\n       * Enable reset task by default.\n       */\n      resetTask: true,\n\n      /**\n       * Include self as a devDep\n       */\n      devDeps: [\"@codedrifters/configulator\"],\n\n      /**\n       * PNPM options for the monorepo.\n       */\n      pnpmOptions: {\n        pnpmWorkspaceOptions: {\n          defaultCatalog: {\n            [\"@types/node\"]: VERSION.TYPES_NODE_VERSION,\n            [\"aws-cdk\"]: VERSION.AWS_CDK_CLI_VERSION,\n            [\"aws-cdk-lib\"]: VERSION.AWS_CDK_LIB_VERSION,\n            [\"projen\"]: VERSION.PROJEN_VERSION,\n            [\"constructs\"]: VERSION.AWS_CONSTRUCTS_VERSION,\n            [\"turbo\"]: VERSION.TURBO_VERSION,\n            /**\n             * `@vitest/coverage-v8` declares an exact `vitest` peer\n             * dependency, so both track one constant.\n             */\n            [\"vitest\"]: VERSION.VITEST_VERSION,\n            [\"@vitest/coverage-v8\"]: VERSION.VITEST_VERSION,\n          },\n        },\n      },\n    };\n\n    /***************************************************************************\n     *\n     * REQUIRED OPTIONS\n     *\n     * These options cannot be changed by the user.\n     *\n     **************************************************************************/\n\n    const requiredOptions: Omit<TypeScriptProjectOptions, \"name\"> = {\n      /**\n       * This is required because it's standard practice and also to simplify\n       * some workflow design.\n       */\n      defaultReleaseBranch: \"main\",\n\n      /**\n       * Use PNPM instead of the default (Yarn). Much of the ecosystem depends\n       * on PNPM and making monorepos PNPM only simplifies many configurations.\n       */\n      packageManager: NodePackageManager.PNPM,\n\n      /**\n       * Some additional pre-build steps if we're using turbo's remote cache.\n       * Set GIT_BRANCH_NAME so Turborepo remote cache hashes match between local and CI.\n       */\n      buildWorkflowOptions: {\n        env: {\n          GIT_BRANCH_NAME: \"${{ github.head_ref || github.ref_name }}\",\n          ...buildWorkflowOptions?.env,\n          ...userOptions.buildWorkflowOptions?.env,\n        },\n        permissions: {\n          ...buildWorkflowOptions?.permissions,\n          ...userOptions.buildWorkflowOptions?.permissions,\n        },\n        preBuildSteps: [\n          ...(buildWorkflowOptions?.preBuildSteps ?? []),\n          ...(userOptions.buildWorkflowOptions?.preBuildSteps ?? []),\n        ],\n      },\n    };\n\n    /***************************************************************************\n     *\n     * CONSTRUCTOR\n     *\n     * Combines default options with user provided options and required options.\n     * Store the options in a const so we can use them after super(), farther\n     * into the constructor for additional configuration.\n     *\n     **************************************************************************/\n\n    const options: AppliedOptions = merge(\n      defaultOptions,\n      userOptions,\n      requiredOptions,\n    );\n\n    super({ ...options });\n\n    postInstallDependenciesMap.set(this, []);\n\n    /**\n     * Projen's TypeScriptProject seeds `tsconfig.include` with\n     * `<srcdir>/**\\/*.ts` by default. MonorepoProject is a shell with no\n     * srcdir, so drop that entry — consumers add their own includes (e.g.\n     * `.projenrc.ts`, `projenrc/**\\/*.ts`) via `this.tsconfig?.addInclude`.\n     */\n    this.tsconfig?.removeInclude(`${this.srcdir}/**/*.ts`);\n\n    /**\n     * Drop the root `tsconfig.tsbuildinfo` before every compile (#656).\n     *\n     * The root compiles with `tsc --build`, whose incremental\n     * `.tsbuildinfo` survives dependency bumps. When a dependency ships a\n     * regressed `.d.ts` rollup, a stale buildinfo lets the root's type-check\n     * pass locally against the old signatures while cold CI (no buildinfo)\n     * fails — the failure only surfaces after merge. Deleting the buildinfo\n     * up front forces `tsc --build` to re-check against the current\n     * `node_modules` on every compile. The root compiles only projenrc, so\n     * the lost incrementality is negligible.\n     *\n     * Interpreter-safe form: this runs under projen's built-in cross-platform\n     * shell (no command substitution), matching the guarded-`rm` idiom in\n     * `src/tasks/reset-task.ts`.\n     */\n    this.preCompileTask.exec(\n      '[ -e \"tsconfig.tsbuildinfo\" ] && rm -f tsconfig.tsbuildinfo || true',\n    );\n\n    /***************************************************************************\n     *\n     * PUBLIC PROPS\n     *\n     * Some props are hidden by Projen and we need to expose them for the\n     * monorepo to work properly. This is where we store them.\n     *\n     **************************************************************************/\n\n    this.pnpmVersion = options.pnpmVersion!;\n    this.configulatorRegistryConsumer =\n      options.configulatorRegistryConsumer ?? true;\n    this.layoutEnforcement =\n      options.layoutEnforcement ?? LAYOUT_ENFORCEMENT.WARN;\n\n    /***************************************************************************\n     *\n     * CUSTOM CONFIGS\n     *\n     * We add some additional configurations to the monorepo root project below\n     * such as Turborepo, VS Code config, and the PNPM workspace file.\n     *\n     **************************************************************************/\n\n    /**\n     * Add VSCode configuration\n     */\n    new VSCodeConfig(this);\n\n    /**\n     * Emit `.nvmrc` at the monorepo root so local dev installs the\n     * same Node version every CI workflow uses\n     * ({@link VERSION.NODE_WORKFLOWS}).\n     */\n    new Nvmrc(this);\n\n    /**\n     * Add workspace definition to PNPM root\n     */\n    new PnpmWorkspace(this, options.pnpmOptions?.pnpmWorkspaceOptions);\n\n    /**\n     * Turn on turborepo support if requested.\n     */\n    if (options.turbo) {\n      new TurboRepo(this, options.turboOptions);\n\n      const defaultBuildSubProjectsStep: JobStep = {\n        name: \"Build Sub Projects\",\n        run: `pnpm exec projen ${ROOT_CI_TASK_NAME}`,\n      };\n      const buildSubProjectsSteps: Array<JobStep> = options.ciBuildSteps ?? [\n        defaultBuildSubProjectsStep,\n      ];\n\n      this.buildWorkflow?.addPostBuildSteps(\n        ...buildSubProjectsSteps,\n        WorkflowSteps.uploadArtifact({\n          name: \"Upload Turbo runs\",\n          if: \"always()\",\n          continueOnError: true,\n          with: {\n            name: \"turbo-runs\",\n            path: \".turbo/runs\",\n          },\n        }),\n      );\n    }\n\n    /**\n     * Add reset task if enabled.\n     */\n    if (options.resetTask !== false) {\n      const defaultResetTaskOptions: ResetTaskOptions = {\n        pathsToRemove: [\n          \"node_modules\",\n          \".turbo\",\n          \"dist\",\n          \"lib\",\n          // Root reset must also drop the incremental buildinfo (#656) so a\n          // stale `.tsbuildinfo` can't hide a regressed dependency `.d.ts`\n          // rollup from the next compile. Sub-projects already clean this.\n          \"tsconfig.tsbuildinfo\",\n        ],\n      };\n      const userResetTaskOptions = options.resetTaskOptions ?? {};\n      const resetTaskOptions: ResetTaskOptions = merge(\n        defaultResetTaskOptions,\n        {\n          ...userResetTaskOptions,\n          pathsToRemove: [\n            ...(defaultResetTaskOptions.pathsToRemove ?? []),\n            ...(userResetTaskOptions.pathsToRemove ?? []),\n          ],\n        },\n      );\n      new ResetTask(this, resetTaskOptions);\n    }\n\n    /**\n     * Specify package manager\n     */\n    // const pnpmVersion = options.pnpmVersion ?? VERSION.PNPM_VERSION;\n    this.package.file.addOverride(\n      \"packageManager\",\n      `pnpm@${options.pnpmVersion}`,\n    );\n\n    /**\n     * The monorepo root is a task-runner shell that is never published, so\n     * it renders `\"private\": true` by default. Pass `packagePrivate: false`\n     * to opt out.\n     */\n    applyPackagePrivate(this, options);\n\n    /**\n     * Add some silly things to the gitignore.\n     */\n    this.gitignore?.addPatterns(\".DS_Store\", \"test-reports\");\n\n    /**\n     * Use catalog versions for constructs and `@types/node`\n     */\n    this.addDevDeps(\"constructs@catalog:\", \"@types/node@catalog:\");\n\n    if (options.approveMergeUpgradeOptions) {\n      addApproveMergeUpgradeWorkflow(this, options.approveMergeUpgradeOptions);\n    }\n\n    /**\n     * Project metadata — auto-instantiated unless explicitly disabled.\n     */\n    if (options.projectMetadata !== false) {\n      new ProjectMetadata(\n        this,\n        typeof options.projectMetadata === \"object\"\n          ? options.projectMetadata\n          : {},\n      );\n    }\n\n    /**\n     * Enable AI agent configuration if requested.\n     */\n    if (options.agentConfig) {\n      new AgentConfig(\n        this,\n        typeof options.agentConfig === \"object\" ? options.agentConfig : {},\n      );\n    }\n\n    /**\n     * Sync GitHub labels if enabled. When AgentConfig is present, its\n     * active bundles contribute labels to `.github/labels.yml` so a\n     * bundle can ship the labels its rules depend on.\n     */\n    if (options.syncLabels !== false) {\n      const syncLabelsOptions =\n        typeof options.syncLabels === \"object\" ? options.syncLabels : {};\n      const agentConfig = AgentConfig.of(this);\n      addSyncLabelsWorkflow(this, {\n        ...syncLabelsOptions,\n        bundles: syncLabelsOptions.bundles ?? agentConfig?.activeBundles,\n      });\n    }\n\n    /**\n     * Emit the cross-repo requirement issue template when opted in.\n     * Off by default so repos with no requirement-traceability story\n     * ship no `.github/ISSUE_TEMPLATE/` file.\n     */\n    if (options.requirementIssueTemplate) {\n      new RequirementIssueTemplate(\n        this,\n        typeof options.requirementIssueTemplate === \"object\"\n          ? options.requirementIssueTemplate\n          : {},\n      );\n    }\n\n    /**\n     * Append the \"complete\" gate job to the build workflow (ADR 0004). Requires\n     * build to succeed and all other jobs to succeed or be skipped.\n     */\n    if (this.buildWorkflow) {\n      addBuildCompleteJob(this.buildWorkflow);\n    }\n\n    // Mutate the upgrade workflow job: add subproject upgrade step (always), and\n    // for consumers add sync + synthesize before it. addPostBuildSteps runs too\n    // late because the workflow is created in UpgradeDependencies constructor.\n    const upgradeWorkflow = this.github?.tryFindWorkflow(\"upgrade\");\n    const upgradeJob = upgradeWorkflow?.getJob(\"upgrade\");\n    const jobWithSteps =\n      upgradeJob && \"steps\" in upgradeJob ? upgradeJob : undefined;\n    if (jobWithSteps?.steps && Array.isArray(jobWithSteps.steps)) {\n      // Insert *after* the projen-generated \"Upgrade dependencies\" step.\n      // Looking it up by name keeps us resilient to upstream step shuffles\n      // (e.g. Projen inserting a `Setup Node.js` step when\n      // `workflowNodeVersion` is set).\n      const upgradeStepIndex = jobWithSteps.steps.findIndex(\n        (step) => step.name === \"Upgrade dependencies\",\n      );\n      const insertIndex =\n        upgradeStepIndex >= 0\n          ? upgradeStepIndex + 1\n          : jobWithSteps.steps.length;\n      if (this.configulatorRegistryConsumer) {\n        jobWithSteps.steps.splice(insertIndex, 0, {\n          name: `Sync ${CONFIGULATOR_PACKAGE_NAME} in workspace`,\n          run: `pnpm update -r ${CONFIGULATOR_PACKAGE_NAME}`,\n        });\n        // `env: { CI: \"false\" }` (NOT \"0\") — this step rewrites\n        // pnpm-workspace.yaml's catalog, so it must not run projen's frozen\n        // install:ci. See NON_CI_STEP_ENV above for why \"0\" is insufficient\n        // (#570, #1006). Spread so the two steps do not alias one object.\n        jobWithSteps.steps.splice(insertIndex + 1, 0, {\n          name: \"Synthesize\",\n          run: this.runTaskCommand(this.defaultTask!),\n          env: { ...NON_CI_STEP_ENV },\n        });\n      }\n      // Inserted for consumers and non-consumers alike, and it needs the same\n      // non-CI env: pnpm's pre-run deps check re-runs a frozen install here\n      // whenever the lockfile is still stale (#570, #1006).\n      jobWithSteps.steps.splice(\n        insertIndex + (this.configulatorRegistryConsumer ? 2 : 0),\n        0,\n        {\n          name: \"Run subproject upgrades\",\n          run: \"pnpm -r run upgrade\",\n          env: { ...NON_CI_STEP_ENV },\n        },\n      );\n    }\n  }\n\n  /**\n   * Validate sub-project `outdir` values against the ADR-006 monorepo\n   * layout contract. Runs in `preSynthesize` so all sub-projects are\n   * attached by the time we inspect the tree.\n   *\n   * Two checks run in sequence:\n   *\n   * 1. **Outdir-vs-root validation.** Every sub-project's `outdir` must\n   *    live under the root expected for its project type (ADR-006 §4).\n   * 2. **Docs-singleton validation.** At most one `StarlightProject`\n   *    may carry `role: \"docs\"` (ADR-006 §3).\n   *\n   * Behavior is controlled by `layoutEnforcement`:\n   * - `\"off\"`  — skip both checks.\n   * - `\"warn\"` — log a `console.warn` per violation; continue. Singleton\n   *   violations also warn in this mode rather than throwing, so all\n   *   layout findings are surfaced consistently.\n   * - `\"error\"` — throw on the first outdir violation, or on the\n   *   singleton violation if outdir validation passed.\n   */\n  public preSynthesize() {\n    super.preSynthesize();\n\n    /**\n     * Pin every `pnpm/action-setup` step across every workflow on this\n     * project's GitHub component to {@link VERSION.PNPM_ACTION_SETUP_VERSION}.\n     * Projen's NodeProject and JsiiProject hardcode their own pin in the\n     * generated build / release / upgrade workflows; without this patch,\n     * the action installs the wrong pnpm version and CI breaks (e.g.\n     * v5 cannot install pnpm 11).\n     */\n    pinPnpmActionSetup(this);\n\n    /**\n     * Pin every `actions/setup-node` step's `node-version` input across\n     * every workflow on this project's GitHub component to\n     * {@link VERSION.NODE_WORKFLOWS}. Projen's release workflow generator\n     * hardcodes `node-version: \"lts/*\"`; without this patch, release\n     * workflows install whatever Node lts/* resolves to while build /\n     * upgrade workflows install the centralised constant. One source of\n     * truth keeps every workflow in sync.\n     */\n    pinSetupNodeVersion(this);\n\n    /**\n     * Set `include-hidden-files: true` on the projen-emitted\n     * `Upload artifact` step in the build job (the one that uploads\n     * `dist`). Projen brackets that upload with\n     * `Backup artifact permissions` / `Restore build artifact permissions`\n     * steps that capture and restore ACLs for **every** entry under `dist/`,\n     * including dotfiles. `actions/upload-artifact` v4+ defaults\n     * `include-hidden-files` to `false`, so without this patch every\n     * hidden entry is silently dropped from the artifact and the\n     * `setfacl --restore` step in each downstream deploy job exits\n     * non-zero, producing a noisy failure annotation per deploy job.\n     */\n    includeHiddenFilesInBuildArtifact(this);\n\n    if (this.layoutEnforcement === LAYOUT_ENFORCEMENT.OFF) {\n      return;\n    }\n\n    const violations = validateMonorepoLayout(this);\n    const singletonViolation = validateStarlightSingleton(this);\n\n    if (this.layoutEnforcement === LAYOUT_ENFORCEMENT.ERROR) {\n      if (violations.length > 0) {\n        throw new Error(formatLayoutViolation(violations[0]));\n      }\n      if (singletonViolation !== undefined) {\n        throw new Error(formatStarlightSingletonViolation(singletonViolation));\n      }\n      return;\n    }\n\n    // \"warn\"\n    for (const violation of violations) {\n      console.warn(formatLayoutViolation(violation));\n    }\n    if (singletonViolation !== undefined) {\n      console.warn(formatStarlightSingletonViolation(singletonViolation));\n    }\n  }\n\n  /**\n   * Allows a sub project to request installation of dependency at the Monorepo root\n   * They must provide a function that is executed after dependencies have been installed\n   * If this function returns true, the install command is run for a second time after all sub project requests have run.\n   * This is used to resolve dependency versions from `*` to a concrete version constraint.\n   */\n  public requestInstallDependencies(resolver: IDependencyResolver) {\n    postInstallDependenciesMap\n      .get(this)!\n      .push(resolver.resolveDepsAndWritePackageJson);\n  }\n\n  /**\n   * Runs a non-frozen dependency install during synth.\n   *\n   * Projen's `NodePackage.installDependencies` runs the frozen `install:ci`\n   * task (`pnpm i --frozen-lockfile`) whenever `process.env.CI` is truthy.\n   * That is wrong for a synth-time install: synth itself can rewrite\n   * `pnpm-workspace.yaml` (e.g. when a configulator catalog value in\n   * `versions.ts` bumps), leaving the lockfile out of sync with the freshly\n   * written workspace catalog. A frozen install then fails with\n   * `ERR_PNPM_LOCKFILE_CONFIG_MISMATCH`, which previously broke the scheduled\n   * upgrade workflow on every consumer repo across any catalog bump.\n   *\n   * Frozen-install enforcement belongs to CI's explicit `install:ci`\n   * invocation, not to the synth-time install. We therefore always run the\n   * non-frozen `install` task here, which refreshes the lockfile to match the\n   * rewritten workspace — matching the canonical regen sequence consumers\n   * already document (`pnpm i && pnpm exec projen && pnpm i`, neither frozen).\n   *\n   * Runs the task via `this.tasks.runTask` (the public task-execution API,\n   * which projen itself uses in `NodePackage.installDependencies`) rather than\n   * constructing a `TaskRuntime`: projen 0.100 removed `TaskRuntime` from the\n   * package root and made it internal to the CLI. `Tasks.runTask` is stable\n   * across the 0.99/0.100 boundary and executes against this project's outdir,\n   * so behavior is unchanged.\n   *\n   * @see https://github.com/codedrifters/packages/issues/570\n   */\n  private installDependenciesNonFrozen() {\n    this.tasks.runTask(this.package.installTask.name);\n  }\n\n  /**\n   * Hooks into the install dependencies cycle\n   */\n  public postSynthesize() {\n    const postInstallDependencies = postInstallDependenciesMap.get(this);\n    if (postInstallDependencies?.length) {\n      this.installDependenciesNonFrozen();\n\n      const completedRequests = postInstallDependencies.map((request) =>\n        request(),\n      );\n      if (completedRequests.some(Boolean)) {\n        this.installDependenciesNonFrozen();\n      }\n\n      postInstallDependenciesMap.set(this, []);\n    }\n  }\n}\n","import { Component, Project } from \"projen\";\nimport { TextFile } from \"projen/lib/textfile\";\nimport { VERSION } from \"../versions\";\n\n/**\n * Emits a `.nvmrc` file at the project root containing the Node.js\n * version pinned in {@link VERSION.NODE_WORKFLOWS}.\n *\n * The file gives `nvm`, `fnm`, `volta`, and IDE plugins a single\n * source of truth for the Node version local development should use,\n * matching the version every CI workflow installs via\n * `actions/setup-node`. Without it, devs on hosts whose default Node\n * is older than the floor required by tooling (Astro 6, Starlight,\n * pnpm 11) silently break after a regen.\n *\n * Projen has no built-in `.nvmrc` knob — the closest input is\n * `workflowNodeVersion`, which only drives CI. This component closes\n * the local-dev gap.\n */\nexport class Nvmrc extends Component {\n  constructor(project: Project) {\n    super(project);\n\n    new TextFile(project, \".nvmrc\", {\n      // `lines` is joined with `\\n` — adding an empty trailing entry\n      // produces a POSIX-friendly trailing newline (`24\\n`).\n      lines: [VERSION.NODE_WORKFLOWS, \"\"],\n      readonly: true,\n    });\n  }\n}\n","import { NodeProject } from \"projen/lib/javascript\";\n\n/**\n * Shared option for controlling the `private` field in `package.json`.\n *\n * Mixed into every configulator Node project's options interface\n * (`TypeScriptProjectOptions`, `AwsCdkProjectOptions`,\n * `MonorepoProjectOptions`) so the knob reads and behaves identically\n * across project types.\n */\nexport interface PackagePrivateOptions {\n  /**\n   * Whether to synthesize `\"private\": true` into `package.json`.\n   *\n   * When omitted, the value is derived from the release configuration: a\n   * project that does not publish to a registry (`releaseToNpm` unset or\n   * `false`) is marked private, and a project that does publish\n   * (`releaseToNpm: true`) is not. npm refuses to publish a package\n   * carrying `\"private\": true`, so the default makes an unpublished\n   * package unpublishable by hand rather than merely un-wired from the\n   * release workflow.\n   *\n   * Set to `false` to omit the field entirely — the escape hatch for a\n   * package that is published by hand or by tooling outside projen's\n   * release flow. Set to `true` to force the field on a project that has\n   * no release configuration of its own.\n   *\n   * Setting `true` alongside `releaseToNpm: true` throws: the release\n   * workflow would run `npm publish` against a package npm refuses to\n   * accept, and failing at synth time beats failing mid-release.\n   *\n   * @default - `true` when `releaseToNpm` is not enabled, otherwise the field is omitted\n   */\n  readonly packagePrivate?: boolean;\n}\n\n/**\n * Resolve whether `package.json` should carry `\"private\": true`.\n *\n * An explicit `packagePrivate` always wins. Otherwise the field tracks\n * the inverse of `releaseToNpm` — projen throws when `releaseToNpm` is\n * set without `release`, so `releaseToNpm` alone is a sufficient signal\n * that a registry publish is actually wired up.\n */\nexport function resolvePackagePrivate(options: {\n  readonly packagePrivate?: boolean;\n  readonly releaseToNpm?: boolean;\n}): boolean {\n  const releaseToNpm = options.releaseToNpm ?? false;\n\n  if (options.packagePrivate !== undefined) {\n    if (options.packagePrivate && releaseToNpm) {\n      throw new Error(\n        'Cannot set `packagePrivate: true` together with `releaseToNpm: true`: npm refuses to publish a package marked `\"private\": true`. ' +\n          \"Drop `packagePrivate` to let it track the release configuration, or turn off `releaseToNpm`.\",\n      );\n    }\n    return options.packagePrivate;\n  }\n\n  return !releaseToNpm;\n}\n\n/**\n * Apply the resolved {@link resolvePackagePrivate} decision to a project's\n * `package.json`. Writes nothing when the package is publishable, so an\n * npm-released package renders exactly as it did before this option\n * existed.\n */\nexport function applyPackagePrivate(\n  project: NodeProject,\n  options: {\n    readonly packagePrivate?: boolean;\n    readonly releaseToNpm?: boolean;\n  },\n): void {\n  if (resolvePackagePrivate(options)) {\n    project.package.addField(\"private\", true);\n  }\n}\n","import { Component, Project } from \"projen\";\nimport { TypeScriptProject } from \"../projects/typescript-project\";\nimport { TurboRepo } from \"../turbo/turbo-repo\";\nimport { TurboRepoTask } from \"../turbo/turbo-repo-task\";\n\n/*******************************************************************************\n *\n * Reset Task Component\n *\n * Adds a \"reset\" task that deletes all build artifacts produced by the build\n * process. This includes node_modules, lib, dist, coverage, test-reports,\n * .turbo, and tsconfig.tsbuildinfo.\n *\n ******************************************************************************/\n\nexport interface ResetTaskOptions {\n  /**\n   * Custom output directory to delete (overrides tsconfig artifactsDirectory detection).\n   *\n   * @default - detected from typescript project.artifactsDirectory or \"lib\"\n   */\n  readonly artifactsDirectory?: string;\n\n  /**\n   * Array of glob patterns for paths to remove.\n   * If empty, the artifactsDirectory will be added automatically.\n   *\n   * @default []\n   */\n  readonly pathsToRemove?: string[];\n\n  /**\n   * Name of the task to create.\n   *\n   * @default \"reset\"\n   */\n  readonly taskName?: string;\n}\n\nexport class ResetTask extends Component {\n  /**\n   * Static method to discover reset task in a project.\n   */\n  public static of(project: Project): ResetTask | undefined {\n    const isDefined = (c: Component): c is ResetTask => c instanceof ResetTask;\n    return project.components.find(isDefined);\n  }\n\n  /**\n   * The output directory to delete (from tsconfig or custom).\n   */\n  public readonly artifactsDirectory: string;\n\n  /**\n   * The final array of paths that will be removed by the reset task.\n   */\n  public readonly pathsToRemove: string[];\n\n  /**\n   * The name of the task that was created.\n   */\n  public readonly taskName: string;\n\n  constructor(\n    public readonly project: Project,\n    options: ResetTaskOptions = {},\n  ) {\n    super(project);\n\n    /**\n     * Determine the output directory.\n     * 1. Use custom artifactsDirectory if provided\n     * 2. Use the artifacts directory if project is TypeScriptProject\n     * 3. Default to \"lib\"\n     */\n    this.artifactsDirectory = options.artifactsDirectory\n      ? options.artifactsDirectory\n      : project instanceof TypeScriptProject\n        ? project.artifactsDirectory\n        : \"lib\";\n\n    /**\n     * Build the paths array to remove.\n     * If pathsToRemove is empty, add artifactsDirectory.\n     * If pathsToRemove is not empty, use it as-is (artifactsDirectory is not automatically added).\n     * Remove duplicate entries from the array.\n     */\n    const pathsToRemove = options.pathsToRemove ?? [];\n    const finalPaths =\n      pathsToRemove.length === 0 ? [this.artifactsDirectory] : pathsToRemove;\n\n    /**\n     * Remove duplicate paths from the array.\n     */\n    this.pathsToRemove = Array.from(new Set(finalPaths));\n\n    /**\n     * Determine the task name.\n     */\n    this.taskName = options.taskName ?? \"reset\";\n\n    /**\n     * Create the reset task.\n     */\n    const resetTask = this.project.tasks.addTask(this.taskName, {\n      description:\n        \"Delete build artifacts specified by pathsToRemove option, or artifactsDirectory if pathsToRemove is empty\",\n    });\n\n    /**\n     * Delete build artifacts with existence checks.\n     * Using shell conditionals to only delete if paths exist.\n     * Using -e to check existence (works for both files and directories).\n     */\n    this.pathsToRemove.forEach((path) => {\n      resetTask.exec(`[ -e \"${path}\" ] && rm -rf ${path} || true`);\n    });\n\n    /**\n     * Turbo tasks are added after all components are created.\n     * This assumes turbo is built first so that it's available to be\n     * referenced. This could introduce problems in future but works for now.\n     */\n\n    /**\n     * Check if turborepo is active.\n     */\n    const rootHasTurbo = TurboRepo.of(this.project.root) !== undefined;\n    const isSubproject = this.project !== this.project.root;\n    const isRootProject = this.project === this.project.root;\n\n    /**\n     * If turborepo is active for the subproject, add turbo tasks.\n     */\n    if (isSubproject && rootHasTurbo) {\n      /**\n       * Get TurboRepo instance for this subproject.\n       * It should exist by now since preSynthesize runs after all components are created.\n       */\n      const turbo = TurboRepo.of(this.project);\n      if (turbo && !turbo.isRootProject) {\n        /**\n         * Create turbo:reset task (or `turbo:${taskName}`).\n         */\n        const turboResetTask = new TurboRepoTask(this.project, {\n          name: `turbo:${this.taskName}`,\n          cache: false,\n        });\n        turbo.tasks.push(turboResetTask);\n\n        /**\n         * Create a turbo task with the same name as the reset task.\n         */\n        const turboTaskWithSameName = new TurboRepoTask(this.project, {\n          name: this.taskName,\n          cache: false,\n        });\n        turbo.tasks.push(turboTaskWithSameName);\n\n        /**\n         * turboResetTask depends on turboTaskWithSameName so that the reset task\n         * can be run across all suprojects using turbo:reset as the entry point.\n         */\n        turboResetTask.dependsOn.push(turboTaskWithSameName.name);\n      }\n    }\n\n    /**\n     * If reset-task is in the root project, add a turbo task that will trigger\n     * all the subtasks using dependsOn of \"^turbo:reset\".\n     */\n    if (isRootProject && rootHasTurbo) {\n      const turbo = TurboRepo.of(this.project);\n      if (turbo && turbo.isRootProject) {\n        /**\n         * Create turbo:reset task (or `turbo:${taskName}`) in the root project.\n         * The `^` prefix means \"run this task in all dependencies first\".\n         */\n        const rootTurboResetTask = new TurboRepoTask(this.project, {\n          name: `turbo:${this.taskName}`,\n          dependsOn: [`^turbo:${this.taskName}`],\n          cache: false,\n        });\n        turbo.tasks.push(rootTurboResetTask);\n\n        /**\n         * Create a turbo task with the same name as the reset task.\n         */\n        const turboTaskWithSameName = new TurboRepoTask(this.project, {\n          name: this.taskName,\n          cache: false,\n        });\n        turbo.tasks.push(turboTaskWithSameName);\n\n        /**\n         * rootTurboResetTask depends on turboTaskWithSameName so that the reset task\n         * can be run across all suprojects using turbo:reset as the entry point.\n         */\n        rootTurboResetTask.dependsOn.push(turboTaskWithSameName.name);\n\n        /**\n         * Create reset:all task - a projen task that calls the turbo task.\n         * This is similar to build:all in turbo-repo.ts.\n         */\n        const resetAllTask = this.project.tasks.addTask(\n          `${this.taskName}:all`,\n          {\n            description: `Reset all build artifacts across the monorepo by running turbo:${this.taskName} in all subprojects.`,\n          },\n        );\n        resetAllTask.exec(\"turbo telemetry disable\");\n        resetAllTask.exec(\n          `turbo turbo:${this.taskName} ${turbo.renderRunArgs(false)}`,\n        );\n        resetAllTask.exec(`pnpm ${this.taskName}`);\n      }\n    }\n  }\n}\n","import { Component, vscode } from \"projen\";\nimport { TypeScriptAppProject } from \"projen/lib/typescript\";\n\n/*******************************************************************************\n *\n * Configure VSCode Settings\n *\n ******************************************************************************/\n\nexport class VSCodeConfig extends Component {\n  constructor(project: TypeScriptAppProject) {\n    super(project);\n\n    /**\n     * Create instance of config file.\n     */\n    const vsConfig = new vscode.VsCode(project);\n\n    /**\n     * Add some basic configuration settings to the VS Code settings file:\n     *\n     * - Set the tab size to 2 spaces\n     * - Enable bracket pair colorization\n     * - Highlight active bracket pairs\n     * - Add rulers at 80 and 120 characters\n     */\n    const vsSettings = new vscode.VsCodeSettings(vsConfig);\n    vsSettings.addSetting(\"editor.tabSize\", 2);\n    vsSettings.addSetting(\"editor.detectIndentation\", false);\n    vsSettings.addSetting(\"editor.bracketPairColorization.enabled\", true);\n    vsSettings.addSetting(\"editor.guides.bracketPairs\", \"active\");\n    vsSettings.addSetting(\"editor.rulers\", [80, 120]);\n\n    /**\n     * Add some ESLint specific settings to the VS Code settings file.\n     */\n    vsSettings.addSetting(\n      \"editor.codeActionsOnSave\",\n      { \"source.fixAll.eslint\": \"explicit\" },\n      \"typescript\",\n    );\n  }\n}\n","import { JobPermission } from \"projen/lib/github/workflows-model\";\nimport type { NodeProject } from \"projen/lib/javascript\";\n\n/** Merge methods supported by enable-pull-request-automerge. */\nexport const MERGE_METHODS = {\n  SQUASH: \"squash\",\n  MERGE: \"merge\",\n  REBASE: \"rebase\",\n} as const;\n\n/** Merge method for the approve-and-merge-upgrade workflow. */\nexport type MergeMethod = (typeof MERGE_METHODS)[keyof typeof MERGE_METHODS];\n\n/**\n * Options for the approve-and-merge-upgrade workflow (ADR 0001 §2).\n * When set, adds a workflow that approves and merges the dependency-upgrade PR\n * when it has the auto-approve label and head branch matches. Trigger types\n * exclude `opened` to prevent double approval when the PR is created with the label.\n */\nexport interface ApproveMergeUpgradeOptions {\n  /**\n   * Workflow file name (display name in Actions tab).\n   * @default \"approve-and-merge-upgrade\"\n   */\n  readonly workflowName?: string;\n\n  /**\n   * Label that must be present on the PR to trigger approve-and-merge.\n   * @default \"auto-approve\"\n   */\n  readonly autoApproveLabel?: string;\n\n  /**\n   * Head branch name the PR must target (e.g. the branch created by the upgrade workflow).\n   * @default \"github-actions/upgrade\"\n   */\n  readonly headBranch?: string;\n\n  /**\n   * GitHub usernames allowed as PR authors (e.g. automation bot logins).\n   * The workflow runs only when the PR user is in this list.\n   */\n  readonly allowedUsernames: string[];\n\n  /**\n   * Repository secret name for the approval GitHub App ID.\n   * @default \"APPROVAL_APP_ID\"\n   */\n  readonly approvalAppIdSecret?: string;\n\n  /**\n   * Repository secret name for the approval GitHub App private key (PEM).\n   * @default \"APPROVAL_APP_PRIVATE_KEY\"\n   */\n  readonly approvalAppPrivateKeySecret?: string;\n\n  /**\n   * Merge method for enable-pull-request-automerge.\n   * @default \"squash\"\n   */\n  readonly mergeMethod?: MergeMethod;\n\n  /**\n   * Optional branch filters for pull_request_target (e.g. base branches).\n   * @see https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target\n   */\n  readonly branches?: string[];\n}\n\nconst DEFAULT_WORKFLOW_NAME = \"approve-and-merge-upgrade\";\nconst DEFAULT_AUTO_APPROVE_LABEL = \"auto-approve\";\nconst DEFAULT_HEAD_BRANCH = \"github-actions/upgrade\";\nconst DEFAULT_APPROVAL_APP_ID_SECRET = \"APPROVAL_APP_ID\";\nconst DEFAULT_APPROVAL_APP_PRIVATE_KEY_SECRET = \"APPROVAL_APP_PRIVATE_KEY\";\nconst DEFAULT_MERGE_METHOD = MERGE_METHODS.SQUASH;\n\n/**\n * Trigger types for pull_request_target. Excludes `opened` so that when the\n * upgrade workflow creates a PR with the auto-approve label, GitHub emits both\n * `opened` and `labeled` and we avoid running the workflow twice (double approval).\n */\nconst PULL_REQUEST_TARGET_TYPES = [\n  \"labeled\",\n  \"synchronize\",\n  \"reopened\",\n  \"ready_for_review\",\n] as const;\n\n/**\n * Adds the approve-and-merge-upgrade workflow to the project.\n * Uses a GitHub App token for approve + enable automerge (squash by default).\n *\n * @param project - A NodeProject with GitHub (e.g. MonorepoProject)\n * @param options - Options for the workflow; allowedUsernames is required\n */\nexport function addApproveMergeUpgradeWorkflow(\n  project: NodeProject,\n  options: ApproveMergeUpgradeOptions,\n): void {\n  const workflowName = options.workflowName ?? DEFAULT_WORKFLOW_NAME;\n  const autoApproveLabel =\n    options.autoApproveLabel ?? DEFAULT_AUTO_APPROVE_LABEL;\n  const headBranch = options.headBranch ?? DEFAULT_HEAD_BRANCH;\n  const allowedUsernames = options.allowedUsernames;\n  const appIdSecret =\n    options.approvalAppIdSecret ?? DEFAULT_APPROVAL_APP_ID_SECRET;\n  const privateKeySecret =\n    options.approvalAppPrivateKeySecret ??\n    DEFAULT_APPROVAL_APP_PRIVATE_KEY_SECRET;\n  const mergeMethod = options.mergeMethod ?? DEFAULT_MERGE_METHOD;\n\n  const workflow = project.github?.addWorkflow(workflowName);\n  if (!workflow) return;\n\n  workflow.on({\n    pullRequestTarget: {\n      types: [...PULL_REQUEST_TARGET_TYPES],\n      ...(options.branches && options.branches.length > 0\n        ? { branches: options.branches }\n        : {}),\n    },\n  });\n\n  const jobCondition = [\n    `contains(github.event.pull_request.labels.*.name, '${autoApproveLabel}')`,\n    `github.event.pull_request.head.ref == '${headBranch}'`,\n    `(${allowedUsernames.map((u) => `github.event.pull_request.user.login == '${u}'`).join(\" || \")})`,\n  ].join(\" && \");\n\n  workflow.addJobs({\n    \"approve-and-merge\": {\n      name: \"Approve and merge upgrade PR\",\n      runsOn: [\"ubuntu-latest\"],\n      permissions: {\n        pullRequests: JobPermission.WRITE,\n        contents: JobPermission.WRITE,\n      },\n      if: jobCondition,\n      steps: [\n        {\n          name: \"Generate token\",\n          id: \"generate_token\",\n          uses: \"actions/create-github-app-token@v2\",\n          with: {\n            \"app-id\": `\\${{ secrets.${appIdSecret} }}`,\n            \"private-key\": `\\${{ secrets.${privateKeySecret} }}`,\n          },\n        },\n        {\n          name: \"Auto-approve\",\n          uses: \"hmarr/auto-approve-action@f0939ea97e9205ef24d872e76833fa908a770363\",\n          with: {\n            \"github-token\": \"${{ steps.generate_token.outputs.token }}\",\n          },\n        },\n        {\n          name: \"Enable auto-merge (squash)\",\n          uses: \"peter-evans/enable-pull-request-automerge@v3\",\n          with: {\n            token: \"${{ steps.generate_token.outputs.token }}\",\n            \"pull-request-number\": \"${{ github.event.pull_request.number }}\",\n            \"merge-method\": mergeMethod,\n          },\n        },\n      ],\n    },\n  });\n}\n","import { BuildWorkflow } from \"projen/lib/build\";\nimport { JobPermission } from \"projen/lib/github/workflows-model\";\n\n/** Job ID of the main build job (Projen constant). */\nconst BUILD_JOB_ID = \"build\";\n\n/** Name of the gate job appended to build workflows (ADR 0004). */\nexport const COMPLETE_JOB_ID = \"complete\";\n\n/**\n * Projen's BuildWorkflow holds the underlying GithubWorkflow in a private\n * property. We use this shape to access it (cast via unknown).\n */\ninterface BuildWorkflowWithWorkflow {\n  workflow: {\n    jobs: Record<string, unknown>;\n    addJob(id: string, job: Record<string, unknown>): void;\n  };\n}\n\n/**\n * Builds the run script for the complete job step. Requires the build job to\n * succeed; all other jobs must succeed or be skipped (ADR 0004).\n * Uses `\\$` so the output contains literal `${{ }}` for GitHub Actions expressions.\n */\nfunction buildCompleteJobRunScript(jobIds: string[]): string {\n  const lines: string[] = [];\n  for (const id of jobIds) {\n    const expr = \"${{ needs.\" + id + \".result }}\";\n    if (id === BUILD_JOB_ID) {\n      lines.push(\n        `if [ \"${expr}\" != \"success\" ]; then echo \"Job ${id} must succeed\"; exit 1; fi`,\n      );\n    } else {\n      lines.push(\n        `if [ \"${expr}\" != \"success\" ] && [ \"${expr}\" != \"skipped\" ]; then echo \"Job ${id} must succeed or be skipped\"; exit 1; fi`,\n      );\n    }\n  }\n  return lines.join(\"\\n\");\n}\n\n/**\n * Appends the \"complete\" gate job to a build workflow (ADR 0004, issue #165).\n * The job runs after all other jobs, uses {@code if: always()}, and succeeds\n * only when the build job succeeded and every other job succeeded or was skipped.\n * Call this for the default build workflow and for any build workflow created\n * by Configulator (e.g. AwsDeployWorkflow).\n *\n * @param buildWorkflow - The Projen BuildWorkflow to append the complete job to.\n */\nexport function addBuildCompleteJob(buildWorkflow: BuildWorkflow): void {\n  const w = (buildWorkflow as unknown as BuildWorkflowWithWorkflow).workflow;\n  if (!w?.jobs || typeof w.addJob !== \"function\") {\n    return;\n  }\n  const jobIds = Object.keys(w.jobs).filter((id) => id !== COMPLETE_JOB_ID);\n  if (jobIds.length === 0) {\n    return;\n  }\n  const runScript = buildCompleteJobRunScript(jobIds);\n  w.addJob(COMPLETE_JOB_ID, {\n    name: \"Complete\",\n    needs: jobIds,\n    if: \"always()\",\n    runsOn: [\"ubuntu-latest\"],\n    permissions: {\n      contents: JobPermission.NONE,\n    },\n    steps: [\n      {\n        name: \"Verify all jobs succeeded or were skipped\",\n        run: runScript,\n      },\n    ],\n  });\n}\n","import { Project } from \"projen\";\nimport { GitHub } from \"projen/lib/github\";\nimport { JobStep } from \"projen/lib/github/workflows-model\";\n\n/**\n * Name of the `Upload artifact` step projen emits in the build job.\n *\n * @see {@link UPLOAD_ARTIFACT_PREFIX}\n */\nconst UPLOAD_ARTIFACT_STEP_NAME = \"Upload artifact\";\n\n/**\n * Prefix matched against {@link JobStep.uses} to identify\n * `actions/upload-artifact` steps.\n */\nconst UPLOAD_ARTIFACT_PREFIX = \"actions/upload-artifact@\";\n\n/**\n * Value of the `with.name` input on the projen-emitted build-artifact\n * upload step. Matching all three of name + uses + with.name keeps the\n * patch surgical — other `actions/upload-artifact` steps (e.g. the\n * `turbo-runs` upload, the `repo.patch` upload) are left untouched.\n */\nconst BUILD_ARTIFACT_WITH_NAME = \"build-artifact\";\n\n/**\n * Sets `with[\"include-hidden-files\"] = true` on every build-artifact\n * `Upload artifact` step generated by projen's\n * {@code BuildWorkflow.renderBuildSteps()}.\n *\n * **Why this exists.** Projen's build workflow brackets the\n * `Upload artifact` step (for the `dist` build artifact) with a pair\n * of permission backup/restore steps:\n *\n * 1. `Backup artifact permissions` — runs\n *    `cd dist && getfacl -R . > permissions-backup.acl` and captures\n *    ACLs for **every** entry under `dist/`, including dotfiles\n *    (`.pnpm`, `.travis.yml`, etc.).\n * 2. `Upload artifact` — uploads `dist` using `actions/upload-artifact`.\n *    In `actions/upload-artifact` v4+, the default value of the\n *    `include-hidden-files` input is `false`, so every hidden entry is\n *    silently dropped from the artifact zip.\n * 3. `Restore build artifact permissions` (in each deploy job) — runs\n *    `setfacl --restore=permissions-backup.acl`. The ACL backup\n *    references hidden paths that no longer exist in the downloaded\n *    artifact, so `setfacl` exits non-zero, producing a failure\n *    annotation on every deploy job (`continue-on-error: true` masks\n *    the job result but does not suppress the annotation).\n *\n * Setting `include-hidden-files: true` on the upload keeps the artifact\n * faithful to what `getfacl -R .` captured, eliminating the\n * `setfacl --restore` errors and preserving hidden files that CDK\n * assets legitimately depend on (e.g. the `.pnpm` store layout in a\n * bundled `node_modules/`).\n *\n * **Why this is a configulator patch instead of an upstream projen\n * change.** Projen exposed the `includeHiddenFiles` opt-in in\n * `actions/upload-artifact` via\n * [projen#3827](https://github.com/projen/projen/pull/3827) but never\n * plumbed it into its own `BuildWorkflow.renderBuildSteps()`\n * build-artifact upload. Until projen patches its own helper, this\n * helper is the downstream fix.\n *\n * **Why this is a separate helper.** Projen's BuildWorkflow stores\n * the build job's `steps` as a **lazy closure**\n * (`steps: () => this.renderBuildSteps(...)`), not an eager array, so\n * the `Upload artifact` step does not exist anywhere at\n * `preSynthesize` time. The two existing sibling helpers\n * ({@code pinPnpmActionSetup}, {@code pinSetupNodeVersion}) reach\n * lazy-closure steps by patching the component-level\n * `preBuildSteps` / `postBuildSteps` arrays the closure later\n * concatenates — that path does not work here because the build-\n * artifact upload is emitted **inside** `renderBuildSteps()` and is\n * never added to either component-level array.\n *\n * Instead, this helper wraps each job's `steps` closure: it replaces\n * the original `() => JobStep[]` with a new closure that invokes the\n * original and post-processes the rendered array to set\n * `with[\"include-hidden-files\"] = true` on every matching step.\n * Eager (already-array) step lists are patched in place.\n *\n * **Matching rule.** A step is patched only when all three of the\n * following are true:\n *\n * - `step.name === \"Upload artifact\"`\n * - `step.uses` starts with `actions/upload-artifact@`\n * - `step.with.name === \"build-artifact\"`\n *\n * This deliberately misses other `actions/upload-artifact` steps in\n * the same workflow (e.g. the `turbo-runs` artifact, the `repo.patch`\n * self-mutation artifact) — those uploads do not source hidden files\n * and do not pair with a `setfacl --restore` restore step.\n *\n * @param project - The project whose GitHub workflows should be patched.\n */\nexport function includeHiddenFilesInBuildArtifact(project: Project): void {\n  const github = GitHub.of(project);\n  if (!github) {\n    return;\n  }\n  for (const workflow of github.workflows) {\n    for (const job of Object.values(workflow.jobs)) {\n      patchJobSteps(job);\n    }\n  }\n}\n\n/**\n * Mutates a job's `steps` field so any matching build-artifact upload\n * step carries `with[\"include-hidden-files\"] = true`.\n *\n * Handles both the eager (`steps` is an array) and lazy (`steps` is a\n * closure returning an array) shapes projen uses for workflow jobs.\n */\nfunction patchJobSteps(job: unknown): void {\n  if (typeof job !== \"object\" || job === null) {\n    return;\n  }\n  const mutable = job as { steps?: unknown };\n  const steps = mutable.steps;\n  if (Array.isArray(steps)) {\n    patchStepArray(steps as Array<MutableStep>);\n    return;\n  }\n  if (typeof steps === \"function\") {\n    const original = steps as () => Array<MutableStep>;\n    mutable.steps = () => {\n      const rendered = original();\n      patchStepArray(rendered);\n      return rendered;\n    };\n  }\n}\n\n/**\n * Walks a step array in place and sets\n * `with[\"include-hidden-files\"] = true` on every step that matches\n * the build-artifact upload shape documented in\n * {@link includeHiddenFilesInBuildArtifact}.\n */\nfunction patchStepArray(steps: Array<MutableStep>): void {\n  for (const step of steps) {\n    if (isBuildArtifactUploadStep(step)) {\n      if (!step.with || typeof step.with !== \"object\") {\n        step.with = {};\n      }\n      step.with[\"include-hidden-files\"] = true;\n    }\n  }\n}\n\n/**\n * Returns `true` when the step matches all three of:\n *\n * - `name === \"Upload artifact\"`\n * - `uses` starts with `actions/upload-artifact@`\n * - `with.name === \"build-artifact\"`\n */\nfunction isBuildArtifactUploadStep(step: MutableStep): boolean {\n  if (step.name !== UPLOAD_ARTIFACT_STEP_NAME) {\n    return false;\n  }\n  if (\n    typeof step.uses !== \"string\" ||\n    !step.uses.startsWith(UPLOAD_ARTIFACT_PREFIX)\n  ) {\n    return false;\n  }\n  const withBlock = step.with;\n  if (!withBlock || typeof withBlock !== \"object\") {\n    return false;\n  }\n  return (withBlock as { name?: unknown }).name === BUILD_ARTIFACT_WITH_NAME;\n}\n\n/**\n * Internal mutable view of a {@link JobStep} so we can rewrite the\n * `with` map past projen's `readonly` declarations.\n */\ninterface MutableStep {\n  name?: string;\n  uses?: string;\n  with?: Record<string, unknown>;\n}\n","import { Component, Project } from \"projen\";\nimport { GitHub } from \"projen/lib/github\";\nimport { JobStep } from \"projen/lib/github/workflows-model\";\nimport { VERSION } from \"../versions\";\n\n/**\n * Prefix matched against {@link JobStep.uses} to identify pnpm/action-setup steps.\n */\nconst PNPM_ACTION_SETUP_PREFIX = \"pnpm/action-setup@\";\n\n/**\n * Component property names that, when present, hold an array of\n * {@link JobStep} objects we want to scan for pnpm/action-setup pins.\n *\n * Projen's {@code BuildWorkflow} stores them on a private\n * {@code preBuildSteps} field; {@code Release} stores them on\n * {@code preBuildSteps} (public-ish); both feed steps into the lazy\n * step closures rendered at synth time, so simply walking\n * {@code workflow.jobs[*].steps} during {@code preSynthesize} misses\n * them. This array enumerates the well-known fields we reach into\n * directly to keep the patch in sync with the centralised\n * {@link VERSION.PNPM_ACTION_SETUP_VERSION}.\n */\nconst STEP_ARRAY_FIELDS = [\"preBuildSteps\", \"postBuildSteps\"] as const;\n\n/**\n * Rewrites every `pnpm/action-setup@vX` step `uses` field reachable from\n * a project's GitHub component (and its sub-projects) to the version\n * pinned in {@link VERSION.PNPM_ACTION_SETUP_VERSION}.\n *\n * Projen's NodeProject and JsiiProject both hardcode a `pnpm/action-setup`\n * pin in their generated build / release / upgrade workflows. When that\n * pin lags behind the version required by the pnpm release we run in CI\n * (e.g. v5 cannot install pnpm 11), the action installs the wrong pnpm\n * version and CI breaks. This helper post-patches every workflow owned\n * by `project.github` so the pin tracks our centralised constant.\n *\n * Two passes run in sequence:\n *\n * 1. **Eager step arrays.** Walks every {@link Component} on the\n *    project (and on its sub-projects) for the well-known fields\n *    enumerated in {@link STEP_ARRAY_FIELDS}. Projen's BuildWorkflow\n *    and Release components hold their pnpm-setup steps in these\n *    arrays before the workflow's lazy step closures resolve them.\n * 2. **Direct workflow jobs.** Walks every job step on every\n *    `GithubWorkflow` for jobs whose steps are eagerly populated\n *    (e.g. the upgrade workflow). Steps held inside lazy closures\n *    are skipped — those are reached via pass 1.\n *\n * @param project - The project whose GitHub workflows should be patched.\n */\nexport function pinPnpmActionSetup(project: Project): void {\n  const pinned = `${PNPM_ACTION_SETUP_PREFIX}${VERSION.PNPM_ACTION_SETUP_VERSION}`;\n  // Pass 1: walk components on this project and every sub-project.\n  patchComponentStepArrays(project, pinned);\n  for (const sub of project.subprojects) {\n    patchComponentStepArrays(sub, pinned);\n  }\n  // Pass 2: walk eagerly-populated workflow job steps on the project's\n  // GitHub component (sub-project release workflows attach to the root\n  // GitHub via `GitHub.of(project.root)`, so a single pass covers them).\n  const github = GitHub.of(project);\n  if (!github) {\n    return;\n  }\n  for (const workflow of github.workflows) {\n    for (const job of Object.values(workflow.jobs)) {\n      patchStepArray(getEagerSteps(job), pinned);\n    }\n  }\n}\n\n/**\n * Walks {@link STEP_ARRAY_FIELDS} on every {@link Component} of the\n * given project and rewrites pnpm/action-setup pins in any step\n * arrays that are eagerly populated.\n */\nfunction patchComponentStepArrays(project: Project, pinned: string): void {\n  for (const component of project.components) {\n    for (const field of STEP_ARRAY_FIELDS) {\n      const steps = readStepArray(component, field);\n      if (steps !== undefined) {\n        patchStepArray(steps, pinned);\n      }\n    }\n  }\n}\n\n/**\n * Reads a {@code JobStep[]}-shaped property off a component, casting\n * past projen's private/readonly declarations. Returns `undefined`\n * when the property is missing or not an array.\n */\nfunction readStepArray(\n  component: Component,\n  field: string,\n): Array<{ uses?: string }> | undefined {\n  const value = (component as unknown as Record<string, unknown>)[field];\n  return Array.isArray(value) ? (value as Array<{ uses?: string }>) : undefined;\n}\n\n/**\n * Reads {@code job.steps} only when it is already an array (i.e. not\n * a lazy closure). Workflows that build their steps via a closure\n * are reached via the component-level pass instead.\n */\nfunction getEagerSteps(job: unknown): Array<{ uses?: string }> | undefined {\n  if (typeof job !== \"object\" || job === null) {\n    return undefined;\n  }\n  const steps = (job as { steps?: unknown }).steps;\n  return Array.isArray(steps) ? (steps as Array<{ uses?: string }>) : undefined;\n}\n\n/**\n * Mutates a step array in place: rewrites every step whose\n * {@code uses} field starts with the pnpm/action-setup prefix to\n * the pinned version.\n */\nfunction patchStepArray(\n  steps: Array<{ uses?: string }> | undefined,\n  pinned: string,\n): void {\n  if (!steps) {\n    return;\n  }\n  for (const step of steps) {\n    if (\n      typeof step.uses === \"string\" &&\n      step.uses.startsWith(PNPM_ACTION_SETUP_PREFIX)\n    ) {\n      step.uses = pinned;\n    }\n  }\n}\n","import { Component, Project } from \"projen\";\nimport { GitHub } from \"projen/lib/github\";\nimport { JobStep } from \"projen/lib/github/workflows-model\";\nimport { VERSION } from \"../versions\";\n\n/**\n * Prefix matched against {@link JobStep.uses} to identify\n * `actions/setup-node` steps.\n */\nconst SETUP_NODE_PREFIX = \"actions/setup-node@\";\n\n/**\n * Component property names that, when present, hold an array of\n * {@link JobStep} objects we want to scan for `actions/setup-node`\n * `node-version` inputs.\n *\n * Mirrors {@link pinPnpmActionSetup}'s traversal: projen's\n * {@code BuildWorkflow} stores them on a private\n * {@code preBuildSteps} field; {@code Release} stores them on\n * {@code preBuildSteps} (public-ish); both feed steps into the lazy\n * step closures rendered at synth time, so simply walking\n * {@code workflow.jobs[*].steps} during {@code preSynthesize} misses\n * them. This array enumerates the well-known fields we reach into\n * directly.\n */\nconst STEP_ARRAY_FIELDS = [\"preBuildSteps\", \"postBuildSteps\"] as const;\n\n/**\n * Component property names that, when present, hold a string value\n * carrying the Node version a release workflow renders into a\n * `tools.node.version` block (and therefore into a\n * `with[\"node-version\"]` input on the auto-generated\n * `actions/setup-node` step). Projen's {@code Publisher} stores its\n * version under {@code workflowNodeVersion} and defaults it to\n * `\"lts/*\"` when no value is supplied.\n */\nconst NODE_VERSION_FIELDS = [\"workflowNodeVersion\"] as const;\n\n/**\n * Rewrites every Node-version source reachable from a project's\n * GitHub component (and its sub-projects) to the version pinned in\n * {@link VERSION.NODE_WORKFLOWS}.\n *\n * Projen hardcodes `node-version: \"lts/*\"` in its release workflow\n * generator (via {@code Publisher.workflowNodeVersion}); configulator-\n * owned workflows already pass through {@link VERSION.NODE_WORKFLOWS}.\n * Without this patch, the two sources disagree (release workflows\n * install whatever Node lts/* resolves to; build / upgrade workflows\n * install Node 24). This helper post-patches every Node-version\n * source so a single source of truth — the centralised\n * {@link VERSION.NODE_WORKFLOWS} constant — drives every workflow\n * this repo and its consumers generate.\n *\n * Three passes run in sequence:\n *\n * 1. **Component Node-version fields.** Walks every {@link Component}\n *    on the project (and on its sub-projects) and rewrites the\n *    well-known fields enumerated in {@link NODE_VERSION_FIELDS} —\n *    notably {@code Publisher.workflowNodeVersion}, which projen\n *    renders into {@code tools.node.version} on the publish job\n *    (and ultimately into the synthesized\n *    `actions/setup-node` step).\n * 2. **Component step arrays.** Walks every {@link Component} on the\n *    project (and on its sub-projects) for the well-known step-array\n *    fields enumerated in {@link STEP_ARRAY_FIELDS}. Projen's\n *    BuildWorkflow and Release components hold their pre/post-build\n *    steps in these arrays before the workflow's lazy step closures\n *    resolve them.\n * 3. **Direct workflow jobs.** Walks every job on every\n *    `GithubWorkflow`. For each job:\n *    - If `tools.node.version` is set (the lazy `setupTools` path\n *      that synthesises the setup-node step at render time),\n *      rewrite it.\n *    - If `steps` is already an array (i.e. not a lazy closure),\n *      patch any `actions/setup-node` step in place.\n *\n * The step-level patch only mutates `with[\"node-version\"]`. Other\n * fields on `with` (`cache`, `cache-dependency-path`,\n * `registry-url`, `package-manager-cache`, etc.) are preserved\n * untouched. The step's `uses` field is also left alone — this\n * helper pins the input, not the action version pin.\n *\n * @param project - The project whose GitHub workflows should be patched.\n */\nexport function pinSetupNodeVersion(project: Project): void {\n  const pinned = VERSION.NODE_WORKFLOWS;\n  // Pass 1 + 2: walk components on this project and every sub-project.\n  patchComponentNodeVersionFields(project, pinned);\n  patchComponentStepArrays(project, pinned);\n  for (const sub of project.subprojects) {\n    patchComponentNodeVersionFields(sub, pinned);\n    patchComponentStepArrays(sub, pinned);\n  }\n  // Pass 3: walk eagerly-populated workflow job steps and the\n  // `tools.node.version` block on every job. Sub-project release\n  // workflows attach to the root GitHub via `GitHub.of(project.root)`,\n  // so a single pass covers them.\n  const github = GitHub.of(project);\n  if (!github) {\n    return;\n  }\n  for (const workflow of github.workflows) {\n    for (const job of Object.values(workflow.jobs)) {\n      patchJobToolsNode(job, pinned);\n      patchStepArray(getEagerSteps(job), pinned);\n    }\n  }\n}\n\n/**\n * Walks {@link NODE_VERSION_FIELDS} on every {@link Component} of the\n * given project and rewrites the field's string value to the pinned\n * version. Used to retarget {@code Publisher.workflowNodeVersion}\n * (and any future component that exposes a similar field).\n */\nfunction patchComponentNodeVersionFields(\n  project: Project,\n  pinned: string,\n): void {\n  for (const component of project.components) {\n    for (const field of NODE_VERSION_FIELDS) {\n      const record = component as unknown as Record<string, unknown>;\n      const value = record[field];\n      if (typeof value === \"string\") {\n        record[field] = pinned;\n      }\n    }\n  }\n}\n\n/**\n * Walks {@link STEP_ARRAY_FIELDS} on every {@link Component} of the\n * given project and rewrites `actions/setup-node` `node-version`\n * inputs in any step arrays that are eagerly populated.\n */\nfunction patchComponentStepArrays(project: Project, pinned: string): void {\n  for (const component of project.components) {\n    for (const field of STEP_ARRAY_FIELDS) {\n      const steps = readStepArray(component, field);\n      if (steps !== undefined) {\n        patchStepArray(steps, pinned);\n      }\n    }\n  }\n}\n\n/**\n * Reads a {@code JobStep[]}-shaped property off a component, casting\n * past projen's private/readonly declarations. Returns `undefined`\n * when the property is missing or not an array.\n */\nfunction readStepArray(\n  component: Component,\n  field: string,\n): Array<MutableStep> | undefined {\n  const value = (component as unknown as Record<string, unknown>)[field];\n  return Array.isArray(value) ? (value as Array<MutableStep>) : undefined;\n}\n\n/**\n * Reads {@code job.steps} only when it is already an array (i.e. not\n * a lazy closure). Workflows that build their steps via a closure\n * are reached via the component-level pass instead.\n */\nfunction getEagerSteps(job: unknown): Array<MutableStep> | undefined {\n  if (typeof job !== \"object\" || job === null) {\n    return undefined;\n  }\n  const steps = (job as { steps?: unknown }).steps;\n  return Array.isArray(steps) ? (steps as Array<MutableStep>) : undefined;\n}\n\n/**\n * Rewrites {@code job.tools.node.version} when it is set. Projen's\n * `setupTools` helper synthesises an `actions/setup-node` step at\n * workflow render time from this field — patching the source string\n * here is the only path that reaches release-workflow setup-node\n * steps, since those steps never appear in a `steps[]` array before\n * render.\n */\nfunction patchJobToolsNode(job: unknown, pinned: string): void {\n  if (typeof job !== \"object\" || job === null) {\n    return;\n  }\n  const tools = (job as { tools?: unknown }).tools;\n  if (typeof tools !== \"object\" || tools === null) {\n    return;\n  }\n  const node = (tools as { node?: unknown }).node;\n  if (typeof node !== \"object\" || node === null) {\n    return;\n  }\n  if (typeof (node as { version?: unknown }).version === \"string\") {\n    (node as { version: string }).version = pinned;\n  }\n}\n\n/**\n * Mutates a step array in place: rewrites every step whose\n * {@code uses} field starts with the `actions/setup-node` prefix to\n * carry `with[\"node-version\"] = pinned`. Other fields on `with` are\n * preserved; if the step has no `with` block, one is created.\n */\nfunction patchStepArray(\n  steps: Array<MutableStep> | undefined,\n  pinned: string,\n): void {\n  if (!steps) {\n    return;\n  }\n  for (const step of steps) {\n    if (\n      typeof step.uses === \"string\" &&\n      step.uses.startsWith(SETUP_NODE_PREFIX)\n    ) {\n      if (!step.with || typeof step.with !== \"object\") {\n        step.with = {};\n      }\n      step.with[\"node-version\"] = pinned;\n    }\n  }\n}\n\n/**\n * Internal mutable view of a {@link JobStep} so we can rewrite the\n * `with` map past projen's `readonly` declarations.\n */\ninterface MutableStep {\n  uses?: string;\n  with?: Record<string, unknown>;\n}\n","import { Component, Project, TextFile } from \"projen\";\n\n/** Field values for the canonical cross-repo `## Requirement` block. */\nexport interface RequirementBlockFields {\n  /** Requirement ID (e.g. `FR-042`). */\n  readonly id: string;\n\n  /** URL to the canonical requirement doc in the planning repo. */\n  readonly specUrl: string;\n\n  /** Requirement tier (Platform | Industry | Customer Workflow | Consumer Application). */\n  readonly tier: string;\n\n  /** Customer scope, or `—`. */\n  readonly customer: string;\n}\n\n/**\n * Render the canonical cross-repo `## Requirement` traceability block.\n * Shared by the requirement issue template (#824) and the fan-out\n * workflow (#825) so a human-filed issue and a bot-fanned-out issue\n * produce byte-identical blocks.\n */\nexport function renderRequirementBlock(fields: RequirementBlockFields): string {\n  return [\n    \"## Requirement\",\n    \"\",\n    `- **ID:** ${fields.id}`,\n    `- **Spec:** ${fields.specUrl}`,\n    `- **Tier:** ${fields.tier}`,\n    `- **Customer:** ${fields.customer}`,\n  ].join(\"\\n\");\n}\n\n/** Options for the requirement issue template component. */\nexport interface RequirementIssueTemplateOptions {\n  /**\n   * Output path for the emitted GitHub issue template.\n   * @default \".github/ISSUE_TEMPLATE/requirement-impl.md\"\n   */\n  readonly path?: string;\n\n  /**\n   * Static labels applied by the template front-matter.\n   * @default [\"type:feat\"]\n   */\n  readonly labels?: ReadonlyArray<string>;\n}\n\nconst DEFAULT_TEMPLATE_PATH = \".github/ISSUE_TEMPLATE/requirement-impl.md\";\nconst DEFAULT_TEMPLATE_LABELS: ReadonlyArray<string> = [\"type:feat\"];\n\n/**\n * Emits a GitHub markdown issue template that carries the canonical\n * cross-repo `## Requirement` traceability block. A human opening an\n * issue from this template records the requirement ID, its spec URL,\n * tier, and customer scope, and is prompted to add a `req:<ID>` label\n * so the issue is traceable to the requirement across repositories.\n *\n * The `## Requirement` block is rendered by {@link renderRequirementBlock}\n * so a human-filed issue and a bot-fanned-out issue (the fan-out\n * workflow in #825) produce byte-identical blocks.\n *\n * @see docs/src/content/docs/packages/\\@codedrifters/configulator/requirement-traceability.md\n */\nexport class RequirementIssueTemplate extends Component {\n  constructor(project: Project, options: RequirementIssueTemplateOptions = {}) {\n    super(project);\n\n    const path = options.path ?? DEFAULT_TEMPLATE_PATH;\n    const labels = options.labels ?? DEFAULT_TEMPLATE_LABELS;\n    const labelsYaml = `[${labels.map((l) => `\"${l}\"`).join(\", \")}]`;\n\n    // The four `## Requirement` lines come from renderRequirementBlock so\n    // the block structure is shared with the fan-out workflow (#825). The\n    // placeholder values are HTML comments so the rendered issue shows an\n    // inline hint next to each field.\n    const requirementBlock = renderRequirementBlock({\n      id: \"<!-- e.g. FR-042 -->\",\n      specUrl:\n        \"<!-- URL to the canonical requirement doc in the planning repo -->\",\n      tier: \"<!-- Platform | Industry | Customer Workflow | Consumer Application -->\",\n      customer: \"<!-- customer scope, or — -->\",\n    });\n\n    const lines = [\n      \"---\",\n      \"name: Requirement implementation\",\n      \"about: Implement a canonical requirement tracked in the planning repo\",\n      'title: \"feat: implement <REQ-ID> — <short summary>\"',\n      `labels: ${labelsYaml}`,\n      \"---\",\n      \"\",\n      ...requirementBlock.split(\"\\n\"),\n      \"\",\n      \"> Add the `req:<ID>` label (e.g. `req:FR-042`) so this issue is traceable to the requirement across repos.\",\n      \"\",\n      \"## Summary\",\n      \"\",\n      \"<!-- What must change in THIS repo to satisfy the requirement above. -->\",\n      \"\",\n      \"## Acceptance Criteria\",\n      \"\",\n      \"- [ ]\",\n    ];\n\n    // marker:false — projen's marker comment would corrupt the YAML\n    // front-matter that GitHub parses at the top of the file.\n    new TextFile(project, path, {\n      marker: false,\n      committed: true,\n      lines,\n    });\n  }\n}\n","import { Component, Project, YamlFile } from \"projen\";\nimport { JobPermission } from \"projen/lib/github/workflows-model\";\nimport type { NodeProject } from \"projen/lib/javascript\";\nimport type { AgentRuleBundle } from \"../agent/agent-config-options\";\n\n/** A single GitHub label definition for EndBug/label-sync. */\nexport interface LabelDefinition {\n  /** Label name (e.g. \"priority:high\"). */\n  readonly name: string;\n\n  /** Hex color without the leading `#` (e.g. \"B60205\"). */\n  readonly color: string;\n\n  /** Short description shown in the GitHub UI. */\n  readonly description: string;\n}\n\n/** Options for the sync-labels workflow and labels config file. */\nexport interface SyncLabelsOptions {\n  /**\n   * Additional labels to sync alongside the standard defaults.\n   * Merged with DEFAULT_STATUS_LABELS, DEFAULT_PRIORITY_LABELS, and\n   * DEFAULT_TYPE_LABELS (standard labels are always included).\n   */\n  readonly labels?: ReadonlyArray<LabelDefinition>;\n\n  /**\n   * Remove labels from the repo that are not in the config file.\n   * @default true\n   */\n  readonly deleteOtherLabels?: boolean;\n\n  /**\n   * Workflow file name (display name in the Actions tab).\n   * @default \"sync-labels\"\n   */\n  readonly workflowName?: string;\n\n  /**\n   * Agent bundles whose contributed labels should be merged into\n   * `.github/labels.yml`. Typically populated by the project type from\n   * `AgentConfig.of(project)?.activeBundles` so bundle-supplied labels\n   * only appear when the bundle is actually enabled.\n   *\n   * Merge order: Tier 1 defaults → bundle labels → user-supplied `labels`\n   * (later entries override earlier ones on name collision).\n   */\n  readonly bundles?: ReadonlyArray<AgentRuleBundle>;\n}\n\n/** Default status labels. */\nexport const DEFAULT_STATUS_LABELS: ReadonlyArray<LabelDefinition> = [\n  {\n    name: \"status:ready\",\n    color: \"0E8A16\",\n    description: \"Task is ready for pickup\",\n  },\n  {\n    name: \"status:in-progress\",\n    color: \"FBCA04\",\n    description: \"Actively being worked on\",\n  },\n  {\n    name: \"status:ready-for-review\",\n    color: \"1D76DB\",\n    description: \"PR opened and awaiting review\",\n  },\n  {\n    name: \"status:blocked\",\n    color: \"D93F0B\",\n    description: \"Blocked on a dependency or question\",\n  },\n  {\n    name: \"status:done\",\n    color: \"6F42C1\",\n    description: \"Task completed and closed\",\n  },\n  {\n    name: \"status:deferred\",\n    color: \"C2E0C6\",\n    description: \"Intentionally parked — not ready for pickup\",\n  },\n  {\n    name: \"status:needs-attention\",\n    color: \"FF0000\",\n    description: \"Requires human review\",\n  },\n];\n\n/** Default priority labels. */\nexport const DEFAULT_PRIORITY_LABELS: ReadonlyArray<LabelDefinition> = [\n  {\n    name: \"priority:critical\",\n    color: \"B60205\",\n    description: \"Critical priority — address immediately\",\n  },\n  {\n    name: \"priority:high\",\n    color: \"D93F0B\",\n    description: \"High priority — pick before normal\",\n  },\n  {\n    name: \"priority:medium\",\n    color: \"E4E669\",\n    description: \"Medium priority\",\n  },\n  {\n    name: \"priority:low\",\n    color: \"D4C5F9\",\n    description: \"Low priority — skip if higher-priority work exists\",\n  },\n  {\n    name: \"priority:trivial\",\n    color: \"EDEDED\",\n    description: \"Trivial priority — address when convenient\",\n  },\n];\n\n/** Default type labels — one per conventional commit type. */\nexport const DEFAULT_TYPE_LABELS: ReadonlyArray<LabelDefinition> = [\n  {\n    name: \"type:feat\",\n    color: \"1D76DB\",\n    description: \"New feature or functionality\",\n  },\n  {\n    name: \"type:fix\",\n    color: \"D73A4A\",\n    description: \"Bug fix\",\n  },\n  {\n    name: \"type:docs\",\n    color: \"0075CA\",\n    description: \"Documentation only\",\n  },\n  {\n    name: \"type:style\",\n    color: \"BFD4F2\",\n    description: \"Code style (formatting, whitespace) — no logic change\",\n  },\n  {\n    name: \"type:refactor\",\n    color: \"A2EEEF\",\n    description: \"Code restructure — no feature or fix\",\n  },\n  {\n    name: \"type:perf\",\n    color: \"F9D0C4\",\n    description: \"Performance improvement\",\n  },\n  {\n    name: \"type:test\",\n    color: \"BFD4F2\",\n    description: \"Adding or updating tests\",\n  },\n  {\n    name: \"type:build\",\n    color: \"E6CCF5\",\n    description: \"Build system or external dependencies\",\n  },\n  {\n    name: \"type:ci\",\n    color: \"D4C5F9\",\n    description: \"CI configuration changes\",\n  },\n  {\n    name: \"type:chore\",\n    color: \"E6E6E6\",\n    description: \"Maintenance tasks (deps, tooling, config)\",\n  },\n  {\n    name: \"type:revert\",\n    color: \"EDEDED\",\n    description: \"Revert a previous commit\",\n  },\n  {\n    name: \"type:release\",\n    color: \"0E8A16\",\n    description: \"Release preparation and version bumps\",\n  },\n  {\n    name: \"type:hotfix\",\n    color: \"B60205\",\n    description: \"Urgent production fix\",\n  },\n];\n\nconst DEFAULT_WORKFLOW_NAME = \"sync-labels\";\nconst LABELS_CONFIG_PATH = \".github/labels.yml\";\n\n/**\n * Hard limit GitHub's Labels API enforces on the `description` field.\n * EndBug/label-sync rejects (and the API returns an opaque error for)\n * any label whose description exceeds this length, which silently\n * breaks the sync workflow downstream.\n */\nexport const MAX_LABEL_DESCRIPTION_LENGTH = 100;\n\n/**\n * Adds a labels config file and a GitHub Actions workflow that syncs\n * labels to the repository using EndBug/label-sync.\n */\nexport function addSyncLabelsWorkflow(\n  project: NodeProject,\n  options: SyncLabelsOptions,\n): void {\n  const workflowName = options.workflowName ?? DEFAULT_WORKFLOW_NAME;\n  const deleteOtherLabels = options.deleteOtherLabels ?? true;\n\n  // Merge order: Tier 1 defaults → bundle labels → user-supplied. Later\n  // entries override earlier ones on name collision, so a consumer can\n  // always override a bundle-contributed label without disabling the bundle.\n  const labelMap = new Map<string, LabelDefinition>();\n  for (const label of DEFAULT_STATUS_LABELS) {\n    labelMap.set(label.name, label);\n  }\n  for (const label of DEFAULT_PRIORITY_LABELS) {\n    labelMap.set(label.name, label);\n  }\n  for (const label of DEFAULT_TYPE_LABELS) {\n    labelMap.set(label.name, label);\n  }\n  for (const bundle of options.bundles ?? []) {\n    for (const label of bundle.labels ?? []) {\n      labelMap.set(label.name, label);\n    }\n  }\n  for (const label of options.labels ?? []) {\n    labelMap.set(label.name, label);\n  }\n  const allLabels = [...labelMap.values()];\n\n  // Fail fast at synth time when any description exceeds GitHub's hard\n  // limit. Otherwise the bug only surfaces when EndBug/label-sync runs\n  // on push to main and returns an opaque API error, with no mention\n  // of length anywhere in the failure log.\n  const overlength = allLabels.filter(\n    (l) => (l.description ?? \"\").length > MAX_LABEL_DESCRIPTION_LENGTH,\n  );\n  if (overlength.length > 0) {\n    const offenders = overlength\n      .map(\n        (l) =>\n          `  - ${l.name} (${(l.description ?? \"\").length} chars): ${l.description}`,\n      )\n      .join(\"\\n\");\n    throw new Error(\n      `The following label descriptions exceed GitHub's ${MAX_LABEL_DESCRIPTION_LENGTH}-char limit and would break the sync-labels workflow:\\n${offenders}`,\n    );\n  }\n\n  // Generate .github/labels.yml\n  new LabelsFile(project, allLabels);\n\n  // Generate the sync workflow\n  const workflow = project.github?.addWorkflow(workflowName);\n  if (!workflow) {\n    return;\n  }\n\n  workflow.on({\n    push: {\n      branches: [\"main\"],\n      paths: [LABELS_CONFIG_PATH],\n    },\n    workflowDispatch: {},\n  });\n\n  workflow.addJobs({\n    sync: {\n      name: \"Sync labels\",\n      runsOn: [\"ubuntu-latest\"],\n      permissions: {\n        contents: JobPermission.READ,\n        issues: JobPermission.WRITE,\n      },\n      steps: [\n        {\n          name: \"Checkout\",\n          uses: \"actions/checkout@v6\",\n        },\n        {\n          name: \"Sync labels\",\n          uses: \"EndBug/label-sync@v2\",\n          with: {\n            \"config-file\": LABELS_CONFIG_PATH,\n            \"delete-other-labels\": deleteOtherLabels,\n            token: \"${{ secrets.GITHUB_TOKEN }}\",\n          },\n        },\n      ],\n    },\n  });\n}\n\n/**\n * Projen component that writes .github/labels.yml.\n * Separated so the YAML file participates in the normal synth lifecycle.\n */\nclass LabelsFile extends Component {\n  constructor(project: Project, labels: ReadonlyArray<LabelDefinition>) {\n    super(project);\n\n    new YamlFile(project, LABELS_CONFIG_PATH, {\n      obj: labels.map((l) => ({\n        name: l.name,\n        color: l.color,\n        description: l.description,\n      })),\n      committed: true,\n    });\n  }\n}\n","import { Component, JsonFile } from \"projen\";\nimport { TypeScriptProject } from \"projen/lib/typescript\";\n\n/*******************************************************************************\n *\n * TsdocConfig\n *\n * Emits `tsdoc.json` at the project root so `eslint-plugin-tsdoc` recognises\n * the JSDoc tags consuming code commonly uses but that are not in the\n * default TSDoc tag list:\n *\n * - Workspace-scope package references (such as `@codedrifters` or\n *   `@openhi`) registered as modifier tags so prose like\n *   `See @codedrifters/configulator` does not trip `tsdoc-at-sign-in-word`.\n * - Common JSDoc convention tags (default, defaultValue, experimental, and\n *   the internal-marker tag) registered as modifier tags so they do\n *   not trip `tsdoc-undefined-tag`.\n *\n * Without `tsdoc.json` configulator emits, downstream consumers see ~1,250\n * `tsdoc-at-sign-in-word` warnings and ~17 `tsdoc-undefined-tag` warnings\n * per build on every scoped-package reference in a JSDoc comment.\n *\n * Note: the tag names above are intentionally written without their leading\n * at-sign. `tsc --stripInternal` (which configulator enables) treats the\n * file-leading banner as the JSDoc comment of the next declaration, and a\n * bare at-sign-prefixed `internal` token anywhere in that banner — even\n * inside a backtick code span — strips the following interface from the\n * emitted `.d.ts`.\n *\n ******************************************************************************/\n\n/**\n * Configuration options for {@link TsdocConfig}.\n */\nexport interface TsdocConfigOptions {\n  /**\n   * Workspace scopes to register as TSDoc modifier tags so prose references\n   * like `@codedrifters/configulator` are not treated as malformed TSDoc\n   * tags.\n   *\n   * Each entry should include the leading `@` (e.g. `@codedrifters`,\n   * `@openhi`). When omitted, the scope is derived from the consuming\n   * project's `packageName` (the substring up to the first `/`, when the\n   * name starts with `@`). `@codedrifters` is always included so internal\n   * configulator references work out of the box.\n   */\n  readonly workspaceScopes?: Array<string>;\n\n  /**\n   * Additional modifier tag names (each starting with `@`) to register\n   * beyond the standard set: default, defaultValue, experimental, and\n   * the internal-marker tag.\n   *\n   * Note: the tag names above are intentionally written without their\n   * leading at-sign. `tsc --stripInternal` (which configulator enables)\n   * strips any declaration whose JSDoc contains the bare at-sign-prefixed\n   * `internal` tag — even when the token sits inside a backtick code span\n   * — and that strips this field from the published `.d.ts` rollup.\n   *\n   * @default []\n   */\n  readonly additionalModifierTags?: Array<string>;\n}\n\n/**\n * JSDoc convention modifier tags configulator registers in every emitted\n * `tsdoc.json`. `@default` is widely used across the npm ecosystem but is\n * not in the default `@microsoft/tsdoc` tag list. Built-in TSDoc tags\n * such as defaultValue, experimental, and the internal-marker tag are\n * intentionally NOT included — re-registering a built-in tag trips\n * `Error applying TSDoc configuration: A tag is already defined`, which\n * causes the parser to drop the entire custom config and flood lint with\n * cascading `tsdoc-undefined-tag` warnings on workspace-scope references.\n *\n * Note: the built-in tag names above are written without leading at-signs\n * for the same reason documented on `TsdocConfigOptions` — a bare\n * at-sign-prefixed `internal` token inside this banner would cause\n * `tsc --stripInternal` to strip the following declaration from the\n * emitted `.d.ts`.\n */\nconst STANDARD_MODIFIER_TAGS: Array<string> = [\"@default\"];\n\n/**\n * JSDoc convention inline tags configulator registers in every emitted\n * `tsdoc.json`. `{@code …}` is widely used across the npm ecosystem but is\n * not in the default `@microsoft/tsdoc` tag list. `{@link …}` and\n * `{@inheritDoc …}` are intentionally omitted — they are built-in TSDoc\n * inline tags and re-registering them would trip the duplicate-definition\n * cascade described on `STANDARD_MODIFIER_TAGS`.\n */\nconst STANDARD_INLINE_TAGS: Array<string> = [\"@code\"];\n\n/**\n * Always-on workspace scope. CodeDrifters packages cross-reference each\n * other often enough that this scope is registered on every project even\n * when the consumer's own package lives under a different scope.\n */\nconst ALWAYS_ON_SCOPES: Array<string> = [\"@codedrifters\"];\n\n/**\n * Emits `tsdoc.json` so `eslint-plugin-tsdoc` recognises workspace-scope\n * package references and the standard JSDoc modifier tag set.\n */\nexport class TsdocConfig extends Component {\n  /**\n   * Derive a workspace scope from a scoped package name (`@scope/name`).\n   * Returns `undefined` when the name is unscoped.\n   *\n   * @internal\n   */\n  public static scopeFromPackageName(\n    packageName: string | undefined,\n  ): string | undefined {\n    if (!packageName || !packageName.startsWith(\"@\")) {\n      return undefined;\n    }\n    const slash = packageName.indexOf(\"/\");\n    if (slash <= 1) {\n      return undefined;\n    }\n    return packageName.slice(0, slash);\n  }\n\n  constructor(project: TypeScriptProject, options: TsdocConfigOptions = {}) {\n    super(project);\n\n    /**\n     * Build the workspace-scope set. Start from caller-provided scopes,\n     * fall back to the project's own scope, and always include the\n     * always-on set. Deduplicate so the emitted JSON is stable.\n     */\n    const scopeFromName = TsdocConfig.scopeFromPackageName(\n      project.package.packageName,\n    );\n    const scopeSet = new Set<string>([\n      ...ALWAYS_ON_SCOPES,\n      ...(scopeFromName ? [scopeFromName] : []),\n      ...(options.workspaceScopes ?? []),\n    ]);\n\n    /**\n     * Build the modifier-tag set. Workspace scopes register as modifier\n     * tags alongside the standard set + any additional caller-provided\n     * names. Deduplicate to keep the emitted JSON deterministic.\n     */\n    const modifierTagSet = new Set<string>([\n      ...STANDARD_MODIFIER_TAGS,\n      ...Array.from(scopeSet),\n      ...(options.additionalModifierTags ?? []),\n    ]);\n\n    /**\n     * Inline-tag set. Currently fixed to `STANDARD_INLINE_TAGS` — kept as\n     * a separate set so future additions follow the same dedupe/sort\n     * shape as the modifier set.\n     */\n    const inlineTagSet = new Set<string>([...STANDARD_INLINE_TAGS]);\n\n    /**\n     * `tsdoc.json` schema: an array of tag definitions, each with a\n     * `tagName` (starts with `@`), `syntaxKind` (`\"modifier\"` /\n     * `\"inline\"` / `\"block\"`), and `allowMultiple`. Sort by `tagName`\n     * across the combined set so the emitted file is stable across\n     * synth runs. Built-in TSDoc tags must NOT appear here — see the\n     * comment on `STANDARD_MODIFIER_TAGS` for the cascade this avoids.\n     */\n    const tagDefinitions = [\n      ...Array.from(modifierTagSet).map((tagName) => ({\n        tagName,\n        syntaxKind: \"modifier\",\n        allowMultiple: true,\n      })),\n      ...Array.from(inlineTagSet).map((tagName) => ({\n        tagName,\n        syntaxKind: \"inline\",\n        allowMultiple: true,\n      })),\n    ].sort((a, b) => a.tagName.localeCompare(b.tagName));\n\n    /**\n     * `marker: false` — the TSDoc JSON schema is strict\n     * (`additionalProperties: false`) and rejects projen's usual\n     * `\"//\"` generated-by comment. Without this, `eslint-plugin-tsdoc`\n     * fails to load `tsdoc.json`\n     * (`Error loading config file: data must NOT have additional properties`),\n     * falls back to the built-in tag set, and floods every release-workflow\n     * run with cascading `tsdoc-undefined-tag` warnings. The\n     * `linguist-generated` git attribute still flags the file as generated\n     * in diffs.\n     */\n    new JsonFile(project, \"tsdoc.json\", {\n      marker: false,\n      obj: {\n        $schema:\n          \"https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json\",\n        tagDefinitions,\n      },\n    });\n\n    /**\n     * `tsdoc.json` is a build-time lint config — it does not belong in the\n     * published npm tarball.\n     */\n    project.addPackageIgnore(\"tsdoc.json\");\n  }\n}\n","import { relative } from \"node:path\";\nimport { Component } from \"projen\";\nimport { TypeScriptProject } from \"projen/lib/typescript\";\nimport { ensureRelativePathStartsWithDot } from \"projen/lib/util/path\";\n\n/*******************************************************************************\n *\n * Update / customize typescript configs for a project.\n *\n * Update typescript paths in tsconfig so we don't have to compile packages to\n * dist in order to see changes.\n *\n ******************************************************************************/\nexport class TypeScriptConfig extends Component {\n  constructor(project: TypeScriptProject) {\n    super(project);\n\n    /**\n     * Container for paths to insert at the end.\n     */\n    let tsPaths = {};\n\n    const workspaceDeps = project.deps.all.filter(\n      (d) => d.version === \"workspace:*\",\n    );\n\n    workspaceDeps.forEach((dep) => {\n      const subproject = (\n        project.root.subprojects as Array<TypeScriptProject>\n      ).find((p) => p.package.packageName === dep.name);\n\n      if (!subproject) {\n        throw new Error(`Could not find subproject ${dep.name} in monorepo.`);\n      }\n\n      tsPaths = {\n        ...tsPaths,\n        [dep.name]: [\n          ensureRelativePathStartsWithDot(\n            relative(project.outdir, subproject.outdir),\n          ),\n        ],\n      };\n    });\n\n    project.tsconfig?.file.addOverride(\"compilerOptions.paths\", tsPaths);\n    project.tsconfigDev?.file.addOverride(\"compilerOptions.paths\", tsPaths);\n  }\n}\n","import { awscdk, Dependencies, ReleasableCommits } from \"projen\";\nimport { BuildWorkflow } from \"projen/lib/build\";\nimport {\n  NodePackageManager,\n  Transform,\n  UpgradeDependenciesSchedule,\n} from \"projen/lib/javascript\";\nimport { ReleaseTrigger } from \"projen/lib/release\";\nimport { merge } from \"ts-deepmerge\";\nimport { CHANGELOG_TYPES, resolveVersionrcOptions } from \"./changelog-types\";\nimport { MonorepoProject } from \"./monorepo-project\";\nimport { applyPackagePrivate, PackagePrivateOptions } from \"./package-private\";\nimport { resolveAwsCdkProjectOutdir } from \"./resolve-outdir\";\nimport { TestRunner } from \"./typescript-project\";\nimport { AgentConfig } from \"../agent/agent-config\";\nimport { AgentConfigOptions } from \"../agent/agent-config-options\";\nimport {\n  AwsDeploymentConfig,\n  AwsDeploymentTarget,\n  AwsDeploymentTargetOptions,\n  CdkCli,\n  CdkCliOptions,\n} from \"../aws\";\nimport { PnpmWorkspace } from \"../pnpm\";\nimport { ResetTask, ResetTaskOptions } from \"../tasks/reset-task\";\nimport { TurboRepo } from \"../turbo\";\nimport { VERSION } from \"../versions\";\nimport { Vitest, VitestOptions } from \"../vitest\";\nimport {\n  AwsDeployWorkflow,\n  DeployDiffOptions,\n  DeployWorkflowOptions,\n} from \"../workflows/aws-deploy-workflow\";\nimport {\n  AwsTeardownWorkflow,\n  AwsTeardownWorkflowOptions,\n} from \"../workflows/aws-teardown-workflow\";\n\n/**\n * Configuration options for AwsCdkProject.\n *\n * AwsCdkProject must be parented to a `MonorepoProject` — the constructor\n * throws otherwise. Configulator assumes a single-package repo is still a\n * monorepo (with one workspace) so all conventions hold uniformly.\n */\nexport interface AwsCdkProjectOptions\n  extends\n    Omit<\n      awscdk.AwsCdkTypeScriptAppOptions,\n      \"defaultReleaseBranch\" | \"cdkVersion\"\n    >,\n    PackagePrivateOptions {\n  /**\n   * Minimum version of `aws-cdk-lib` to depend on.\n   *\n   * Optional, and normally omitted: the rendered specifier is `catalog:`\n   * whenever the parent `MonorepoProject`'s pnpm catalog carries an entry, so\n   * that catalog decides the resolved version. Supplying a value that\n   * disagrees with the entry throws rather than being silently discarded —\n   * bump the catalog instead. Only where the catalog has no entry at all does\n   * this value render, and then it must be an exact version.\n   *\n   * Listing `aws-cdk-lib` in `deps`, `devDeps`, or `peerDeps` is never the way\n   * to move it — the first is overridden by the pin and the other two throw.\n   *\n   * @default - the parent monorepo's catalog pin for `aws-cdk-lib`\n   */\n  readonly cdkVersion?: string;\n\n  /**\n   * Minimum version of the `constructs` library to depend on.\n   *\n   * Catalog-pinned on the same terms as `cdkVersion` — omit it, or keep it\n   * in step with the parent monorepo's catalog entry for `constructs`.\n   *\n   * @default - the parent monorepo's catalog pin for `constructs`\n   */\n  readonly constructsVersion?: string;\n\n  /**\n   * Options for the `CdkCli` component that every `cdk` invocation this\n   * project renders flows through — per-stage command defaults, per-account\n   * overrides, and the pinned CLI version.\n   *\n   * The component has to be seeded here rather than constructed afterwards.\n   * This constructor creates an `AwsDeploymentConfig`, which auto-creates a\n   * default `CdkCli` when the project has none, and `CdkCli.of()` resolves to\n   * the *first* matching component — so a `new CdkCli(project, options)` built\n   * once the constructor has returned is silently unreachable: no error, no\n   * warning, and the generated workflows render as if nothing was passed.\n   *\n   * Use it to declare a setting once per project instead of repeating it on\n   * every target via `AwsDeploymentTargetOptions.cdkOptions` — for example\n   * pinning `cdk diff --method=change-set` across stages so a diff never\n   * degrades to a template-only comparison and reports it as authoritative.\n   *\n   * @see `docs/src/content/docs/packages/@codedrifters/configulator/cdk-cli.md`\n   * @default - a `CdkCli` carrying no consumer overrides, identical to the one\n   * `AwsDeploymentConfig` would have auto-created\n   */\n  readonly cdkCliOptions?: CdkCliOptions;\n\n  /**\n   * AWS deployment targets (dev / stage / prod accounts and regions). Each\n   * entry creates an `AwsDeploymentTarget` component on the project.\n   */\n  readonly deploymentTargets?: Array<AwsDeploymentTargetOptions>;\n\n  /**\n   * AWS deploy workflows. If omitted, one workflow is auto-generated per\n   * unique `awsStageType` present in `deploymentTargets`. Each auto-generated\n   * workflow renders to its own `.github/workflows/*.yml` file.\n   *\n   * Pass an empty array (`[]`) to opt out of auto-derivation entirely without\n   * supplying any workflows of your own — the array is truthy and short-circuits\n   * the default. Useful when you intend to attach deploy jobs to an existing\n   * build workflow yourself.\n   */\n  readonly deployWorkflows?: Array<DeployWorkflowOptions>;\n\n  /**\n   * Opt every auto-derived deploy workflow into a `cdk diff` job per target.\n   *\n   * Forwarded onto each workflow derived from `deploymentTargets`. An explicit\n   * `deployWorkflows[].diff` overrides it for that stage, matching the\n   * `buildWorkflowOptions` precedence rule.\n   *\n   * `environment` is not usable here: auto-derived workflows set no `gate`, so\n   * there is no environment for the diff jobs to borrow and the flag fails\n   * synth. Set it on the individual `deployWorkflows` entry that gates.\n   *\n   * @see `docs/packages/@codedrifters/configulator/workflows/aws-deploy-workflow.md`\n   * @default - no diff jobs are emitted\n   */\n  readonly diff?: DeployDiffOptions;\n\n  /**\n   * Optional shared `BuildWorkflow` to attach all auto-derived deploy jobs to.\n   * When set, every workflow generated from `deploymentTargets` re-uses this\n   * build workflow instead of creating its own. Default behavior (omit) is one\n   * separate yml file per stage type.\n   *\n   * Distinct from `buildWorkflow: boolean` inherited from\n   * `AwsCdkTypeScriptAppOptions`, which toggles whether the projen-managed\n   * build workflow is generated at all.\n   */\n  readonly sharedBuildWorkflow?: BuildWorkflow;\n\n  /**\n   * Test runner to use.\n   *\n   * @default TestRunner.JEST\n   */\n  readonly testRunner?: TestRunner;\n\n  /**\n   * Options for Vitest (only used when testRunner is 'vitest').\n   */\n  readonly vitestOptions?: VitestOptions;\n\n  /**\n   * Enable the reset task that deletes all build artifacts.\n   *\n   * @default true\n   */\n  readonly resetTask?: boolean;\n\n  /**\n   * Options for the reset task.\n   */\n  readonly resetTaskOptions?: ResetTaskOptions;\n\n  /**\n   * AI agent configuration (Cursor, Claude Code rules). Opt-in per project;\n   * not inherited from the parent `MonorepoProject`.\n   *\n   * @default false\n   */\n  readonly agentConfig?: AgentConfigOptions | boolean;\n\n  /**\n   * Scheduled teardown workflow options. When provided, an `AwsTeardownWorkflow`\n   * is attached to the parent `MonorepoProject` that periodically deletes\n   * orphaned CloudFormation stacks whose branch no longer exists.\n   */\n  readonly teardownWorkflow?: AwsTeardownWorkflowOptions;\n}\n\n/**\n * AWS CDK TypeScript application with CodeDrifters conventions baked in.\n *\n * Always creates an `AwsDeploymentConfig` component (even with zero deployment\n * targets) so the `synth` task is consistently rewritten to emit into\n * `dist/<project-path>/cdk.out`. This is intentional and not opt-out: it\n * funnels every package's CDK output into one root-level `dist/` tree so\n * GitHub Actions workflows can pass artifacts between jobs uniformly.\n */\nexport class AwsCdkProject extends awscdk.AwsCdkTypeScriptApp {\n  constructor(userOptions: AwsCdkProjectOptions) {\n    /**\n     * Configulator requires every project to live inside a MonorepoProject.\n     * The catalog-based `@types/node` pin, the workspace install hook, and the\n     * deploy workflow all assume the parent exists.\n     */\n    if (!(userOptions.parent instanceof MonorepoProject)) {\n      throw new Error(\n        \"AwsCdkProject must be parented to a MonorepoProject. Pass `parent: <MonorepoProject>` in the project options.\",\n      );\n    }\n\n    const parent = userOptions.parent;\n    const pnpmVersion = parent.pnpmVersion;\n    const pnpmWorkspace = PnpmWorkspace.of(parent);\n    const defaultCatalog = pnpmWorkspace?.defaultCatalog ?? {};\n\n    /*************************************************************************\n     *\n     * Reject catalog-managed packages in `devDeps` / `peerDeps`\n     *\n     * The pin re-registers both packages as RUNTIME deps after `super()`, and\n     * `Dependencies.addDependency` keys its replace-vs-append decision on name\n     * *and* type — so only a RUNTIME entry is replaced. A `devDeps` or\n     * `peerDeps` entry survives it and renders a second, uncontrolled\n     * specifier beside the pin. Reject those the same way an out-of-step\n     * `cdkVersion` is rejected, rather than discard them silently.\n     *\n     ************************************************************************/\n\n    rejectCatalogManagedDeps(\"devDeps\", userOptions.devDeps);\n    rejectCatalogManagedDeps(\"peerDeps\", userOptions.peerDeps);\n\n    /*************************************************************************\n     *\n     * Resolve CDK versions from the catalog\n     *\n     * `aws-cdk-lib` and `constructs` are re-registered as `catalog:` after\n     * `super()`, so the parent monorepo's catalog — not these options —\n     * decides what actually resolves. Read the versions back out of that\n     * catalog so projen's own view of them can never drift from what gets\n     * installed, and reject both ways it could stop being a real pin: a\n     * range-valued catalog entry, or an explicit option that disagrees.\n     *\n     * Each call also yields the specifier to render, which is `catalog:` only\n     * while the catalog actually carries an entry to resolve through.\n     *\n     ************************************************************************/\n\n    const cdkPin = resolveCatalogPin(\n      \"cdkVersion\",\n      \"aws-cdk-lib\",\n      userOptions.cdkVersion,\n      VERSION.AWS_CDK_LIB_VERSION,\n      defaultCatalog,\n    );\n    const constructsPin = resolveCatalogPin(\n      \"constructsVersion\",\n      \"constructs\",\n      userOptions.constructsVersion,\n      VERSION.AWS_CONSTRUCTS_VERSION,\n      defaultCatalog,\n    );\n    const cdkVersion = cdkPin.version;\n    const constructsVersion = constructsPin.version;\n\n    /*************************************************************************\n     *\n     * Resolve outdir\n     *\n     * When the caller omits `outdir`, derive it from the scoped package\n     * name (`packageName ?? name`) as `apps/<scope>/<name>`. This enforces\n     * the monorepo-layout contract (ADR-006) without requiring every\n     * sub-project to restate its own path.\n     *\n     ************************************************************************/\n\n    const resolvedOutdir =\n      userOptions.outdir ??\n      resolveAwsCdkProjectOutdir(userOptions.packageName ?? userOptions.name);\n\n    /*************************************************************************\n     *\n     * Default Options\n     *\n     ************************************************************************/\n\n    const testRunner = userOptions.testRunner ?? TestRunner.JEST;\n    const useJest = testRunner === TestRunner.JEST;\n\n    const defaultOptions: Omit<AwsCdkProjectOptions, \"name\"> & {\n      defaultReleaseBranch: string;\n      cdkVersion: string;\n    } = {\n      defaultReleaseBranch: \"main\",\n\n      /**\n       * Outdir defaults to `apps/<scope>/<name>` when the caller omits\n       * it. Explicit overrides in `userOptions` always win via the\n       * merge below.\n       */\n      outdir: resolvedOutdir,\n\n      /**\n       * Enable reset task by default.\n       */\n      resetTask: true,\n\n      /**\n       * Packaging options.\n       */\n      packageManager: NodePackageManager.PNPM,\n      pnpmVersion: pnpmVersion,\n      licensed: userOptions.license !== undefined || false,\n      copyrightOwner: \"CodeDrifters\",\n      release: false,\n\n      /**\n       * Don't add sample code.\n       */\n      sampleCode: false,\n\n      /**\n       * CDK versions read back out of the catalog above. The framework and\n       * its `constructs` peer render as `catalog:` (see after `super()`);\n       * these keep projen's own view of the versions in step with whatever\n       * that catalog pins, rather than its `^10.5.1`-style fallbacks.\n       */\n      cdkVersion,\n      constructsVersion,\n      cdkCliVersion: VERSION.AWS_CDK_CLI_VERSION,\n\n      ...(useJest\n        ? {\n            /**\n             * Make sure jest config is stored outside of package.json and use\n             * SWC for faster compilation (matches TypeScriptProject).\n             */\n            jestOptions: {\n              configFilePath: \"jest.config.json\",\n              jestConfig: {\n                roots: [`<rootDir>/src`],\n                transform: {\n                  [\"^.+\\\\.[t]sx?$\"]: new Transform(\"@swc/jest\"),\n                },\n                moduleFileExtensions: [\"js\", \"ts\"],\n              },\n            },\n            devDeps: [\"@swc/jest\", \"@swc/core\"] as Array<string>,\n          }\n        : {\n            jest: false,\n            devDeps: [] as Array<string>,\n          }),\n\n      /**\n       * Turn on prettier formatting.\n       */\n      prettier: true,\n\n      /**\n       * Don't package test files.\n       */\n      npmIgnoreOptions: {\n        ignorePatterns: [\"*.spec.*\", \"*.test.*\"],\n      },\n\n      /**\n       * Tests are co-located in `src`, so projen 0.100.4+'s test-directory\n       * tsconfig would only ever create an empty `test/` folder holding a\n       * lone `test/tsconfig.json`. Disable it — the main `tsconfig.json`\n       * already covers the co-located tests for the typescript-eslint\n       * project service (see #830), so a separate dev/test config is dead\n       * weight.\n       */\n      disableTsconfigDev: true,\n\n      /**\n       * Options for the automated dependency upgrade task / workflow.\n       * Exclude any packages managed by the parent project's default catalog\n       * so the catalog stays the source of truth.\n       */\n      depsUpgrade: true,\n      depsUpgradeOptions: {\n        workflow: false,\n        exclude: Object.keys(defaultCatalog),\n        workflowOptions: {\n          schedule: UpgradeDependenciesSchedule.WEEKLY,\n        },\n        cooldown: 7,\n      },\n\n      /**\n       * Only release when the package's own sources or `package.json`\n       * (version, dependencies) change.\n       *\n       * Deliberately narrower than the `\".\"` pathspec the bump decision and\n       * the changelog use below. Widening this to `<outdir>/**` would make\n       * all three filters select exactly the same files, but it also makes\n       * every package-local edit releasable — a test-only change, or the\n       * `.projen/` regeneration that a sibling package's change produces. In\n       * this monorepo that regeneration is routine, so the aligned trigger\n       * publishes versions whose tarballs are byte-identical to the previous\n       * one.\n       *\n       * The asymmetry that remains is benign: a package-local commit outside\n       * `src` cannot start a release on its own, but is still described in\n       * the notes of the next release that something else triggers. Notes\n       * covering slightly more than the trigger is the right direction for\n       * the two to disagree in.\n       */\n      releaseTrigger: ReleaseTrigger.continuous({\n        paths: [`${resolvedOutdir}/src/**`, `${resolvedOutdir}/package.json`],\n      }),\n\n      /**\n       * Scope the other two release filters to the package folder, the same\n       * slice of history the trigger above reads from.\n       *\n       * `versionrcOptions.path` reaches `commit-and-tag-version`, which\n       * forwards it to `conventional-changelog` as a `git log` pathspec —\n       * without it the changelog between two package-scoped tags spans every\n       * commit in the monorepo. `releasableCommits` appends the same pathspec\n       * to the command that decides whether to bump at all; without it a\n       * package with no relevant changes still cuts a release, just with an\n       * empty changelog.\n       *\n       * `\".\"` rather than `resolvedOutdir`: both commands run with their\n       * working directory already set to the package outdir. A single string\n       * is all `path` accepts — `git-raw-commits` splices it into `git log`\n       * as one argv entry (`push(\"--\", path)`), so the pathspec cannot be a\n       * list, so it cannot be narrowed to `src` plus `package.json` to match\n       * the trigger exactly.\n       *\n       * `types` gives every conventional-commit type a visible section. The\n       * preset hides or discards everything but `feat` and `fix` by default,\n       * while still bumping for them, which is what makes a package-local\n       * churn release ship notes holding nothing but a version heading. See\n       * `CHANGELOG_TYPES`.\n       */\n      versionrcOptions: { path: \".\", types: [...CHANGELOG_TYPES] },\n      releasableCommits: ReleasableCommits.everyCommit(\".\"),\n    };\n\n    /*************************************************************************\n     *\n     * Merge defaults into user options\n     *\n     ************************************************************************/\n\n    const mergedOptions = merge(defaultOptions, userOptions);\n\n    const options: AwsCdkProjectOptions & awscdk.AwsCdkTypeScriptAppOptions = {\n      ...mergedOptions,\n\n      /**\n       * Both versions are the catalog's, resolved above — restate them after\n       * the merge so a supplied option can never reintroduce a value the\n       * catalog disagrees with. Restating `cdkVersion` also keeps the\n       * intersection type honest, since it is optional here but required by\n       * projen.\n       */\n      cdkVersion,\n      constructsVersion,\n\n      /**\n       * `ts-deepmerge` concatenates arrays, so a supplied changelog `types`\n       * arrives appended to `CHANGELOG_TYPES` — and the preset resolves each\n       * commit with `types.find(...)`, so our entry would win every lookup\n       * and the consumer's list would be inert. Replace, don't concatenate.\n       */\n      versionrcOptions: resolveVersionrcOptions(\n        mergedOptions.versionrcOptions,\n        userOptions.versionrcOptions,\n      ),\n    };\n\n    super(options);\n\n    /**\n     * Use catalog version for `@types/node` so all packages share a single\n     * pinned version.\n     */\n    this.addDevDeps(\"@types/node@catalog:\");\n\n    /**\n     * Projen's `AwsCdkDeps` renders the framework and its peer as caret\n     * ranges (`aws-cdk-lib@^2.264.0`, `constructs@^10.5.1`), so pnpm floats\n     * both within the major line and the configulator-managed catalog never\n     * actually pins them. Re-register each against the specifier resolved\n     * above — `addDependency` replaces the same name/type entry rather than\n     * duplicating it, and `AwsCdkTypeScriptApp` registers both as RUNTIME\n     * deps, which is what `addDeps` writes.\n     */\n    this.addDeps(\n      `aws-cdk-lib@${cdkPin.specifier}`,\n      `constructs@${constructsPin.specifier}`,\n    );\n\n    /**\n     * The main tsconfig now includes co-located `src/**` test files (no\n     * `**\\/*.test.*` exclude) so projen 0.100.4+'s typescript-eslint project\n     * service can resolve them (issue #830). Because `tsc --build` also uses\n     * the main tsconfig, skip type-checking of dependency declaration files\n     * so the compile doesn't fail on test-runner types — Vitest pulls in\n     * Vite's `.d.ts`, which don't type-check under the package's classic\n     * `node` moduleResolution.\n     */\n    this.tsconfig?.file.addOverride(\"compilerOptions.skipLibCheck\", true);\n\n    /**\n     * When using Jest, remove ts-jest since we use `@swc/jest`.\n     * When using Vitest, add the Vitest component (test task + config + deps).\n     */\n    if (testRunner === TestRunner.VITEST) {\n      new Vitest(this, {\n        ...options.vitestOptions,\n        config: {\n          include: [\"src/**/*.{test,spec}.?(c|m)[jt]s?(x)\"],\n          ...options.vitestOptions?.config,\n        },\n      });\n    } else {\n      this.deps.removeDependency(\"ts-jest\");\n    }\n\n    /**\n     * Specify package manager in package.json.\n     */\n    this.package.file.addOverride(\n      \"packageManager\",\n      `pnpm@${options.pnpmVersion}`,\n    );\n\n    /**\n     * A CDK app is deployed, not published, so it renders `\"private\": true`\n     * by default and npm refuses to publish it by hand. Pass\n     * `packagePrivate: false` to opt out.\n     */\n    applyPackagePrivate(this, options);\n\n    /**\n     * Allow test files to use devDependencies. Projen disables the rule for\n     * `tests/*` only; we colocate tests next to source so we extend it.\n     */\n    this.eslint?.addOverride({\n      files: [\"**/*.test.*\", \"**/*.spec.*\"],\n      rules: {\n        \"import/no-extraneous-dependencies\": \"off\",\n      },\n    });\n\n    /**\n     * Some standard ignores for all projects.\n     */\n    this.gitignore?.addPatterns(\".DS_Store\", \"test-reports\", \"cdk.out\");\n    this.npmignore?.addPatterns(\"*.spec.*\", \"*.test.*\", \"__fixtures__\");\n\n    /**\n     * Seed the CdkCli before AwsDeploymentConfig gets the chance to auto-create\n     * a default one. That config resolves the component as\n     * `CdkCli.of(this) || new CdkCli(this)`, and `CdkCli.of` returns the first\n     * match — so the slot is taken for good by whichever instance exists first,\n     * and anything a consumer constructs after this constructor returns is\n     * silently unreachable. Constructed unconditionally to keep a single code\n     * path: with no `cdkCliOptions` this is exactly the empty-option instance\n     * AwsDeploymentConfig would have built for itself on the next line.\n     */\n    new CdkCli(this, options.cdkCliOptions ?? {});\n\n    /**\n     * Always create the AwsDeploymentConfig so the synth task is rewritten\n     * consistently. AwsDeploymentTarget instances will register themselves\n     * onto this config below.\n     */\n    new AwsDeploymentConfig(this);\n\n    /**\n     * Wire up deployment targets supplied via constructor options.\n     */\n    (options.deploymentTargets ?? []).forEach((targetOptions) =>\n      this.addDeploymentTarget(targetOptions),\n    );\n\n    /**\n     * Wire up deploy workflows. If `deployWorkflows` is undefined, derive one\n     * workflow per unique awsStageType present in the deployment targets.\n     * An explicit empty array opts out of auto-derivation.\n     */\n    const targetsForAutoDerive =\n      AwsDeploymentConfig.of(this)?.awsDeploymentTargets ?? [];\n    const deployWorkflows =\n      options.deployWorkflows ??\n      Array.from(new Set(targetsForAutoDerive.map((t) => t.awsStageType))).map(\n        (awsStageType): DeployWorkflowOptions => {\n          // A diff job is a post-build job and conflicts with nothing a shared\n          // build workflow provides, so unlike `buildWorkflowOptions` this\n          // forwards on both paths below. Omit the key entirely when unset so\n          // the no-options case stays byte-identical.\n          const diff = options.diff ? { diff: options.diff } : {};\n\n          // When a shared build workflow is supplied, the deploy jobs re-use\n          // it and the runner is owned by that external workflow. Forwarding\n          // `buildWorkflowOptions` here would trip AwsDeployWorkflow's\n          // both-provided guard, so emit only the build workflow.\n          if (options.sharedBuildWorkflow) {\n            return {\n              awsStageType,\n              buildWorkflow: options.sharedBuildWorkflow,\n              ...diff,\n            };\n          }\n\n          // Otherwise forward the project-level `buildWorkflowOptions` (e.g.\n          // `runsOn`) onto each derived deploy build job. Omit the key entirely\n          // when unset so the no-options case stays byte-identical.\n          return {\n            awsStageType,\n            ...(options.buildWorkflowOptions\n              ? { buildWorkflowOptions: options.buildWorkflowOptions }\n              : {}),\n            ...diff,\n          };\n        },\n      );\n    deployWorkflows.forEach(\n      (workflowOptions) => new AwsDeployWorkflow(this, workflowOptions),\n    );\n\n    /**\n     * Optional teardown workflow. Attached to the parent MonorepoProject so\n     * it renders once per repo regardless of how many AwsCdkProjects exist.\n     */\n    if (options.teardownWorkflow) {\n      new AwsTeardownWorkflow(parent, options.teardownWorkflow);\n    }\n\n    /**\n     * If turbo is active in the parent project, configure it here.\n     */\n    const turboActive = TurboRepo.of(parent) !== undefined;\n    if (turboActive) {\n      const turbo = new TurboRepo(this);\n      // Only inputs here. Post-compile outputs are owned by\n      // `AwsDeploymentConfig`, which registers the root-dist `cdk.out` path\n      // from its own `preSynthesize` — the sole artifact post-compile writes,\n      // since `synth:silent` emits there and the `package` task (the other\n      // thing that would fill a local `dist/`) has no steps while `release`\n      // defaults to false. A package-local `dist/**` here declared an output\n      // nothing produces, so turbo cached an empty directory for it (#974).\n      turbo.postCompileTask?.inputs.push(\"src/**\");\n    }\n\n    /**\n     * AI agent configuration — opt-in per project. Does not propagate from\n     * the parent MonorepoProject so sub-projects don't render duplicate\n     * `.cursor/` / `.claude/` / `CLAUDE.md` files into their own outdir.\n     */\n    if (\n      options.agentConfig === true ||\n      typeof options.agentConfig === \"object\"\n    ) {\n      new AgentConfig(\n        this,\n        typeof options.agentConfig === \"object\" ? options.agentConfig : {},\n      );\n    }\n\n    /**\n     * Add reset task if enabled.\n     */\n    if (options.resetTask !== false) {\n      const defaultResetTaskOptions: ResetTaskOptions = {\n        pathsToRemove: [\n          \"node_modules\",\n          \"dist\",\n          \"lib\",\n          \"cdk.out\",\n          \"coverage\",\n          \"test-reports\",\n          \".turbo\",\n          \"tsconfig.tsbuildinfo\",\n          this.artifactsDirectory,\n        ],\n      };\n      const userResetTaskOptions = options.resetTaskOptions ?? {};\n      const resetTaskOptions: ResetTaskOptions = merge(\n        defaultResetTaskOptions,\n        {\n          ...userResetTaskOptions,\n          pathsToRemove: [\n            ...(defaultResetTaskOptions.pathsToRemove ?? []),\n            ...(userResetTaskOptions.pathsToRemove ?? []),\n          ],\n        },\n      );\n      new ResetTask(this, resetTaskOptions);\n    }\n\n    /**\n     * Route dependency installation through the parent MonorepoProject so the\n     * workspace install handles everything in one pass.\n     */\n    /* @ts-ignore access private method */\n    const originalResolve = this.package.resolveDepsAndWritePackageJson;\n    /* @ts-ignore access private method */\n    this.package.installDependencies = () => {\n      parent.requestInstallDependencies({\n        resolveDepsAndWritePackageJson: () =>\n          originalResolve.apply(this.package),\n      });\n    };\n    /* @ts-ignore access private method */\n    this.package.resolveDepsAndWritePackageJson = () => {};\n  }\n\n  /**\n   * Add an AWS deployment target to this project after construction. The\n   * target is registered on the existing `AwsDeploymentConfig` and immediately\n   * available for `AwsDeployWorkflow` consumption.\n   */\n  public addDeploymentTarget(\n    options: AwsDeploymentTargetOptions,\n  ): AwsDeploymentTarget {\n    return new AwsDeploymentTarget(this, options);\n  }\n}\n\n/**\n * A single exact version — `2.264.0`, `2.264.0-rc.1` — as opposed to any\n * range npm accepts (`^2.264.0`, `~2.264`, `>=2`, `2.x`, `*`, `latest`).\n */\nconst EXACT_VERSION = /^\\d+\\.\\d+\\.\\d+(?:-[\\w.-]+)?(?:\\+[\\w.-]+)?$/;\n\n/**\n * The packages `AwsCdkProject` pins itself. A consumer entry for either can\n * only restate the pin or contradict it, never improve on it.\n */\nconst CATALOG_MANAGED_PACKAGES = [\"aws-cdk-lib\", \"constructs\"];\n\n/**\n * How a catalog-managed dependency renders.\n */\ninterface CatalogPin {\n  /** The version projen's own view of the dependency resolves to. */\n  readonly version: string;\n\n  /**\n   * The specifier written into `package.json` — `catalog:` when the catalog\n   * carries an entry to resolve through, otherwise the exact version itself.\n   */\n  readonly specifier: string;\n}\n\n/**\n * Reject any `aws-cdk-lib` / `constructs` entry in a non-RUNTIME dependency\n * array, naming the offending spec.\n *\n * Neither ever reaches the pin: `addDependency` replaces only a same-name,\n * *same-type* entry, so a `devDeps` spec renders a second specifier next to\n * the pinned one (`devDependencies: { \"aws-cdk-lib\": \"^2.0.0\" }`, or `\"*\"`\n * when the spec carries no version), a `peerDeps` spec does the same in\n * `peerDependencies`, and projen's own `AwsCdkDeps` deletes a `constructs`\n * dev entry outright. Every one of those discards what the consumer asked\n * for, so say so rather than let it happen quietly.\n */\nfunction rejectCatalogManagedDeps(\n  optionName: string,\n  specs: Array<string> | undefined,\n): void {\n  for (const spec of specs ?? []) {\n    const { name } = Dependencies.parseDependency(spec);\n\n    if (!CATALOG_MANAGED_PACKAGES.includes(name)) {\n      continue;\n    }\n\n    throw new Error(\n      `AwsCdkProject pins \"${name}\" itself, as a runtime dependency on the parent MonorepoProject's catalog, ` +\n        `so \\`${optionName}: [\"${spec}\"]\\` never reaches that pin — it renders a second, unpinned specifier beside it or is dropped outright. ` +\n        `Remove \"${spec}\" from \\`${optionName}\\`, and change the version through the catalog entry for \"${name}\" instead.`,\n    );\n  }\n}\n\n/**\n * Resolve how `packageName` is pinned: the version projen's own view uses,\n * and the specifier rendered into `package.json`.\n *\n * Reading the version back out of the parent monorepo's catalog — rather than\n * validating a default against it — is what keeps projen's view from drifting\n * from what pnpm installs, including when a consumer overrides the catalog and\n * omits the option entirely.\n */\nfunction resolveCatalogPin(\n  optionName: string,\n  packageName: string,\n  suppliedVersion: string | undefined,\n  fallbackVersion: string,\n  catalog: { [key: string]: string },\n): CatalogPin {\n  const catalogVersion = catalog[packageName];\n\n  /**\n   * With no entry behind it, `catalog:` resolves to nothing and pnpm fails the\n   * install on a protocol error naming neither this project nor the entry it\n   * expected. Render the resolved version literally instead — that holds the\n   * pin without depending on a catalog that is not there.\n   */\n  if (catalogVersion === undefined) {\n    const version = suppliedVersion ?? fallbackVersion;\n\n    if (!EXACT_VERSION.test(version)) {\n      throw new Error(\n        `AwsCdkProject pins \"${packageName}\" exactly, but the parent MonorepoProject's catalog carries no entry for it, ` +\n          `so the rendered specifier falls back to \\`${optionName}: \"${version}\"\\` — a range, which would leave every CDK app floating within it. ` +\n          `Add an exact \"${packageName}\" entry to the catalog, or set \\`${optionName}\\` to an exact version.`,\n      );\n    }\n\n    return { version, specifier: version };\n  }\n\n  // `catalog:` pins only as tightly as the entry behind it, so a range there\n  // silently reinstates the float the pin exists to remove.\n  if (!EXACT_VERSION.test(catalogVersion)) {\n    throw new Error(\n      `AwsCdkProject renders \"${packageName}\" as \"catalog:\", which pins only as tightly as the catalog entry behind it. ` +\n        `The parent MonorepoProject's catalog holds \"${catalogVersion}\" — a range, so every CDK app would keep floating within it. ` +\n        `Set the catalog entry for \"${packageName}\" to an exact version.`,\n    );\n  }\n\n  if (suppliedVersion !== undefined && suppliedVersion !== catalogVersion) {\n    throw new Error(\n      `AwsCdkProject renders \"${packageName}\" as \"catalog:\", so the parent MonorepoProject's catalog pin (${catalogVersion}) decides the resolved version. ` +\n        `\\`${optionName}: \"${suppliedVersion}\"\\` would be silently ignored. Drop the option, or bump the catalog entry for \"${packageName}\" to ${suppliedVersion}.`,\n    );\n  }\n\n  return { version: catalogVersion, specifier: \"catalog:\" };\n}\n","// eslint-disable-next-line import/no-extraneous-dependencies\nimport {\n  AWS_STAGE_TYPE,\n  AwsStageType,\n  DEPLOYMENT_TARGET_ROLE,\n  DeploymentTargetRoleType,\n} from \"@codedrifters/utils\";\nimport { Component } from \"projen\";\nimport { AwsCdkTypeScriptApp } from \"projen/lib/awscdk\";\nimport { BuildWorkflow, BuildWorkflowOptions } from \"projen/lib/build\";\nimport { GitHub, GithubWorkflow, WorkflowSteps } from \"projen/lib/github\";\nimport { JobPermission, JobStep } from \"projen/lib/github/workflows-model\";\nimport { ValueOf } from \"type-fest\";\nimport {\n  AwsDeploymentConfig,\n  CDK_DIFF_METHOD,\n  renderCdkDeploy,\n  renderCdkDiff,\n  renderCdkList,\n} from \"../aws\";\nimport { ApplyWorkflow } from \"./apply-workflow\";\nimport { addBuildCompleteJob } from \"./build-complete-job\";\nimport {\n  APPROVE_JOB_ID,\n  DEPLOY_APPROVALS,\n  DEPLOY_GATE,\n  DeployApprovals,\n  DeployGate,\n  resolveApprovalGate,\n  resolveDiffEnvironment,\n  resolveEnvironmentGate,\n} from \"./deploy-gate\";\nimport {\n  DIFF_NEW_STACK_MARKER,\n  DIFF_OUTPUT_DIRECTORY,\n  DIFF_PART_ARTIFACT_PREFIX,\n  DIFF_REPORT_JOB_ID,\n  DiffReportJob,\n  renderDiffPartUploadStep,\n} from \"./diff-report-job\";\nimport {\n  WorkflowHomeRepository,\n  renderHomeRepositoryCondition,\n} from \"./home-repository\";\nimport { renderSetupNode, renderSetupPnpm } from \"./node-setup\";\nimport {\n  BUILD_ARTIFACT_NAME,\n  PERMISSION_BACKUP_FILE,\n  PLAN_RUN_ID_INPUT,\n  PlanApplyOptions,\n  VALIDATE_PLAN_JOB_ID,\n} from \"./plan-apply\";\nimport { AwsDeploymentTarget } from \"../aws/aws-deployment-target\";\nimport { GitBranch } from \"../git\";\nimport { MonorepoProject } from \"../projects\";\nimport { ROOT_CI_TASK_NAME, TurboRepo } from \"../turbo\";\n\nexport const PROD_DEPLOY_NAME = \"prod-deploy\";\n\n/**\n * The branch a run is *for*, as a GitHub Actions expression.\n *\n * `head_ref` is set on `pull_request` only, so this resolves to the source\n * branch on a PR and to the pushed/dispatched ref everywhere else. Shared by\n * the build job's `GIT_BRANCH_NAME` and by {@link\n * DeployWorkflowOptions.branchScopedConcurrency}: a consumer whose stack names\n * are derived from `GIT_BRANCH_NAME` only gets a correct concurrency key if\n * both read the same branch.\n */\nconst BRANCH_NAME_EXPRESSION = \"${{ github.head_ref || github.ref_name }}\";\n\n/**\n * Opt-in `cdk diff` capture for a deploy workflow.\n *\n * With `enabled` unset (the default), no diff jobs are emitted and the\n * generated workflow is byte-identical to one configured without a `diff`\n * block at all.\n */\nexport interface DeployDiffOptions {\n  /**\n   * Emit one `cdk diff` job per deployment target.\n   *\n   * @default false\n   */\n  readonly enabled?: boolean;\n\n  /**\n   * Upload the captured diff as a per-run CI artifact, named uniquely per\n   * target so parallel diff jobs do not collide under `actions/upload-artifact`\n   * v4+ immutability semantics.\n   *\n   * @default true (when `enabled`)\n   */\n  readonly artifact?: boolean;\n\n  /**\n   * Render the captured diff into the job summary, wrapped in a `<details>`\n   * block and truncated below GitHub's per-step summary limit.\n   *\n   * @default true (when `enabled`)\n   */\n  readonly summary?: boolean;\n\n  /**\n   * Put the workflow's `environmentName` on each diff job, so it authenticates\n   * with the same OIDC subject claim as the deploy jobs it informs.\n   *\n   * A job's `sub` claim is `repo:<owner>/<repo>:environment:<name>` when the\n   * job declares an environment and `repo:<owner>/<repo>:ref:refs/heads/<branch>`\n   * when it does not. Under the `environment` gate the diff jobs are the only\n   * cloud-touching jobs left on the ref form, so a deployer-role trust policy\n   * narrowed to environment subjects alone rejects every one of them at the\n   * credentials step — and because the merged report gates the deploys, the run\n   * dies before anything deploys.\n   *\n   * Requires `gate: \"environment\"` and `enabled`; anything else fails synth.\n   *\n   * This does **not** gate the diff. An environment with no protection rules\n   * adds no prompt, which is what keeps the diff readable before the approval\n   * it exists to inform. A required-reviewer rule on the *deploy* environment\n   * would make every diff job prompt individually — put that rule on the\n   * separate `approvalEnvironmentName` under `approvals: \"once\"` instead.\n   *\n   * @see `docs/packages/@codedrifters/configulator/workflows/aws-deploy-workflow.md`\n   * @default false\n   */\n  readonly environment?: boolean;\n}\n\nexport interface DeployWorkflowOptions {\n  /**\n   * What type of deploy is this workflow for?\n   *\n   * @default AWS_STAGE_TYPE.DEV\n   */\n  readonly awsStageType?: ValueOf<typeof AWS_STAGE_TYPE>;\n\n  /**\n   * Optionally feed a list of targets to deploy to.\n   *\n   * @default discovers all targets using stageType\n   */\n  readonly awsDeploymentTargets?: Array<AwsDeploymentTarget>;\n\n  /**\n   * Key each deploy job's concurrency group on the branch as well as the\n   * deployment target.\n   *\n   * A deploy job's group is otherwise the target coordinates alone\n   * (`<stage>-<role>-deploy-<project>-<account>-<region>`), and GitHub scopes\n   * concurrency groups to the *repository* — so one group serializes every run\n   * of every workflow carrying that job, on every branch. That is what you want\n   * when each branch deploys the same stacks.\n   *\n   * It is not what you want when the CDK app derives its stack names from the\n   * branch: two branches then update entirely separate stacks while queueing\n   * behind one lock. Setting this appends the branch, so branches deploy in\n   * parallel and same-branch runs still serialize.\n   *\n   * Enabling this lets per-branch deploys run concurrently into the *same* AWS\n   * account, so anything they share outside their own stacks — a parent hosted\n   * zone, an account-level singleton — has to tolerate concurrent mutation.\n   *\n   * Applies to the deploy job and — when diff capture is on — to each target's\n   * diff job, which locks the same branch's stacks for the same reason. The\n   * `plan-apply` gate's apply job keeps the unsuffixed group: an apply is\n   * dispatched from whatever ref the operator happens to be on, which says\n   * nothing about the branch that was planned, so a branch key there would\n   * weaken the mutual exclusion rather than sharpen it.\n   *\n   * @see `docs/packages/@codedrifters/configulator/workflows/aws-deploy-workflow.md`\n   * @default false - the group is the deployment target alone\n   */\n  readonly branchScopedConcurrency?: boolean;\n\n  /**\n   * Existing workflow, useful if we're tacking deployments onto an existing\n   * build workflow\n   */\n  readonly buildWorkflow?: BuildWorkflow;\n\n  /**\n   * Options for the build workflow, if no build workflow is provided.\n   */\n  readonly buildWorkflowOptions?: Partial<BuildWorkflowOptions>;\n\n  /**\n   * Projects that should complete deployment before this one starts.\n   */\n  readonly deployAfterTargets?: Array<AwsDeploymentTarget>;\n\n  /**\n   * Opt into a `cdk diff` job per deployment target.\n   *\n   * The `cdk diff` flags themselves are **not** configured here — they come\n   * from the {@link CdkCli} precedence chain (per-stage built-in → per-stage\n   * `diffDefaults` → per-account override → per-target `cdkOptions.diff`). This\n   * option only controls whether the jobs are emitted, what they publish, and —\n   * via {@link DeployDiffOptions.environment} — which OIDC subject claim they\n   * authenticate with.\n   *\n   * @default - no diff jobs are emitted, unless `gate` is `plan-apply`\n   */\n  readonly diff?: DeployDiffOptions;\n\n  /**\n   * Hold this workflow's deploy jobs behind a gate.\n   *\n   * `\"environment\"` puts a GitHub environment on every deploy job, so its\n   * protection rules apply before the job is sent to a runner. Requires\n   * {@link environmentName}.\n   *\n   * `\"plan-apply\"` splits the workflow instead: this one becomes a plan that\n   * builds and diffs but never deploys, and a second dispatch-only apply\n   * workflow deploys the exact assembly a nominated plan run produced. Needs\n   * no protection rule, so it works on every GitHub plan.\n   *\n   * Adding an environment changes a job's OIDC subject claim, so deployer-role\n   * trust policies must be updated in the same change.\n   *\n   * @see `docs/packages/@codedrifters/configulator/workflows/aws-deploy-workflow.md`\n   * @default - deploy jobs are ungated and stay in this workflow\n   */\n  readonly gate?: DeployGate;\n\n  /**\n   * Name of the GitHub environment gated jobs are held behind. Required when\n   * {@link gate} is `\"environment\"`, optional when it is `\"plan-apply\"` — where\n   * it layers an environment onto the apply jobs — and rejected when {@link\n   * gate} is unset.\n   *\n   * The environment must be created and configured deliberately — referencing a\n   * name that does not exist creates it with no protection rules at all.\n   *\n   * @see `docs/packages/@codedrifters/configulator/workflows/aws-deploy-workflow.md`\n   * @default - no environment is applied\n   */\n  readonly environmentName?: string;\n\n  /**\n   * How many approvals the `\"environment\"` gate asks for across one run.\n   *\n   * `\"per-target\"` (the default) leaves the gate exactly as it was: the\n   * environment sits on every deploy job, so each one reaches its protection\n   * rules separately. Deploy jobs chained by {@link deployAfterTargets} reach\n   * them one at a time, with a full deploy between each prompt, so an operator\n   * approves N times with a wait in between.\n   *\n   * `\"once\"` emits a single `approve` job behind {@link\n   * approvalEnvironmentName} and holds every deploy job behind it, so one\n   * approval after the diff report releases the whole run. The deploy jobs keep\n   * their own `environment`, so OIDC subject claims, environment-scoped\n   * secrets, and per-stack deployment history are unchanged. Requires {@link\n   * approvalEnvironmentName} and the `\"environment\"` gate.\n   *\n   * @see `docs/packages/@codedrifters/configulator/workflows/aws-deploy-workflow.md`\n   * @default DEPLOY_APPROVALS.PER_TARGET - one approval per deploy job\n   */\n  readonly approvals?: DeployApprovals;\n\n  /**\n   * Name of the GitHub environment the single `approve` job is held behind.\n   * Required when {@link approvals} is `\"once\"`, and rejected otherwise.\n   *\n   * Must differ from {@link environmentName}: this is the environment carrying\n   * the required-reviewer rule, while the deploy environment keeps the secrets\n   * and the deployment history. An administrator has to create it with that\n   * rule and remove the rule from the deploy environment, or the run prompts\n   * twice.\n   *\n   * @see `docs/packages/@codedrifters/configulator/workflows/aws-deploy-workflow.md`\n   * @default - no approval job is emitted\n   */\n  readonly approvalEnvironmentName?: string;\n\n  /**\n   * Extra settings for the `plan-apply` gate. Ignored under every other gate.\n   *\n   * @default - the apply workflow is `<plan-workflow-name>-apply` with no\n   * head-drift or digest assertions\n   */\n  readonly planApply?: PlanApplyOptions;\n\n  /**\n   * Pin this workflow's cloud-touching jobs to one repository, as an\n   * `owner/repo` slug.\n   *\n   * Guards every deploy and diff job with\n   * `github.repository == '<owner>/<repo>'` so a mirror or clone of the\n   * consumer repo hosted elsewhere skips them instead of failing at the OIDC\n   * credentials step. The build job is intentionally left unguarded.\n   *\n   * @see `docs/packages/@codedrifters/configulator/workflows/aws-deploy-workflow.md`\n   * @default - no repository guard is emitted\n   */\n  readonly homeRepository?: string;\n}\n\n/**\n * Adds a build + deploy GitHub Actions workflow for an AwsCdkTypeScriptApp.\n *\n * Deploy URLs are surfaced via a naming convention: any CfnOutput whose\n * logical ID ends in `Endpoint` is rendered into the PR sticky comment and\n * the job summary. See the docs page for the full convention and naming\n * guidance.\n *\n * @see `docs/packages/@codedrifters/configulator/workflows/aws-deploy-workflow.md`\n */\nexport class AwsDeployWorkflow extends Component {\n  public static of(\n    project: AwsCdkTypeScriptApp,\n    buildWorkflow: BuildWorkflow,\n  ): AwsDeployWorkflow | undefined {\n    const isDefined = (c: Component): c is AwsDeployWorkflow =>\n      c instanceof AwsDeployWorkflow && c.buildWorkflow === buildWorkflow;\n    return project.components.find(isDefined);\n  }\n\n  /**\n   * The root project for this deploy workflow. Must be a monorepo project.\n   */\n  private rootProject: MonorepoProject;\n\n  /**\n   * What type of deploy is this workflow for?\n   */\n  public awsStageType: AwsStageType;\n\n  /**\n   * AWS environment type, such as primary or secondary.\n   *\n   * @deprecated Use deployment target role terminology elsewhere. This property is maintained for backward compatibility.\n   * @default 'primary' (this is the only type supported currently)\n   */\n  public awsEnvironmentType: DeploymentTargetRoleType =\n    DEPLOYMENT_TARGET_ROLE.PRIMARY;\n\n  /**\n   * The list of targets to deploy to.\n   */\n  readonly awsDeploymentTargets: Array<AwsDeploymentTarget>;\n\n  /**\n   * Hold the deploy workflow so we can add to it in preSynth\n   */\n  public buildWorkflow: BuildWorkflow;\n\n  /**\n   * Was this workflow created externally?\n   */\n  public externalWorkflow: boolean;\n\n  /**\n   * Projects that should complete deployment before this one starts.\n   */\n  public deployAfterTargets: Array<AwsDeploymentTarget>;\n\n  /**\n   * Resolved `cdk diff` capture settings. Every field is concrete so callers\n   * never have to re-apply the defaults.\n   */\n  public readonly diffOptions: Required<DeployDiffOptions>;\n\n  /**\n   * Whether each deploy and diff job's concurrency group carries the branch.\n   */\n  public readonly branchScopedConcurrency: boolean;\n\n  /**\n   * Repository this workflow's cloud-touching jobs are pinned to, if any.\n   */\n  public readonly homeRepository?: string;\n\n  /**\n   * GitHub environment this workflow's gated jobs are held behind, if any.\n   */\n  public readonly environmentName?: string;\n\n  /**\n   * Gate model this workflow was built with, or `undefined` when ungated.\n   */\n  public readonly gate?: DeployGate;\n\n  /**\n   * Resolved approval model. Concrete under every gate, and simply unused\n   * outside `environment`.\n   */\n  public readonly approvals: DeployApprovals;\n\n  /**\n   * GitHub environment the single `approve` job sits behind under\n   * `approvals: \"once\"`, or `undefined` under `per-target`.\n   */\n  public readonly approvalEnvironmentName?: string;\n\n  /**\n   * Resolved `plan-apply` settings. Every field is concrete so callers never\n   * have to re-apply the defaults. Populated under every gate, and simply\n   * unused outside `plan-apply`.\n   *\n   * `applyWorkflow` is omitted because it is an input, not a setting — read\n   * {@link applyWorkflow} for the workflow this component actually uses,\n   * whether it created or joined it.\n   */\n  public readonly planApplyOptions: Required<\n    Omit<PlanApplyOptions, \"applyWorkflow\">\n  >;\n\n  /**\n   * The dispatch-only apply workflow, when the gate is `plan-apply`. Shared\n   * with any other `AwsDeployWorkflow` that was pointed at it via\n   * `planApply.applyWorkflow`.\n   */\n  public readonly applyWorkflow?: GithubWorkflow;\n\n  constructor(\n    public project: AwsCdkTypeScriptApp,\n    public options: DeployWorkflowOptions = {},\n  ) {\n    super(project);\n\n    /***************************************************************************\n     *\n     * Root project check\n     *\n     * Detect the root project and ensure it's of type MonorepoProject.\n     *\n     **************************************************************************/\n\n    if (!(project.root instanceof MonorepoProject)) {\n      throw new Error(\n        \"AwsDeployWorkflow requires the root project to be a MonorepoProject\",\n      );\n    }\n\n    this.rootProject = project.root;\n\n    /***************************************************************************\n     *\n     * GitHub Check\n     *\n     * Make sure github config is active in the project. This is to ensure all\n     * workflows will be output properly during synth.\n     *\n     **************************************************************************/\n\n    const github = GitHub.of(this.rootProject);\n\n    if (!github) {\n      throw new Error(\n        \"AwsDeployWorkflow requires a GitHub component in the root project\",\n      );\n    }\n\n    /***************************************************************************\n     *\n     * TurboRepo Check\n     *\n     * If turbo is enabled, we may need the options later in this file.\n     *\n     **************************************************************************/\n\n    const turbo = TurboRepo.of(this.rootProject);\n    const buildWorkflowOptions: Partial<BuildWorkflowOptions> =\n      turbo?.remoteCacheOptions\n        ? TurboRepo.buildWorkflowOptions(turbo.remoteCacheOptions)\n        : {};\n\n    /***************************************************************************\n     *\n     * Workflow Deploy Type\n     *\n     * What type of environments are we deploying into? We'll default to dev to\n     * be safe.\n     *\n     **************************************************************************/\n\n    this.awsStageType = options.awsStageType ?? AWS_STAGE_TYPE.DEV;\n\n    /***************************************************************************\n     *\n     * Workflow Deploy Targets\n     *\n     * Use provided targets or discover them based on the deploy type. Only\n     * include targets that are marked for CI/CD.\n     *\n     **************************************************************************/\n\n    this.awsDeploymentTargets =\n      options.awsDeploymentTargets ??\n      AwsDeploymentConfig.of(project)?.awsDeploymentTargets.filter(\n        (target) =>\n          target.awsStageType === this.awsStageType && target.ciDeployment,\n      ) ??\n      [];\n\n    this.deployAfterTargets = options.deployAfterTargets ?? [];\n\n    /***************************************************************************\n     *\n     * Gate Model\n     *\n     * Resolved before the diff block because `plan-apply` moves the default\n     * for `diff.enabled` — a plan whose whole job is to be reviewed is not\n     * worth much without a diff to review. With `gate` unset the workflow is\n     * ungated and everything below is a no-op.\n     *\n     **************************************************************************/\n\n    this.gate = options.gate;\n\n    const isPlanApply = this.gate === DEPLOY_GATE.PLAN_APPLY;\n\n    /***************************************************************************\n     *\n     * Diff Capture\n     *\n     * Opt-in when ungated or environment-gated. With `diff` unset the resolved\n     * `enabled` stays false, no diff jobs are registered, and the generated\n     * workflow is byte-identical to one configured without a `diff` block at\n     * all.\n     *\n     * Under `plan-apply` the default flips to true, and turning it off is\n     * rejected outright: projen only uploads the build artifact when the\n     * workflow has at least one post-build job, and under `plan-apply` the\n     * diff jobs are the only post-build jobs left once the deploy jobs move\n     * out. A diff-less plan would publish nothing for the apply to download\n     * and fail at dispatch time instead of at synth time.\n     *\n     **************************************************************************/\n\n    if (isPlanApply && options.diff?.enabled === false) {\n      throw new Error(\n        \"AwsDeployWorkflow cannot disable `diff` under the `plan-apply` gate: the diff jobs are what keep the plan workflow publishing the build artifact the apply workflow deploys.\",\n      );\n    }\n\n    const diffEnabled = options.diff?.enabled ?? isPlanApply;\n\n    /**\n     * Opt-in, and only meaningful under the `environment` gate — where the diff\n     * jobs are the last cloud-touching jobs still authenticating on the ref\n     * subject claim, so a deployer role narrowed to environment subjects turns\n     * them all away. Validated before the environment itself resolves, so a\n     * flag with nothing to borrow fails synth rather than rendering diff jobs\n     * that look environment-scoped and are not.\n     */\n    this.diffOptions = {\n      enabled: diffEnabled,\n      artifact: options.diff?.artifact ?? true,\n      summary: options.diff?.summary ?? true,\n      environment: resolveDiffEnvironment(\n        options.gate,\n        options.diff?.environment,\n        diffEnabled,\n        \"AwsDeployWorkflow\",\n      ),\n    };\n\n    /***************************************************************************\n     *\n     * Branch-Scoped Concurrency\n     *\n     * Opt-in. Widens each deploy and diff job's concurrency group with the\n     * branch so branch-scoped stacks stop queueing behind each other. Off by\n     * default, in which case the group is the target coordinates alone and the\n     * rendered deploy job is unchanged.\n     *\n     **************************************************************************/\n\n    this.branchScopedConcurrency = options.branchScopedConcurrency ?? false;\n\n    /***************************************************************************\n     *\n     * Environment Gate\n     *\n     * Opt-in. Puts a GitHub environment on every deploy job so its protection\n     * rules run before the job reaches a runner, and — when diff capture is on —\n     * orders each deploy behind its own target's diff so the approver reads a\n     * finished diff. Resolved before any workflow is constructed so a\n     * half-configured gate fails synth early. With `gate` unset no environment\n     * is emitted and job ordering is unchanged.\n     *\n     * Under `plan-apply` the deploy jobs live in the apply workflow, so an\n     * environment supplied alongside it lands on the apply jobs instead —\n     * a second, differently-authorized approver on top of whoever dispatched\n     * the apply. It is optional there rather than required, because the\n     * dispatch split is already the gate.\n     *\n     **************************************************************************/\n\n    this.environmentName = resolveEnvironmentGate(\n      options.gate,\n      options.environmentName,\n      \"AwsDeployWorkflow\",\n    );\n\n    /***************************************************************************\n     *\n     * Approval Placement\n     *\n     * Opt-in, and only meaningful under the `environment` gate. `per-target`\n     * (the default) leaves the gate as it was: the environment is the whole\n     * gate, so every deploy job carries it and every deploy job prompts. Deploy\n     * jobs chained by `deployAfterTargets` reach that prompt one at a time —\n     * each only after its predecessor has finished deploying — so the prompts\n     * arrive as a trickle no GitHub setting can batch.\n     *\n     * `once` splits the two jobs the environment was doing at the same time. A\n     * dedicated `approve` job carries the required-reviewer rule and every\n     * deploy job waits on it; the deploy jobs keep their own `environment`, so\n     * their OIDC subject claims stay in the `environment:<name>` form,\n     * environment-scoped secrets still resolve, and each stack still records\n     * its own deployment. Moving the environment onto the gate job instead\n     * would have cost all three.\n     *\n     * Resolved here — after `environmentName`, whose resolved value the\n     * same-name check reads — so a half-configured approval gate fails synth\n     * before any workflow is constructed.\n     *\n     **************************************************************************/\n\n    this.approvals = options.approvals ?? DEPLOY_APPROVALS.PER_TARGET;\n\n    this.approvalEnvironmentName = resolveApprovalGate(\n      options.gate,\n      options.approvals,\n      options.approvalEnvironmentName,\n      this.environmentName,\n      \"AwsDeployWorkflow\",\n    );\n\n    /***************************************************************************\n     *\n     * Home Repository Guard\n     *\n     * Opt-in. Pins every job that touches cloud resources to one repository so\n     * a mirror or clone of the consumer repo skips them rather than failing at\n     * the OIDC credentials step. Resolved before any workflow is constructed so\n     * a malformed slug fails synth early. With `homeRepository` unset no guard\n     * is emitted and the generated workflow is unchanged.\n     *\n     **************************************************************************/\n\n    this.homeRepository = options.homeRepository;\n\n    const homeRepositoryCondition = renderHomeRepositoryCondition(\n      this.homeRepository,\n      \"AwsDeployWorkflow\",\n    );\n\n    /***************************************************************************\n     *\n     * Build Workflow Options\n     *\n     * Can't use the options if an existing workflow was passed in.\n     *\n     **************************************************************************/\n\n    if (options.buildWorkflow && options.buildWorkflowOptions) {\n      throw new Error(\n        \"Cannot provide both buildWorkflow and buildWorkflowOptions\",\n      );\n    }\n\n    this.externalWorkflow = !!options.buildWorkflow;\n\n    /***************************************************************************\n     *\n     * Build Workflow\n     *\n     * Create a workflow either based on input or from scratch.\n     *\n     **************************************************************************/\n\n    this.buildWorkflow =\n      options.buildWorkflow ??\n      new BuildWorkflow(this.rootProject, {\n        /**\n         * Name based on project and environment.\n         */\n        name:\n          options.buildWorkflowOptions?.name ??\n          [\n            \"deploy\",\n            project.name,\n            this.awsStageType,\n            this.awsEnvironmentType,\n          ].join(\"-\"),\n\n        /**\n         * Use the root projects build task.\n         */\n        buildTask: this.rootProject.buildTask,\n\n        /**\n         * Use push triggers based n the branch config for each environment.\n         *\n         * Deduped: targets in one workflow routinely share a branch — two prod\n         * targets both default to `main` — and a repeated entry is only noise\n         * in the generated file, since GitHub treats this as a filter list.\n         */\n        workflowTriggers: {\n          push: {\n            branches: Array.from(\n              new Set(\n                this.awsDeploymentTargets.flatMap((t) =>\n                  t.branches.map((b) => b.branch),\n                ),\n              ),\n            ),\n          },\n          workflowDispatch: {},\n          ...options.buildWorkflowOptions?.workflowTriggers,\n        },\n\n        /**\n         * Never allow mutations for deploys. This should have been handled\n         * during build.\n         */\n        mutableBuild: false,\n\n        /**\n         * Do this pre-merge of permissions and build steps\n         */\n        ...options.buildWorkflowOptions,\n\n        /**\n         * Set GIT_BRANCH_NAME so Turborepo remote cache hashes match between local and CI.\n         */\n        env: {\n          GIT_BRANCH_NAME: BRANCH_NAME_EXPRESSION,\n          ...options.buildWorkflowOptions?.env,\n          ...buildWorkflowOptions?.env,\n        },\n\n        /**\n         * Some additional permissions may be required when turbo's involved.\n         */\n        permissions: {\n          ...options.buildWorkflowOptions?.permissions,\n          ...buildWorkflowOptions?.permissions,\n        },\n\n        /**\n         * Assemble all pre-build steps\n         */\n        preBuildSteps: [\n          ...this.setupPnpm(),\n          ...this.setupNode(),\n          {\n            name: \"Install dependencies\",\n            run: \"pnpm i --no-frozen-lockfile\",\n          },\n          ...(options.buildWorkflowOptions?.preBuildSteps ?? []),\n          ...(buildWorkflowOptions?.preBuildSteps ?? []),\n        ],\n      });\n\n    /***************************************************************************\n     *\n     * Home Repository Agreement\n     *\n     * The pin belongs to the workflow file, not to this component: it guards\n     * every cloud-touching job in the file. Recorded against the build workflow\n     * here, and against the apply workflow below, so a second component sharing\n     * either one cannot stamp a different pin on its own jobs.\n     *\n     **************************************************************************/\n\n    WorkflowHomeRepository.require(this.rootProject, {\n      workflow: this.buildWorkflow,\n      workflowName: this.buildWorkflow.name,\n      homeRepository: this.homeRepository,\n      componentName: \"AwsDeployWorkflow\",\n    });\n\n    /***************************************************************************\n     *\n     * Apply Workflow\n     *\n     * Under `plan-apply` the workflow built above becomes the plan: it keeps\n     * its triggers, its build job, and its diff jobs, but its deploy jobs move\n     * to a second, dispatch-only workflow that runs them against the assembly\n     * a nominated plan run already produced.\n     *\n     * That second workflow is created here, or joined when the supplied\n     * `applyWorkflow` points at one another component already created. Joining\n     * is what lets a multi-service repo keep its cross-service\n     * `deployAfterTargets` ordering, since GitHub resolves `needs` only within\n     * one workflow file.\n     *\n     **************************************************************************/\n\n    const sharedApplyWorkflow = options.planApply?.applyWorkflow;\n\n    if (sharedApplyWorkflow && options.planApply?.applyWorkflowName) {\n      throw new Error(\n        \"Cannot provide both planApply.applyWorkflow and planApply.applyWorkflowName: the workflow being joined already has a name.\",\n      );\n    }\n\n    this.planApplyOptions = {\n      applyWorkflowName:\n        sharedApplyWorkflow?.name ??\n        options.planApply?.applyWorkflowName ??\n        `${this.buildWorkflow.name}-apply`,\n      requireCurrentHead: options.planApply?.requireCurrentHead ?? false,\n      verifyArtifactDigest: options.planApply?.verifyArtifactDigest ?? false,\n    };\n\n    if (isPlanApply) {\n      const applyWorkflow = sharedApplyWorkflow\n        ? this.attachApplyWorkflow(sharedApplyWorkflow)\n        : new ApplyWorkflow(this.rootProject, github, {\n            applyWorkflowName: this.planApplyOptions.applyWorkflowName,\n            planWorkflowName: this.buildWorkflow.name,\n            requireCurrentHead: this.planApplyOptions.requireCurrentHead,\n            verifyArtifactDigest: this.planApplyOptions.verifyArtifactDigest,\n            homeRepositoryCondition,\n            awsDeploymentTargets: this.awsDeploymentTargets,\n            componentName: \"AwsDeployWorkflow\",\n          });\n\n      this.applyWorkflow = applyWorkflow.workflow;\n\n      WorkflowHomeRepository.require(this.rootProject, {\n        workflow: applyWorkflow.workflow,\n        workflowName: this.planApplyOptions.applyWorkflowName,\n        homeRepository: this.homeRepository,\n        componentName: \"AwsDeployWorkflow\",\n      });\n    }\n\n    /***************************************************************************\n     *\n     * Add Deployments to workflow\n     *\n     **************************************************************************/\n\n    this.awsDeploymentTargets.forEach((target) => {\n      const deployJobName = this.buildJobName(target);\n\n      // Build the branch filter condition\n      const branchFilterCondition = this.buildBranchFilterCondition(\n        target.branches,\n      );\n\n      /**\n       * Compose the job gate. The build's self-mutation check always applies;\n       * the optional home-repository pin and the target's branch filter are\n       * ANDed in when present. With both unset the rendered expression is\n       * identical to what this workflow emitted before either option existed.\n       */\n      const jobCondition =\n        \"${{ \" +\n        [\n          \"!needs.build.outputs.self_mutation_happened\",\n          ...(homeRepositoryCondition ? [homeRepositoryCondition] : []),\n          ...(branchFilterCondition ? [`(${branchFilterCondition})`] : []),\n        ].join(\" && \") +\n        \" }}\";\n\n      /**\n       * Under every gate but `plan-apply` the deploy job hangs off the build\n       * job in this same workflow. Under `plan-apply` it moves to the apply\n       * workflow, where a nominated plan run feeds it instead.\n       */\n      if (this.applyWorkflow) {\n        this.addApplyJob(this.applyWorkflow, target, homeRepositoryCondition);\n      } else {\n        /**\n         * An environment-gated deploy waits on the diff *report*, not on its\n         * own target's diff job. The report transitively needs every diff, so\n         * the deploy sits in \"Waiting\" only once the whole picture is on the\n         * run page — an approver decides on all of it rather than on one\n         * service's slice.\n         *\n         * Ungated, or with diff capture off, `needs` is unchanged.\n         *\n         * Under `approvals: \"once\"` the deploy also waits on the single\n         * `approve` job. Everything else about the job — its own `environment`\n         * included — is untouched: the approval job holds the reviewer rule,\n         * the deploy job's environment keeps the secrets, the OIDC subject\n         * claim, and the deployment record.\n         */\n        const gatedOnDiff = !!this.environmentName && this.diffOptions.enabled;\n\n        this.buildWorkflow.addPostBuildJob(deployJobName, {\n          name: `Deploy ${this.project.name} ${target.awsStageType}/${target.deploymentTargetRole}/${target.account}/${target.region}`,\n          needs: [\n            \"build\",\n            ...(gatedOnDiff ? [DIFF_REPORT_JOB_ID] : []),\n            ...(this.approvalEnvironmentName ? [APPROVE_JOB_ID] : []),\n            ...this.deployAfterTargets.map((p) => {\n              return this.buildJobName(p);\n            }),\n          ],\n          runsOn: [\"ubuntu-latest\"],\n          permissions: {\n            contents: JobPermission.READ,\n            idToken: JobPermission.WRITE,\n            pullRequests: JobPermission.WRITE,\n          },\n          ...(this.environmentName\n            ? { environment: this.environmentName }\n            : undefined),\n          concurrency: this.buildDeployConcurrency(deployJobName),\n          if: jobCondition,\n          steps: [...this.deploySteps(target)],\n        });\n      }\n\n      /**\n       * Optional `cdk diff` job for the same target.\n       *\n       * Registered here — inside the target loop and therefore before\n       * `addBuildCompleteJob` runs below — so the aggregate gate job picks the\n       * diff jobs up without a second pass.\n       *\n       * Deliberately narrower than the deploy job:\n       *\n       * - `needs: [build]` only. A diff is a read-only comparison against live\n       *   cloud state, so it does not inherit `deployAfterTargets` ordering and\n       *   every target's diff runs in parallel.\n       * - Its own `concurrency` group with a `diff` verb, not the deploy job's.\n       *   A diff is read-only with respect to stack *state*, but\n       *   `--method=change-set` creates a fixed-name change set per stack, so\n       *   two runs diffing one target race for that single named slot and the\n       *   loser fails. A separate group serializes diff against diff — including\n       *   across two workflows carrying the same target, since GitHub scopes\n       *   groups to the repository — without also queueing every diff behind a\n       *   long deploy the way sharing the deploy group would.\n       * - No `pull-requests: write`. The diff job posts no PR comment, and\n       *   `actions/upload-artifact` authenticates with the Actions runtime\n       *   token rather than `GITHUB_TOKEN`, so it needs no extra permission.\n       * - No `environment` by default, even when the deploy jobs are gated. The\n       *   gate exists so an approver can read the diff, and a diff held behind\n       *   a required-reviewer rule would wait for the approval it informs.\n       *\n       *   `diff.environment` opts back in, for the one thing the environment\n       *   does to a job besides gate it: a job that declares one requests an\n       *   OIDC token subject-claimed `environment:<name>` rather than\n       *   `ref:refs/heads/<branch>`. Under the `environment` gate these are the\n       *   only cloud-touching jobs left on the ref form, so a deployer role\n       *   trusting environment subjects alone rejects every diff — and the\n       *   merged report gates the deploys, so the run dies before deploying.\n       *   Whether the environment *also* pauses the job is a property of its\n       *   protection rules, which is why the flag pairs with an approval rule\n       *   kept on a separate `approvalEnvironmentName` rather than on this one.\n       *\n       * It renders no summary of its own — its capture is uploaded as a part\n       * for the report job, which is the single place the diffs are read.\n       */\n      if (this.diffOptions.enabled) {\n        const diffJobName = this.buildDiffJobName(target);\n\n        this.buildWorkflow.addPostBuildJob(diffJobName, {\n          name: `Diff ${this.project.name} ${target.awsStageType}/${target.deploymentTargetRole}/${target.account}/${target.region}`,\n          needs: [\"build\"],\n          runsOn: [\"ubuntu-latest\"],\n          permissions: {\n            contents: JobPermission.READ,\n            idToken: JobPermission.WRITE,\n          },\n          ...(this.diffOptions.environment && this.environmentName\n            ? { environment: this.environmentName }\n            : undefined),\n          concurrency: this.buildDiffConcurrency(diffJobName),\n          if: jobCondition,\n          steps: [...this.diffSteps(target)],\n        });\n      }\n    });\n\n    /***************************************************************************\n     *\n     * Diff Report\n     *\n     * The diffs themselves stay in their own parallel jobs — each target owns\n     * its own stacks and needs its own account's credentials, so only two diffs\n     * of one target ever serialize. What does not scale is the review: under\n     * `plan-apply` the diff is the *only* review surface, so a multi-service\n     * repo would mean one job summary per service to open and reconcile by\n     * hand. Every target uploads its capture as a part, and one report job\n     * merges them into a single summary and a single artifact.\n     *\n     * Registered before `addBuildCompleteJob` below so the aggregate gate job\n     * picks it up, and after the target loop so its `needs` name jobs that\n     * already exist.\n     *\n     **************************************************************************/\n\n    if (this.diffOptions.enabled && this.awsDeploymentTargets.length > 0) {\n      DiffReportJob.attach(this.rootProject, {\n        buildWorkflow: this.buildWorkflow,\n        homeRepositoryCondition,\n        summary: this.diffOptions.summary,\n        artifact: this.diffOptions.artifact,\n        targets: this.awsDeploymentTargets.map((target) => ({\n          label: `${this.project.name} ${target.awsStageType}/${target.deploymentTargetRole}/${target.account}/${target.region}`,\n          jobName: this.buildDiffJobName(target),\n          outputFile: this.buildDiffOutputFile(target),\n          branchCondition: this.buildBranchFilterCondition(target.branches),\n        })),\n      });\n    }\n\n    /***************************************************************************\n     *\n     * Single Approval Job\n     *\n     * The one job under `approvals: \"once\"` that actually pauses. It needs the\n     * diff report — the same thing a `per-target` deploy waits on — so the\n     * reviewer still reads the combined `cdk diff` for every target before\n     * anything deploys, and with diff capture off it falls back to `build`\n     * alone exactly as a gated deploy does.\n     *\n     * Registered on the workflow directly rather than through\n     * `addPostBuildJob`, which would prepend a download of the build artifact\n     * this job has no use for — it runs no CDK and touches no cloud. The deploy\n     * jobs remain post-build jobs, so the invariant that keeps projen uploading\n     * the build artifact is unaffected.\n     *\n     * Registered after the diff report and before `addBuildCompleteJob`, which\n     * enumerates the workflow's jobs to build the aggregate gate's `needs` — a\n     * job added later would be missing from that gate.\n     *\n     **************************************************************************/\n\n    if (this.approvalEnvironmentName && this.awsDeploymentTargets.length > 0) {\n      if (this.buildWorkflow.workflow.getJob(APPROVE_JOB_ID)) {\n        throw new Error(\n          `AwsDeployWorkflow cannot add a second \\`approvals: \"${DEPLOY_APPROVALS.ONCE}\"\\` gate to the workflow \"${this.buildWorkflow.name}\": the job id \"${APPROVE_JOB_ID}\" is already taken. One approval job releases every deploy job in the file, so give the components separate build workflows if they must be approved separately.`,\n        );\n      }\n\n      const gatedOnDiff = this.diffOptions.enabled;\n\n      this.buildWorkflow.workflow.addJob(APPROVE_JOB_ID, {\n        name: `Approve ${this.project.name} ${this.awsStageType} deployment`,\n        needs: [\"build\", ...(gatedOnDiff ? [DIFF_REPORT_JOB_ID] : [])],\n        runsOn: [\"ubuntu-latest\"],\n        /**\n         * Nothing to read and nothing to write: the job exists so GitHub holds\n         * it at the environment's protection rules, and its only step records\n         * that it cleared them.\n         */\n        permissions: {\n          contents: JobPermission.NONE,\n        },\n        environment: this.approvalEnvironmentName,\n        if: this.buildApprovalCondition(homeRepositoryCondition),\n        steps: [\n          {\n            name: \"Record approval\",\n            run: `echo \"Approved — releasing every ${this.awsStageType} deploy job in this run.\" >> \"$GITHUB_STEP_SUMMARY\"`,\n          },\n        ],\n      });\n    }\n\n    /**\n     * Append the \"complete\" gate job (ADR 0004) so this workflow has a single\n     * required status check.\n     */\n    addBuildCompleteJob(this.buildWorkflow);\n  }\n\n  public setupNode = (): Array<JobStep> => renderSetupNode();\n\n  public setupPnpm = (): Array<JobStep> =>\n    renderSetupPnpm(this.rootProject.pnpmVersion);\n\n  /**\n   * Build the deterministic GitHub Actions job name for a deploy target.\n   *\n   * Used both to register the post-build job and as the sticky-PR-comment\n   * header so dev/stage/prod comments don't collide on the same PR.\n   */\n  private buildJobName = (target: AwsDeploymentTarget): string => {\n    return [\n      target.awsStageType,\n      target.deploymentTargetRole,\n      \"deploy\",\n      target.project.name,\n      target.account,\n      target.region,\n    ].join(\"-\");\n  };\n\n  /**\n   * Build a deploy job's `concurrency` setting from its job name.\n   *\n   * Two shapes, deliberately:\n   *\n   * - Unscoped (the default) stays the bare string the job has always carried,\n   *   so an existing consumer's workflow is byte-identical.\n   * - Branch-scoped spells out `cancel-in-progress: false` rather than leaning\n   *   on GitHub's default, the same way the apply job does. A group keyed on\n   *   the branch reads like a \"cancel superseded pushes\" group, and that is the\n   *   one thing it must not be — cancelling a half-finished `cdk deploy`\n   *   strands a CloudFormation stack mid-update.\n   */\n  private buildDeployConcurrency = (\n    deployJobName: string,\n  ): string | { group: string; \"cancel-in-progress\": boolean } => {\n    if (!this.branchScopedConcurrency) {\n      return deployJobName;\n    }\n\n    return {\n      group: `${deployJobName}-${BRANCH_NAME_EXPRESSION}`,\n      \"cancel-in-progress\": false,\n    };\n  };\n\n  /**\n   * Build the deterministic GitHub Actions job name for a target's apply job.\n   * Mirrors {@link buildJobName} with an `apply` verb.\n   */\n  private buildApplyJobName = (target: AwsDeploymentTarget): string => {\n    return [\n      target.awsStageType,\n      target.deploymentTargetRole,\n      \"apply\",\n      target.project.name,\n      target.account,\n      target.region,\n    ].join(\"-\");\n  };\n\n  /**\n   * Build the deterministic GitHub Actions job name for a target's `cdk diff`\n   * job. Mirrors {@link buildJobName} with a `diff` verb so the diff and deploy\n   * jobs for one target sort next to each other in the run view.\n   */\n  private buildDiffJobName = (target: AwsDeploymentTarget): string => {\n    return [\n      target.awsStageType,\n      target.deploymentTargetRole,\n      \"diff\",\n      target.project.name,\n      target.account,\n      target.region,\n    ].join(\"-\");\n  };\n\n  /**\n   * Build a diff job's `concurrency` setting from its job name.\n   *\n   * Always the object form, unlike {@link buildDeployConcurrency}: a diff job\n   * has no legacy bare-string shape to stay byte-identical with, and\n   * `cancel-in-progress` is load-bearing enough here to spell out. It must\n   * stay `false` — a superseded diff cancelled mid-`CreateChangeSet`\n   * leaves the fixed-name change set occupied for whichever run comes next,\n   * which is the failure the group exists to prevent.\n   *\n   * Carries the branch under\n   * {@link DeployWorkflowOptions.branchScopedConcurrency} for the same reason\n   * the deploy group does: when stack names are derived from the branch, two\n   * branches diff separate stacks and therefore separate change sets, so one\n   * repo-wide lock across all of them would queue for nothing.\n   */\n  private buildDiffConcurrency = (\n    diffJobName: string,\n  ): { group: string; \"cancel-in-progress\": boolean } => {\n    return {\n      group: this.branchScopedConcurrency\n        ? `${diffJobName}-${BRANCH_NAME_EXPRESSION}`\n        : diffJobName,\n      \"cancel-in-progress\": false,\n    };\n  };\n\n  /**\n   * Build the slug that makes a target unique among every target in the plan\n   * workflow, across every deploy component feeding it.\n   *\n   * Includes `deploymentTargetRole`, which two otherwise-identical targets can\n   * differ on.\n   */\n  private buildDiffSlug = (target: AwsDeploymentTarget): string => {\n    return [\n      target.awsStageType,\n      target.deploymentTargetRole,\n      target.project.name,\n      target.account,\n      target.region,\n    ].join(\"-\");\n  };\n\n  /**\n   * Build the file a target's captured diff is written to, both in its own diff\n   * job's workspace and in the merged directory the report job assembles.\n   */\n  private buildDiffOutputFile = (target: AwsDeploymentTarget): string => {\n    return `${DIFF_OUTPUT_DIRECTORY}/${this.buildDiffSlug(target)}.txt`;\n  };\n\n  /**\n   * Build the intermediate artifact name carrying one target's captured diff.\n   *\n   * The diff jobs run in parallel and `actions/upload-artifact` v4+ rejects a\n   * duplicate name within a run, so each target needs its own. The report job\n   * merges them into a single artifact, which is the one meant to be read.\n   */\n  private buildDiffPartArtifactName = (target: AwsDeploymentTarget): string => {\n    return `${DIFF_PART_ARTIFACT_PREFIX}-${this.buildDiffSlug(target)}`;\n  };\n\n  /**\n   * Join an apply workflow another `AwsDeployWorkflow` already created, so this\n   * component's apply jobs land in that file rather than a second one.\n   *\n   * Rejects a `GithubWorkflow` that is not an apply workflow: attaching to an\n   * arbitrary one would add apply jobs depending on a `validate-plan` job that\n   * does not exist there, which GitHub rejects only at run time.\n   */\n  private attachApplyWorkflow = (workflow: GithubWorkflow): ApplyWorkflow => {\n    const shared = ApplyWorkflow.of(this.rootProject, workflow);\n\n    if (!shared) {\n      throw new Error(\n        `AwsDeployWorkflow cannot attach to the workflow \"${workflow.name}\" because it is not an apply workflow. Pass the \\`applyWorkflow\\` of an AwsDeployWorkflow built with the \\`plan-apply\\` gate.`,\n      );\n    }\n\n    shared.attach({\n      planWorkflowName: this.buildWorkflow.name,\n      requireCurrentHead: this.planApplyOptions.requireCurrentHead,\n      verifyArtifactDigest: this.planApplyOptions.verifyArtifactDigest,\n      awsDeploymentTargets: this.awsDeploymentTargets,\n      componentName: \"AwsDeployWorkflow\",\n    });\n\n    return shared;\n  };\n\n  /**\n   * Register one target's apply job on the apply workflow.\n   *\n   * Differences from the `single`-gate deploy job, all of them forced by the\n   * apply run having no build job of its own:\n   *\n   * - `needs` starts at the validation job rather than `build`, so a plan run\n   *   that fails any check skips every apply job instead of deploying.\n   * - `actions: read` is added, which is what lets `actions/download-artifact`\n   *   reach across runs.\n   * - No `pull-requests: write`, and no sticky PR comment step: an apply is\n   *   always a `workflow_dispatch`, so the comment could never fire.\n   * - No branch filter on `github.ref`. The ref an operator happens to\n   *   dispatch from is unrelated to what was planned; the branch that matters\n   *   is the plan run's, and the validation job checks that one.\n   *\n   * When `environmentName` is also supplied, it lands here rather than on the\n   * plan's jobs — a second approver on top of whoever dispatched the apply.\n   * `validate-plan` stays ungated so its verdict is available to read *before*\n   * the approval is given.\n   */\n  private addApplyJob = (\n    workflow: GithubWorkflow,\n    target: AwsDeploymentTarget,\n    homeRepositoryCondition: string | undefined,\n  ): void => {\n    const applyJobName = this.buildApplyJobName(target);\n    const { verifyArtifactDigest } = this.planApplyOptions;\n    const artifactsDirectory = this.rootProject.artifactsDirectory;\n\n    workflow.addJob(applyJobName, {\n      name: `Apply ${this.project.name} ${target.awsStageType}/${target.deploymentTargetRole}/${target.account}/${target.region}`,\n      needs: [\n        VALIDATE_PLAN_JOB_ID,\n        ...this.deployAfterTargets.map((p) => this.buildApplyJobName(p)),\n      ],\n      runsOn: [\"ubuntu-latest\"],\n      permissions: {\n        actions: JobPermission.READ,\n        contents: JobPermission.READ,\n        idToken: JobPermission.WRITE,\n      },\n      ...(this.environmentName\n        ? { environment: this.environmentName }\n        : undefined),\n      /**\n       * Shares the deploy job's group name so an apply can never overlap a\n       * same-target deploy. `cancel-in-progress` is spelled out rather than\n       * left to GitHub's default: cancelling a half-finished `cdk deploy`\n       * strands a CloudFormation stack mid-update.\n       *\n       * `branchScopedConcurrency` deliberately does not reach here. An apply is\n       * dispatched from whatever ref the operator happens to be on — unrelated\n       * to the branch the nominated plan ran against, which is the only branch\n       * that describes what is about to be deployed. Keying on the dispatch ref\n       * would hand out separate locks to applies of the same target, so the\n       * unsuffixed group stays.\n       */\n      concurrency: {\n        group: this.buildJobName(target),\n        \"cancel-in-progress\": false,\n      },\n      ...(homeRepositoryCondition\n        ? { if: `\\${{ ${homeRepositoryCondition} }}` }\n        : {}),\n      steps: [\n        /**\n         * Cross-run download of the plan's assembly. `run-id` plus an explicit\n         * `github-token` is what makes `actions/download-artifact` look outside\n         * the current run; without both it silently searches this run and finds\n         * nothing.\n         */\n        {\n          name: \"Download plan build artifacts\",\n          uses: \"actions/download-artifact@v8\",\n          with: {\n            name: BUILD_ARTIFACT_NAME,\n            path: artifactsDirectory,\n            \"run-id\": `\\${{ inputs.${PLAN_RUN_ID_INPUT} }}`,\n            \"github-token\": \"${{ secrets.GITHUB_TOKEN }}\",\n            ...(verifyArtifactDigest\n              ? {\n                  \"artifact-digest\": `\\${{ needs.${VALIDATE_PLAN_JOB_ID}.outputs.artifact_digest }}`,\n                }\n              : {}),\n          },\n        },\n        {\n          name: \"Restore build artifact permissions\",\n          continueOnError: true,\n          run: `cd ${artifactsDirectory} && setfacl --restore=${PERMISSION_BACKUP_FILE}`,\n        },\n        ...this.deploySteps(target, { stickyPrComment: false }),\n      ],\n    });\n  };\n\n  /**\n   * Builds a GitHub Actions condition string that checks if the current branch\n   * matches any of the provided branch patterns.\n   *\n   * Handles both exact matches (e.g., \"main\") and glob patterns (e.g., \"feature/*\").\n   * Also allows workflow_dispatch (manual runs) to proceed.\n   *\n   * @param branches - Array of GitBranch objects with branch patterns\n   * @returns Condition string or empty string if no branches provided\n   */\n  private buildBranchFilterCondition = (branches: Array<GitBranch>): string => {\n    if (!branches || branches.length === 0) {\n      return \"\";\n    }\n\n    const conditions: Array<string> = [];\n\n    // Always allow workflow_dispatch (manual workflow runs)\n    conditions.push(\"github.event_name == 'workflow_dispatch'\");\n\n    for (const branch of branches) {\n      const branchPattern = branch.branch;\n\n      // Handle glob patterns (e.g., \"feature/*\")\n      if (branchPattern.includes(\"*\")) {\n        // Replace * with proper startsWith check\n        const prefix = branchPattern.replace(/\\*.*$/, \"\");\n        conditions.push(`startsWith(github.ref, 'refs/heads/${prefix}')`);\n        // PR support, unprefixed branch names\n        conditions.push(`startsWith(github.head_ref, '${prefix}')`);\n      } else {\n        // Exact match\n        conditions.push(`github.ref == 'refs/heads/${branchPattern}'`);\n      }\n    }\n\n    /**\n     * Combine all conditions with OR\n     */\n    return conditions.join(\" || \");\n  };\n\n  /**\n   * Compose the single approval job's condition.\n   *\n   * Mirrors a deploy job's, with one difference forced by the job being shared:\n   * the branch clause is the union of every target's, rather than one target's.\n   * Without it a push to a branch no target deploys from would still pause for\n   * an approval — prompting for a deployment that can never happen, and holding\n   * the `complete` gate pending while it waits.\n   *\n   * A target with no branch filter deploys from every branch, so one of those\n   * collapses the union to no clause at all.\n   *\n   * Deliberately no `!cancelled()`, unlike the diff report: a report is wanted\n   * precisely when a diff failed, but an approval is not. GitHub's default —\n   * skip a job whose `needs` failed — is what should happen here, and it\n   * cascades to every deploy job waiting on the approval.\n   */\n  private buildApprovalCondition = (\n    homeRepositoryCondition: string | undefined,\n  ): string => {\n    const branchConditions = this.awsDeploymentTargets.map((target) =>\n      this.buildBranchFilterCondition(target.branches),\n    );\n    const anyBranch = branchConditions.some((condition) => !condition);\n    const branchClause = anyBranch\n      ? undefined\n      : Array.from(new Set(branchConditions)).join(\" || \");\n\n    return (\n      \"${{ \" +\n      [\n        \"!needs.build.outputs.self_mutation_happened\",\n        ...(homeRepositoryCondition ? [homeRepositoryCondition] : []),\n        ...(branchClause ? [`(${branchClause})`] : []),\n      ].join(\" && \") +\n      \" }}\"\n    );\n  };\n\n  /**\n   * Steps for a target's deploy job.\n   *\n   * `stickyPrComment` drops the sticky-PR-comment step when false. Apply jobs\n   * pass false: they only ever run on `workflow_dispatch` and so could never\n   * satisfy that step's own `pull_request` guard.\n   */\n  private deploySteps = (\n    target: AwsDeploymentTarget,\n    options: { stickyPrComment?: boolean } = {},\n  ): Array<JobStep> => {\n    const { stickyPrComment = true } = options;\n    const {\n      awsStageType,\n      deploymentTargetRole,\n      account,\n      region,\n      ciDeploymentConfig,\n      awsDeploymentConfig,\n    } = target;\n    const { roleArn, stackPattern } = ciDeploymentConfig ?? {};\n    const { rootCdkOut, cdkCli } = awsDeploymentConfig;\n    const deployJobName = this.buildJobName(target);\n\n    return [\n      ...this.setupPnpm(),\n      ...this.setupNode(),\n\n      /**\n       * Configure AWS creds.\n       */\n      {\n        name: `AWS Creds ${awsStageType}/${deploymentTargetRole}/${account}/${region}`,\n        uses: \"aws-actions/configure-aws-credentials@v6\",\n        with: {\n          \"role-to-assume\": roleArn,\n          \"aws-region\": region,\n          \"role-duration-seconds\": 900, // 15 minutes\n        },\n      },\n\n      /**\n       * Run CDK Deploy\n       */\n      {\n        name: `Deploy ${awsStageType}/${deploymentTargetRole}/${account}/${region}`,\n        run: `pnpm dlx \"aws-cdk@${cdkCli.cliVersion}\" ${renderCdkDeploy({\n          ...cdkCli.deployOptionsFor(target),\n          app: rootCdkOut,\n          stackPatterns: stackPattern ? [stackPattern] : undefined,\n        })} --outputs-file cdk-outputs.json`,\n      },\n\n      /**\n       * Render a job-summary table listing every `*Endpoint` output emitted\n       * by the deploy. Also writes the same list to `deploy-urls.md` so the\n       * follow-up sticky-PR-comment step can reuse it.\n       *\n       * The file is only created when jq returns at least one match — an\n       * empty `deploy-urls.md` would pass the downstream `hashFiles(...)`\n       * guard and then fail the sticky-comment action with\n       * \"Either message or path input is required\" (issue #721).\n       */\n      {\n        name: \"Render deploy summary\",\n        if: \"hashFiles('cdk-outputs.json') != ''\",\n        shell: \"bash\",\n        run: [\n          '# Convention: CfnOutputs whose logical ID ends in \"Endpoint\" are surfaced.',\n          \"# See docs/packages/@codedrifters/configulator/workflows/aws-deploy-workflow#surfacing-deploy-urls\",\n          `endpoints=$(jq -r '[.[] | to_entries[] | select(.key | test(\"Endpoint$\")) | .value] | .[] | \"- [\\\\(.)](\\\\(.))\"' cdk-outputs.json)`,\n          'if [ -n \"$endpoints\" ]; then',\n          '  echo \"## Deployed endpoints\" >> \"$GITHUB_STEP_SUMMARY\"',\n          '  echo \"$endpoints\" >> \"$GITHUB_STEP_SUMMARY\"',\n          '  echo \"\" >> \"$GITHUB_STEP_SUMMARY\"',\n          '  echo \"_DNS/CloudFront may take ~1 minute to propagate._\" >> \"$GITHUB_STEP_SUMMARY\"',\n          \"  printf '%s\\\\n' \\\"$endpoints\\\" > deploy-urls.md\",\n          \"fi\",\n        ].join(\"\\n\"),\n      },\n\n      /**\n       * Post a sticky PR comment listing each deployed endpoint. The\n       * comment is keyed by the deploy job name so dev/stage/prod comments\n       * don't collide on the same PR.\n       */\n      ...(stickyPrComment\n        ? [\n            {\n              name: \"Sticky PR comment with deploy endpoints\",\n              if: \"github.event_name == 'pull_request' && hashFiles('deploy-urls.md') != ''\",\n              uses: \"marocchino/sticky-pull-request-comment@v3\",\n              with: {\n                header: deployJobName,\n                path: \"deploy-urls.md\",\n              },\n            },\n          ]\n        : []),\n    ];\n  };\n\n  /**\n   * Steps for a target's optional `cdk diff` job.\n   *\n   * Mirrors {@link deploySteps}' toolchain and credential setup — same pnpm /\n   * Node setup, same version-pinned `aws-cdk` CLI, same OIDC role — so a diff\n   * is computed by the same CLI that will run the deploy.\n   *\n   * The `cdk diff` flags come from the {@link CdkCli} precedence chain via\n   * `diffOptionsFor(target)`, so `method`, `securityOnly`, `fail`, and the rest\n   * are consumer-controlled per stage, per account, or per target. Four options\n   * are pinned at the call site because the capture mechanism depends on them:\n   * `app` and `stackPatterns` target the built cloud assembly, and `ci` /\n   * `noColor` force the human-readable diff onto stdout without ANSI escapes\n   * (without `--ci` the CLI interleaves it into stderr alongside logs).\n   *\n   * `method` is the one resolved flag not baked into the rendered command. A\n   * from-scratch target has to be classified before it can be diffed — see\n   * {@link diffProbeLines} — so the command reads the effective method from\n   * `$method`.\n   */\n  private diffSteps = (target: AwsDeploymentTarget): Array<JobStep> => {\n    const {\n      awsStageType,\n      deploymentTargetRole,\n      account,\n      region,\n      ciDeploymentConfig,\n      awsDeploymentConfig,\n    } = target;\n    const { roleArn, stackPattern } = ciDeploymentConfig ?? {};\n    const { rootCdkOut, cdkCli } = awsDeploymentConfig;\n    const label = `${awsStageType}/${deploymentTargetRole}/${account}/${region}`;\n    const outputFile = this.buildDiffOutputFile(target);\n    const stackPatterns = stackPattern ? [stackPattern] : undefined;\n    const diffCommand = [\n      `pnpm dlx \"aws-cdk@${cdkCli.cliVersion}\"`,\n      renderCdkDiff({\n        ...cdkCli.diffOptionsFor(target),\n        app: rootCdkOut,\n        ci: true,\n        noColor: true,\n        method: undefined,\n        stackPatterns: undefined,\n      }),\n      '--method=\"$method\"',\n      ...(stackPatterns ?? []).map((pattern) => `\"${pattern}\"`),\n    ].join(\" \");\n\n    return [\n      ...this.setupPnpm(),\n      ...this.setupNode(),\n\n      /**\n       * Configure AWS creds.\n       */\n      {\n        name: `AWS Creds ${label}`,\n        uses: \"aws-actions/configure-aws-credentials@v6\",\n        with: {\n          \"role-to-assume\": roleArn,\n          \"aws-region\": region,\n          \"role-duration-seconds\": 900, // 15 minutes\n        },\n      },\n\n      /**\n       * Classify the target's stacks, then run CDK Diff, capturing the output\n       * while leaving it visible in the job log. `pipefail` keeps the CLI's\n       * exit code from being masked by `tee`.\n       *\n       * The capture lands under the same path the report job will merge it\n       * back to, so a target's file name is identical in both places. It is\n       * truncated first and appended to from there, so a re-run never reads a\n       * previous attempt's banners.\n       */\n      {\n        name: `Diff ${label}`,\n        shell: \"bash\",\n        run: [\n          \"set -o pipefail\",\n          `mkdir -p ${DIFF_OUTPUT_DIRECTORY}`,\n          `: > ${outputFile}`,\n          ...this.diffProbeLines(target, outputFile),\n          `${diffCommand} 2>&1 | tee -a ${outputFile}`,\n        ].join(\"\\n\"),\n      },\n\n      /**\n       * Hand the capture to the report job. Guarded on `!cancelled()` rather\n       * than success, so a diff that exits non-zero — a synth error, or a\n       * consumer who opted into `--fail` — still contributes what it captured\n       * instead of leaving a hole in the report.\n       */\n      renderDiffPartUploadStep({\n        label,\n        artifactName: this.buildDiffPartArtifactName(target),\n        outputFile,\n      }),\n    ];\n  };\n\n  /**\n   * Lines that classify every stack a target's pattern matches before the diff\n   * runs, so a stack that will be created from scratch is reported as such\n   * instead of failing the job.\n   *\n   * `cdk diff --method=change-set` asks CloudFormation for an `UPDATE` change\n   * set whenever the stack exists — and a `ROLLBACK_COMPLETE` /\n   * `ROLLBACK_FAILED` tombstone left by a failed first create does exist, so\n   * CloudFormation rejects the request and the job goes red. `cdk deploy`\n   * consults `stackStatus.isCreationFailure`, deletes the tombstone and\n   * recreates the stack, so the apply succeeds on exactly the stack the diff\n   * refuses to look at. Under the `plan-apply` gate that asymmetry is a hard\n   * blocker rather than a cosmetic one: the apply requires a successful plan\n   * run, so one from-scratch target blocks applying any plan for the stage.\n   *\n   * A genuinely absent stack fails the same way for a different reason:\n   * `CreateChangeSet` resolves `AWS::SSM::Parameter::Value` template\n   * parameters when the change set is created, so a never-deployed stack that\n   * consumes parameters written by other not-yet-deployed stacks cannot get a\n   * `CREATE` change set at all (`Unable to fetch parameters [...] from\n   * parameter store for this account`). That deadlocks the first deployment of\n   * an entire stage: no green plan without the upstream stacks, no upstream\n   * stacks without an apply, no apply without a green plan.\n   *\n   * `cdk list --long --json` resolves the pattern to CloudFormation stack names\n   * out of the built assembly's manifest — no synth, no cloud call — and each\n   * name costs one `describe-stacks`, which needs only\n   * `cloudformation:DescribeStacks`. Any role that can run a change-set diff\n   * already carries it. A `cdk list` that fails contributes no names, leaving\n   * the diff to run exactly as it does today.\n   *\n   * Both from-scratch arms therefore move the method, and only to `template`,\n   * never to `auto`: `auto` would swallow a real permission failure and\n   * present a degraded diff as authoritative, which is what an explicit\n   * `change-set` pin exists to prevent. `template` over-reporting replacements\n   * is vacuous here, because every resource in a stack built from scratch is\n   * an add. A stack in any other status keeps the configured method.\n   *\n   * The method is per invocation, not per stack — `cdk diff` diffs everything\n   * its pattern matches in one pass. A pattern matching several stacks where\n   * only one is from-scratch therefore diffs all of them with `template`, and\n   * the banner names the stack that caused it.\n   */\n  private diffProbeLines = (\n    target: AwsDeploymentTarget,\n    outputFile: string,\n  ): Array<string> => {\n    const { ciDeploymentConfig, awsDeploymentConfig } = target;\n    const { stackPattern } = ciDeploymentConfig ?? {};\n    const { rootCdkOut, cdkCli } = awsDeploymentConfig;\n    const configuredMethod =\n      cdkCli.diffOptionsFor(target).method ?? CDK_DIFF_METHOD.ChangeSet;\n    const listCommand = `pnpm dlx \"aws-cdk@${cdkCli.cliVersion}\" ${renderCdkList(\n      {\n        app: rootCdkOut,\n        json: true,\n        long: true,\n        stackPatterns: stackPattern ? [stackPattern] : undefined,\n      },\n    )}`;\n\n    return [\n      `method=${configuredMethod}`,\n      \"while read -r stack; do\",\n      '  status=$(aws cloudformation describe-stacks --stack-name \"$stack\" --query \"Stacks[0].StackStatus\" --output text 2>/dev/null || echo NOT_FOUND)',\n      '  case \"$status\" in',\n      \"    NOT_FOUND|REVIEW_IN_PROGRESS)\",\n      `      method=${CDK_DIFF_METHOD.Template}`,\n      `      echo \"${DIFF_NEW_STACK_MARKER} — $stack does not exist yet, so this target will be created from scratch. Diffing it with --method=${CDK_DIFF_METHOD.Template}.\" | tee -a ${outputFile}`,\n      \"      ;;\",\n      \"    ROLLBACK_COMPLETE|ROLLBACK_FAILED)\",\n      `      method=${CDK_DIFF_METHOD.Template}`,\n      `      echo \"${DIFF_NEW_STACK_MARKER} — $stack exists only as a failed-create tombstone ($status), so this target will be created from scratch. Diffing it with --method=${CDK_DIFF_METHOD.Template}.\" | tee -a ${outputFile}`,\n      \"      ;;\",\n      \"  esac\",\n      `done < <(${listCommand} 2>/dev/null | jq -r '.[].name' 2>/dev/null)`,\n    ];\n  };\n\n  preSynthesize(): void {\n    /**\n     * Ensure turbo is active when needed.\n     */\n    if (!this.externalWorkflow && TurboRepo.of(this.rootProject)) {\n      this.buildWorkflow.addPostBuildSteps(\n        {\n          name: \"Build Sub Projects\",\n          run: `pnpm exec projen ${ROOT_CI_TASK_NAME}`,\n        },\n        WorkflowSteps.uploadArtifact({\n          name: \"Upload Turbo runs\",\n          if: \"always()\",\n          continueOnError: true,\n          with: {\n            name: \"turbo-runs\",\n            path: \".turbo/runs\",\n          },\n        }),\n      );\n    }\n\n    super.preSynthesize();\n  }\n}\n","import { Component, Project } from \"projen\";\nimport { GitHub, GithubWorkflow } from \"projen/lib/github\";\nimport { Job, JobPermission } from \"projen/lib/github/workflows-model\";\nimport {\n  PLAN_RUN_ID_INPUT,\n  VALIDATE_PLAN_JOB_ID,\n  renderPlanValidationScript,\n} from \"./plan-apply\";\nimport { AwsDeploymentTarget } from \"../aws/aws-deployment-target\";\n\n/**\n * Settings every `AwsDeployWorkflow` sharing one apply workflow must agree on,\n * because they are baked into the single shared `validate-plan` job.\n */\nexport interface ApplyWorkflowContract {\n  /**\n   * Name of the plan (build) workflow whose runs this apply workflow accepts.\n   */\n  readonly planWorkflowName: string;\n\n  /**\n   * Assert the plan run's commit is still the head of its branch.\n   */\n  readonly requireCurrentHead: boolean;\n\n  /**\n   * Resolve and export the build artifact's digest during validation.\n   */\n  readonly verifyArtifactDigest: boolean;\n}\n\n/**\n * Inputs to {@link ApplyWorkflow.attach}.\n */\nexport interface ApplyWorkflowAttachOptions extends ApplyWorkflowContract {\n  /**\n   * Targets the attaching component deploys. Their branches join the union the\n   * validation job accepts.\n   */\n  readonly awsDeploymentTargets: Array<AwsDeploymentTarget>;\n\n  /**\n   * Component name used in thrown error messages.\n   */\n  readonly componentName: string;\n}\n\n/**\n * Inputs to the {@link ApplyWorkflow} constructor.\n */\nexport interface ApplyWorkflowOptions extends ApplyWorkflowAttachOptions {\n  /**\n   * File name (without `.yml`) of the generated apply workflow.\n   */\n  readonly applyWorkflowName: string;\n\n  /**\n   * Rendered repository-guard expression for the validation job, if any.\n   */\n  readonly homeRepositoryCondition?: string;\n}\n\n/**\n * The dispatch-only apply workflow behind the `plan-apply` gate, plus the state\n * every `AwsDeployWorkflow` attached to it shares.\n *\n * One component owns the file so several deploy components — typically one per\n * service in a multi-service repo, all sharing a build workflow — can put their\n * apply jobs in it. That is what lets a cross-service `deployAfterTargets`\n * graph render as valid `needs`: GitHub resolves `needs` only within a single\n * workflow file.\n *\n * @see `docs/packages/@codedrifters/configulator/workflows/aws-deploy-workflow.md`\n */\nexport class ApplyWorkflow extends Component {\n  public static of(\n    project: Project,\n    workflow: GithubWorkflow,\n  ): ApplyWorkflow | undefined {\n    const isDefined = (c: Component): c is ApplyWorkflow =>\n      c instanceof ApplyWorkflow && c.workflow === workflow;\n    return project.components.find(isDefined);\n  }\n\n  /**\n   * The generated workflow. Exposed so a second `AwsDeployWorkflow` can be\n   * pointed at it via `planApply.applyWorkflow`.\n   */\n  public readonly workflow: GithubWorkflow;\n\n  /**\n   * Settings every attached component must agree on.\n   */\n  public readonly contract: ApplyWorkflowContract;\n\n  /**\n   * Repository guard on the validation job, if any.\n   */\n  private readonly homeRepositoryCondition?: string;\n\n  /**\n   * Every attached component's targets, in attach order. Held as targets rather\n   * than branches because `AwsDeploymentTarget.branches` is mutable — the\n   * branch union is read at `preSynthesize`, once every component has attached.\n   */\n  private readonly attachedTargets: Array<AwsDeploymentTarget> = [];\n\n  constructor(project: Project, github: GitHub, options: ApplyWorkflowOptions) {\n    super(project);\n\n    const { applyWorkflowName } = options;\n\n    /**\n     * A name already in use would silently collide on the underlying\n     * `.github/workflows/<name>.yml` file. The usual cause is two components\n     * that each create an apply workflow while sharing one build workflow; the\n     * fixes are `planApply.applyWorkflow` to share this one, or\n     * `planApply.applyWorkflowName` to create a second under its own name.\n     */\n    if (github.tryFindWorkflow(applyWorkflowName)) {\n      throw new Error(\n        `${options.componentName} cannot create the apply workflow \"${applyWorkflowName}\" because a workflow with that name already exists. Set \\`planApply.applyWorkflow\\` to share the existing one, or \\`planApply.applyWorkflowName\\` to something unique.`,\n      );\n    }\n\n    this.contract = {\n      planWorkflowName: options.planWorkflowName,\n      requireCurrentHead: options.requireCurrentHead,\n      verifyArtifactDigest: options.verifyArtifactDigest,\n    };\n    this.homeRepositoryCondition = options.homeRepositoryCondition;\n    this.attachedTargets.push(...options.awsDeploymentTargets);\n\n    this.workflow = new GithubWorkflow(github, applyWorkflowName);\n\n    this.workflow.on({\n      workflowDispatch: {\n        inputs: {\n          [PLAN_RUN_ID_INPUT]: {\n            description:\n              \"Run id of the plan workflow run to apply. Its build artifact is deployed verbatim.\",\n            required: true,\n            type: \"string\",\n          },\n        },\n      },\n    });\n\n    /**\n     * Registered here rather than at `preSynthesize` so the validation job\n     * keeps its position ahead of every apply job in the rendered file.\n     * `preSynthesize` replaces it in place once the branch union is final.\n     */\n    this.workflow.addJob(VALIDATE_PLAN_JOB_ID, this.renderValidateJob());\n  }\n\n  /**\n   * Attach another component's apply jobs to this workflow.\n   *\n   * Every setting the shared `validate-plan` job bakes in must match what the\n   * workflow was created with — there is one validation job for the whole file,\n   * so a disagreement cannot be honoured and is rejected rather than resolved\n   * in favour of whichever component happened to be constructed first.\n   */\n  public attach = (options: ApplyWorkflowAttachOptions): void => {\n    const { componentName } = options;\n    const name = this.workflow.name;\n\n    if (options.planWorkflowName !== this.contract.planWorkflowName) {\n      throw new Error(\n        `${componentName} cannot attach to the apply workflow \"${name}\": it plans from build workflow \"${options.planWorkflowName}\", but that apply workflow only accepts runs of \"${this.contract.planWorkflowName}\". Every component sharing an apply workflow must share one build workflow.`,\n      );\n    }\n\n    this.requireAgreement(\n      componentName,\n      \"requireCurrentHead\",\n      options.requireCurrentHead,\n      this.contract.requireCurrentHead,\n    );\n    this.requireAgreement(\n      componentName,\n      \"verifyArtifactDigest\",\n      options.verifyArtifactDigest,\n      this.contract.verifyArtifactDigest,\n    );\n\n    this.attachedTargets.push(...options.awsDeploymentTargets);\n  };\n\n  preSynthesize(): void {\n    /**\n     * Re-rendered now that every component has attached, so `allowedBranches`\n     * covers the union of all of their targets. `updateJob` replaces the job in\n     * place, leaving its position — and a single-component workflow's rendered\n     * YAML — unchanged.\n     */\n    this.workflow.updateJob(VALIDATE_PLAN_JOB_ID, this.renderValidateJob());\n\n    super.preSynthesize();\n  }\n\n  /**\n   * Reject a boolean `planApply` setting that differs from the one this\n   * workflow was created with.\n   */\n  private requireAgreement = (\n    componentName: string,\n    option: string,\n    supplied: boolean,\n    expected: boolean,\n  ): void => {\n    if (supplied === expected) {\n      return;\n    }\n\n    throw new Error(\n      `${componentName} cannot attach to the apply workflow \"${this.workflow.name}\": \\`planApply.${option}\\` is ${supplied} here and ${expected} on the components already attached. The setting is baked into the one shared \\`${VALIDATE_PLAN_JOB_ID}\\` job, so every component sharing an apply workflow must agree on it.`,\n    );\n  };\n\n  /**\n   * Render the validation job every apply job depends on.\n   *\n   * `allowedBranches` is the union of every attached target's branches, deduped\n   * and left in attach order. The apply run's own `github.ref` says nothing\n   * about what was planned, so the list is checked against the *plan run's*\n   * `head_branch` rather than against a workflow-level branch filter.\n   */\n  private renderValidateJob = (): Job => {\n    const { planWorkflowName, requireCurrentHead, verifyArtifactDigest } =\n      this.contract;\n\n    const allowedBranches = Array.from(\n      new Set(\n        this.attachedTargets.flatMap((target) =>\n          target.branches.map((b) => b.branch),\n        ),\n      ),\n    );\n\n    return {\n      name: \"Validate plan run\",\n      runsOn: [\"ubuntu-latest\"],\n      permissions: {\n        actions: JobPermission.READ,\n        contents: JobPermission.READ,\n      },\n      ...(this.homeRepositoryCondition\n        ? { if: `\\${{ ${this.homeRepositoryCondition} }}` }\n        : {}),\n      outputs: {\n        head_sha: { stepId: \"validate_plan_run\", outputName: \"head_sha\" },\n        head_branch: { stepId: \"validate_plan_run\", outputName: \"head_branch\" },\n        ...(verifyArtifactDigest\n          ? {\n              artifact_digest: {\n                stepId: \"validate_plan_run\",\n                outputName: \"artifact_digest\",\n              },\n            }\n          : {}),\n      },\n      steps: [\n        {\n          name: \"Validate plan run\",\n          id: \"validate_plan_run\",\n          uses: \"actions/github-script@v9\",\n          /**\n           * The dispatch input reaches the script through the environment\n           * rather than a `${{ }}` interpolation, so a crafted run id cannot\n           * inject JavaScript into the validation itself.\n           */\n          env: {\n            PLAN_RUN_ID: `\\${{ inputs.${PLAN_RUN_ID_INPUT} }}`,\n          },\n          with: {\n            script: renderPlanValidationScript({\n              planWorkflowPath: `.github/workflows/${planWorkflowName}.yml`,\n              allowedBranches,\n              requireCurrentHead,\n              verifyArtifactDigest,\n            }),\n          },\n        },\n      ],\n    };\n  };\n}\n","import { GithubWorkflow } from \"projen/lib/github\";\n\n/**\n * Job id of the apply workflow's validation job. Every apply job depends on\n * it, so a failed validation skips the whole apply run.\n */\nexport const VALIDATE_PLAN_JOB_ID = \"validate-plan\";\n\n/**\n * Name of the `workflow_dispatch` input carrying the plan run to apply.\n */\nexport const PLAN_RUN_ID_INPUT = \"plan_run_id\";\n\n/**\n * Name of the artifact projen's build job uploads. The apply workflow\n * downloads this one cross-run.\n *\n * Mirrors projen's internal `BUILD_ARTIFACT_NAME`, which is not re-exported\n * from `projen/lib/github`.\n */\nexport const BUILD_ARTIFACT_NAME = \"build-artifact\";\n\n/**\n * Permission-backup file projen writes beside the build artifact.\n *\n * Mirrors projen's internal `PERMISSION_BACKUP_FILE`, which is not\n * re-exported from `projen/lib/github`.\n */\nexport const PERMISSION_BACKUP_FILE = \"permissions-backup.acl\";\n\n/**\n * Extra knobs for the `plan-apply` gate. Every field is optional and only read\n * when `gate` is `plan-apply`.\n */\nexport interface PlanApplyOptions {\n  /**\n   * Put this workflow's apply jobs on an apply workflow another\n   * `AwsDeployWorkflow` already created, instead of creating a second one.\n   *\n   * Pass that component's `applyWorkflow`. Sharing is what lets a multi-service\n   * repo render a cross-service `deployAfterTargets` graph: GitHub resolves\n   * `needs` only within a single workflow file. Every component sharing an\n   * apply workflow must share one build workflow and agree on\n   * {@link requireCurrentHead}, {@link verifyArtifactDigest}, and\n   * `homeRepository`, all of which the single shared validation job bakes in.\n   *\n   * Mutually exclusive with {@link applyWorkflowName}.\n   *\n   * @see `docs/packages/@codedrifters/configulator/workflows/aws-deploy-workflow.md`\n   * @default - this component creates its own apply workflow\n   */\n  readonly applyWorkflow?: GithubWorkflow;\n\n  /**\n   * File name (without `.yml`) of the generated apply workflow.\n   *\n   * @default - the plan workflow's name suffixed with `-apply`\n   */\n  readonly applyWorkflowName?: string;\n\n  /**\n   * Also assert the plan run's `head_sha` still equals the current head of the\n   * branch it ran on, so a plan can only be applied while it is still the tip\n   * of its branch.\n   *\n   * Off by default: a legitimate approval window is exactly the time in which\n   * someone may push an unrelated commit, and failing every such apply is\n   * usually more disruptive than the drift it prevents.\n   *\n   * @default false\n   */\n  readonly requireCurrentHead?: boolean;\n\n  /**\n   * Resolve the plan run's build-artifact digest during validation and pass it\n   * to `actions/download-artifact` as `artifact-digest`, so a download whose\n   * content does not match is rejected.\n   *\n   * Fails closed when the API reports no digest for the artifact.\n   *\n   * @default false\n   */\n  readonly verifyArtifactDigest?: boolean;\n}\n\n/**\n * Inputs to {@link renderPlanValidationScript}.\n */\nexport interface PlanValidationScriptOptions {\n  /**\n   * Repo-relative path of the plan workflow file the run must belong to.\n   */\n  readonly planWorkflowPath: string;\n\n  /**\n   * Branch patterns the plan run is allowed to have run on. Exact names and\n   * trailing globs (`feature/*`) are both supported.\n   */\n  readonly allowedBranches: Array<string>;\n\n  /**\n   * Assert the plan run's commit is still the branch head.\n   */\n  readonly requireCurrentHead: boolean;\n\n  /**\n   * Resolve and export the build artifact's digest.\n   */\n  readonly verifyArtifactDigest: boolean;\n}\n\n/**\n * Render the `actions/github-script` body that validates a plan run before any\n * apply job assumes a deploy role.\n *\n * Every check fails closed — the script `setFailed`s and returns rather than\n * falling through — because everything downstream of it deploys to a real\n * account. The run id arrives via `process.env.PLAN_RUN_ID` rather than a\n * `${{ }}` interpolation so a crafted dispatch input cannot inject JavaScript\n * into this script.\n *\n * @see `docs/packages/@codedrifters/configulator/workflows/aws-deploy-workflow.md`\n */\nexport const renderPlanValidationScript = (\n  options: PlanValidationScriptOptions,\n): string => {\n  const {\n    planWorkflowPath,\n    allowedBranches,\n    requireCurrentHead,\n    verifyArtifactDigest,\n  } = options;\n\n  return [\n    \"const raw = (process.env.PLAN_RUN_ID ?? '').trim();\",\n    \"const runId = Number(raw);\",\n    \"if (!/^[0-9]+$/.test(raw) || !Number.isSafeInteger(runId) || runId <= 0) {\",\n    '  core.setFailed(`plan_run_id must be a positive run id, got \"${raw}\"`);',\n    \"  return;\",\n    \"}\",\n    \"\",\n    \"const { owner, repo } = context.repo;\",\n    \"const { data: run } = await github.rest.actions.getWorkflowRun({\",\n    \"  owner,\",\n    \"  repo,\",\n    \"  run_id: runId,\",\n    \"});\",\n    \"\",\n    `const expectedPath = ${JSON.stringify(planWorkflowPath)};`,\n    \"if (run.path !== expectedPath) {\",\n    '  core.setFailed(`Run ${runId} belongs to workflow \"${run.path}\", expected \"${expectedPath}\".`);',\n    \"  return;\",\n    \"}\",\n    \"\",\n    'if (run.status !== \"completed\" || run.conclusion !== \"success\") {',\n    '  core.setFailed(`Run ${runId} is status \"${run.status}\" / conclusion \"${run.conclusion}\", expected a completed successful plan run.`);',\n    \"  return;\",\n    \"}\",\n    \"\",\n    `const allowedBranches = ${JSON.stringify(allowedBranches)};`,\n    'const branch = run.head_branch ?? \"\";',\n    \"const branchAllowed = allowedBranches.some((pattern) =>\",\n    '  pattern.includes(\"*\")',\n    '    ? branch.startsWith(pattern.slice(0, pattern.indexOf(\"*\")))',\n    \"    : branch === pattern,\",\n    \");\",\n    \"if (!branchAllowed) {\",\n    '  core.setFailed(`Run ${runId} ran on branch \"${branch}\", which no deployment target in this workflow accepts (allowed: ${allowedBranches.join(\", \")}).`);',\n    \"  return;\",\n    \"}\",\n    ...(requireCurrentHead\n      ? [\n          \"\",\n          \"const { data: liveBranch } = await github.rest.repos.getBranch({\",\n          \"  owner,\",\n          \"  repo,\",\n          \"  branch,\",\n          \"});\",\n          \"if (liveBranch.commit.sha !== run.head_sha) {\",\n          '  core.setFailed(`Run ${runId} planned ${run.head_sha} but \"${branch}\" now points at ${liveBranch.commit.sha}. Re-run the plan workflow against the current head.`);',\n          \"  return;\",\n          \"}\",\n        ]\n      : []),\n    \"\",\n    \"const artifacts = await github.paginate(\",\n    \"  github.rest.actions.listWorkflowRunArtifacts,\",\n    \"  { owner, repo, run_id: runId, per_page: 100 },\",\n    \");\",\n    `const artifactName = ${JSON.stringify(BUILD_ARTIFACT_NAME)};`,\n    \"const artifact = artifacts.find((a) => a.name === artifactName);\",\n    \"if (!artifact) {\",\n    '  core.setFailed(`Run ${runId} published no \"${artifactName}\" artifact. Only a plan run whose build job completed can be applied.`);',\n    \"  return;\",\n    \"}\",\n    \"if (artifact.expired) {\",\n    '  core.setFailed(`The \"${artifactName}\" artifact on run ${runId} expired at ${artifact.expires_at}. Artifact retention is this gate\\'s approval window — re-run the plan workflow.`);',\n    \"  return;\",\n    \"}\",\n    ...(verifyArtifactDigest\n      ? [\n          \"if (!artifact.digest) {\",\n          '  core.setFailed(`The \"${artifactName}\" artifact on run ${runId} reports no digest, so it cannot be verified. Disable planApply.verifyArtifactDigest or re-run the plan workflow.`);',\n          \"  return;\",\n          \"}\",\n          'core.setOutput(\"artifact_digest\", artifact.digest);',\n        ]\n      : []),\n    \"\",\n    'core.setOutput(\"head_sha\", run.head_sha);',\n    'core.setOutput(\"head_branch\", branch);',\n    \"await core.summary\",\n    \"  .addHeading(`Applying plan run ${runId}`, 2)\",\n    \"  .addTable([\",\n    '    [{ data: \"Field\", header: true }, { data: \"Value\", header: true }],',\n    '    [\"Plan run\", `<a href=\"${run.html_url}\">${runId}</a>`],',\n    '    [\"Branch\", branch],',\n    '    [\"Commit\", run.head_sha],',\n    '    [\"Artifact expires\", artifact.expires_at ?? \"unknown\"],',\n    \"  ])\",\n    \"  .write();\",\n  ].join(\"\\n\");\n};\n","import { ValueOf } from \"type-fest\";\n\n/**\n * Gate models a deploy workflow can be held behind.\n *\n * @see `docs/packages/@codedrifters/configulator/workflows/aws-deploy-workflow.md`\n */\nexport const DEPLOY_GATE = {\n  /**\n   * Hold each deploy job behind a GitHub environment so its protection rules —\n   * required reviewers, wait timers, deployment branch policies — apply before\n   * the job is sent to a runner.\n   */\n  ENVIRONMENT: \"environment\",\n\n  /**\n   * Split the workflow in two. A **plan** workflow builds and diffs but never\n   * deploys; a dispatch-only **apply** workflow deploys the exact cloud\n   * assembly a nominated plan run produced.\n   *\n   * Needs no protection rule, so unlike {@link DEPLOY_GATE.ENVIRONMENT} it\n   * works on every GitHub plan. `environmentName` is optional here and layers\n   * an environment onto the apply jobs.\n   */\n  PLAN_APPLY: \"plan-apply\",\n} as const;\n\nexport type DeployGate = ValueOf<typeof DEPLOY_GATE>;\n\n/**\n * How many approvals the {@link DEPLOY_GATE.ENVIRONMENT} gate asks an operator\n * for across one run.\n *\n * @see `docs/packages/@codedrifters/configulator/workflows/aws-deploy-workflow.md`\n */\nexport const DEPLOY_APPROVALS = {\n  /**\n   * One approval per deploy job. The environment sits on every deploy job, so\n   * each reaches its protection rules on its own — and deploy jobs chained by\n   * `deployAfterTargets` reach them one at a time, with a full deploy between\n   * each prompt.\n   */\n  PER_TARGET: \"per-target\",\n\n  /**\n   * One approval for the whole run. A dedicated approval job carries the\n   * required-reviewer rule and every deploy job waits on it, so the operator\n   * approves once and the rest of the run proceeds unattended.\n   *\n   * Requires `approvalEnvironmentName`, and it must name a *different*\n   * environment than the deploy jobs' — the deploy jobs keep their own\n   * `environment` so their OIDC subject claims, environment-scoped secrets,\n   * and per-stack deployment history are untouched.\n   */\n  ONCE: \"once\",\n} as const;\n\nexport type DeployApprovals = ValueOf<typeof DEPLOY_APPROVALS>;\n\n/**\n * Job id of the single approval job emitted under\n * {@link DEPLOY_APPROVALS.ONCE}.\n */\nexport const APPROVE_JOB_ID = \"approve\";\n\n/**\n * Resolve the GitHub environment the single approval job sits behind,\n * validating the pairing at synth time.\n *\n * Mirrors {@link resolveEnvironmentGate}: every rejected combination is one\n * that renders a workflow which *looks* gated the way it was configured and is\n * not. A name with no `approvals: \"once\"` is inert, `approvals: \"once\"` with no\n * name has nothing to gate on, `approvals: \"once\"` outside the `environment`\n * gate has no deploy jobs in this workflow to hold, and an approval\n * environment equal to the deploy environment reintroduces the per-target\n * prompts the option exists to remove.\n *\n * @see `docs/packages/@codedrifters/configulator/workflows/aws-deploy-workflow.md`\n * @param gate - Gate model, or `undefined` to leave the workflow ungated.\n * @param approvals - Approval model, defaulting to `per-target` when unset.\n * @param approvalEnvironmentName - Approval environment, required under `once`.\n * @param environmentName - Resolved deploy environment, used for the collision check.\n * @param componentName - Component name used in the thrown error message.\n * @returns The approval environment name, or `undefined` under `per-target`.\n */\nexport const resolveApprovalGate = (\n  gate: DeployGate | undefined,\n  approvals: DeployApprovals | undefined,\n  approvalEnvironmentName: string | undefined,\n  environmentName: string | undefined,\n  componentName: string,\n): string | undefined => {\n  const trimmed = approvalEnvironmentName?.trim();\n\n  if (approvals !== DEPLOY_APPROVALS.ONCE) {\n    if (trimmed) {\n      throw new Error(\n        `${componentName} requires \\`approvals\\` to be \"${DEPLOY_APPROVALS.ONCE}\" when \\`approvalEnvironmentName\\` is supplied, got \"${approvalEnvironmentName}\" with \\`approvals\\` ${\n          approvals ? `\"${approvals}\"` : \"unset\"\n        }`,\n      );\n    }\n    return undefined;\n  }\n\n  if (gate !== DEPLOY_GATE.ENVIRONMENT) {\n    throw new Error(\n      `${componentName} requires \\`gate\\` to be \"${DEPLOY_GATE.ENVIRONMENT}\" when \\`approvals\\` is \"${DEPLOY_APPROVALS.ONCE}\", got ${\n        gate ? `\"${gate}\"` : \"no gate\"\n      }`,\n    );\n  }\n\n  if (!trimmed) {\n    throw new Error(\n      `${componentName} requires a non-empty \\`approvalEnvironmentName\\` when \\`approvals\\` is \"${DEPLOY_APPROVALS.ONCE}\"`,\n    );\n  }\n\n  if (trimmed === environmentName?.trim()) {\n    throw new Error(\n      `${componentName} requires \\`approvalEnvironmentName\\` to name a different environment than \\`environmentName\\`, got \"${trimmed}\" for both — a shared environment puts the reviewer rule back on every deploy job, which is the per-target prompting \"${DEPLOY_APPROVALS.ONCE}\" exists to remove`,\n    );\n  }\n\n  return trimmed;\n};\n\n/**\n * Resolve the GitHub environment a workflow's gated jobs sit behind,\n * validating the pairing at synth time.\n *\n * A name with no `gate` throws, because it is silently inert. A `gate` with no\n * name throws only under {@link DEPLOY_GATE.ENVIRONMENT}, where the\n * environment *is* the whole gate and has nothing to attach to without one.\n * Under {@link DEPLOY_GATE.PLAN_APPLY} the dispatch split is the gate and the\n * environment is an optional second checkpoint on the apply jobs.\n *\n * @see `docs/packages/@codedrifters/configulator/workflows/aws-deploy-workflow.md`\n * @param gate - Gate model, or `undefined` to leave the workflow ungated.\n * @param environmentName - Environment name, required under `environment`.\n * @param componentName - Component name used in the thrown error message.\n * @returns The environment name, or `undefined` when no environment applies.\n */\nexport const resolveEnvironmentGate = (\n  gate: DeployGate | undefined,\n  environmentName: string | undefined,\n  componentName: string,\n): string | undefined => {\n  const trimmed = environmentName?.trim();\n\n  if (gate === undefined) {\n    if (trimmed) {\n      throw new Error(\n        `${componentName} requires \\`gate\\` to be set when \\`environmentName\\` is supplied, got \"${environmentName}\" with no gate`,\n      );\n    }\n    return undefined;\n  }\n\n  if (gate === DEPLOY_GATE.ENVIRONMENT && !trimmed) {\n    throw new Error(\n      `${componentName} requires a non-empty \\`environmentName\\` when \\`gate\\` is \"${gate}\"`,\n    );\n  }\n\n  return trimmed;\n};\n\n/**\n * Resolve whether the per-target `cdk diff` jobs carry the deploy\n * environment, validating the pairing at synth time.\n *\n * The flag exists for one reason: a job's OIDC subject claim is\n * `repo:<owner>/<repo>:environment:<name>` when the job declares an\n * environment and `repo:<owner>/<repo>:ref:refs/heads/<branch>` when it does\n * not. A deployer-role trust policy narrowed to environment subjects alone\n * therefore rejects the diff jobs — the only cloud-touching jobs the\n * {@link DEPLOY_GATE.ENVIRONMENT} gate leaves on the ref claim — and since the\n * merged report gates every deploy, the whole run dies before anything\n * deploys. Stamping the environment on the diff jobs puts them on the same\n * subject as the deploys they inform.\n *\n * Mirrors {@link resolveEnvironmentGate} and {@link resolveApprovalGate}:\n * every rejected combination renders a workflow whose diff jobs *look*\n * environment-scoped and are not, and the symptom is a role-assumption failure\n * at run time rather than an error at synth time.\n *\n * Outside {@link DEPLOY_GATE.ENVIRONMENT} there is no deploy environment to\n * borrow. Under {@link DEPLOY_GATE.PLAN_APPLY} that is deliberate rather than\n * incidental: the deploy jobs live in the apply workflow, so any\n * `environmentName` belongs to *that* workflow, and the plan's diff is the\n * review surface an operator reads before dispatching the apply. Holding it\n * behind the apply's environment would make the review wait on the approval it\n * exists to inform.\n *\n * @see `docs/packages/@codedrifters/configulator/workflows/aws-deploy-workflow.md`\n * @param gate - Gate model, or `undefined` to leave the workflow ungated.\n * @param diffEnvironment - The `diff.environment` flag as the caller set it.\n * @param diffEnabled - Resolved `diff.enabled`, so an inert flag is caught.\n * @param componentName - Component name used in the thrown error message.\n * @returns Whether the diff jobs carry the deploy environment.\n */\nexport const resolveDiffEnvironment = (\n  gate: DeployGate | undefined,\n  diffEnvironment: boolean | undefined,\n  diffEnabled: boolean,\n  componentName: string,\n): boolean => {\n  if (!diffEnvironment) {\n    return false;\n  }\n\n  if (gate !== DEPLOY_GATE.ENVIRONMENT) {\n    throw new Error(\n      `${componentName} requires \\`gate\\` to be \"${DEPLOY_GATE.ENVIRONMENT}\" when \\`diff.environment\\` is set, got ${\n        gate ? `\"${gate}\"` : \"no gate\"\n      }`,\n    );\n  }\n\n  if (!diffEnabled) {\n    throw new Error(\n      `${componentName} requires \\`diff.enabled\\` when \\`diff.environment\\` is set — there are no diff jobs to put the environment on`,\n    );\n  }\n\n  return true;\n};\n","import { Component, Project } from \"projen\";\nimport { BuildWorkflow } from \"projen/lib/build\";\nimport { WorkflowSteps } from \"projen/lib/github\";\nimport { JobPermission, JobStep } from \"projen/lib/github/workflows-model\";\n\n/**\n * Job id of the report job that merges every target's captured diff into one\n * reviewable summary and artifact.\n */\nexport const DIFF_REPORT_JOB_ID = \"diff-report\";\n\n/**\n * Directory each target's diff is captured to, and the directory the report job\n * merges every downloaded part into.\n */\nexport const DIFF_OUTPUT_DIRECTORY = \"cdk-diff\";\n\n/**\n * Artifact-name prefix for a single target's captured diff.\n *\n * These are intermediates: the diff jobs run in parallel and\n * `actions/upload-artifact` v4+ treats artifact names as immutable, so each\n * target must upload under its own name. The report job merges them into\n * {@link DIFF_ARTIFACT_NAME}, which is the one meant to be read.\n */\nexport const DIFF_PART_ARTIFACT_PREFIX = \"cdk-diff-part\";\n\n/**\n * Name of the single merged artifact carrying every target's diff.\n */\nexport const DIFF_ARTIFACT_NAME = \"cdk-diff\";\n\n/**\n * Line prefix a diff job writes at the head of its capture when a matched stack\n * will be created from scratch — it does not exist, or exists only as a\n * failed-create tombstone.\n *\n * Deliberately plain ASCII and anchored at the start of a line: the diff job\n * writes it and the report job greps for it, so it doubles as the machine\n * signal that lets the report surface a from-scratch target outside its\n * collapsed `<details>` block.\n */\nexport const DIFF_NEW_STACK_MARKER = \"NEW STACK\";\n\n/**\n * Retention for the per-target parts. They exist only to reach the report job\n * in the same run, so they are kept for the minimum GitHub allows rather than\n * cluttering the run's artifact list for the full retention period.\n */\nconst DIFF_PART_RETENTION_DAYS = 1;\n\n/**\n * Byte budget for the diff text embedded in `$GITHUB_STEP_SUMMARY`.\n *\n * GitHub caps a step summary at 1 MiB and silently drops the whole thing when\n * the cap is exceeded. The cap is per step and the report renders every target\n * in one step, so this budget is split across them — a single noisy target must\n * not be able to cost every other target its summary.\n */\nconst DIFF_SUMMARY_BYTE_LIMIT = 900000;\n\n/**\n * One target's contribution to the diff report.\n */\nexport interface DiffReportTarget {\n  /**\n   * Human-readable target label, used as the summary heading.\n   */\n  readonly label: string;\n\n  /**\n   * Job id of the target's own diff job. Becomes a `needs` entry on the report.\n   */\n  readonly jobName: string;\n\n  /**\n   * File the target's diff lands at once the parts are merged.\n   */\n  readonly outputFile: string;\n\n  /**\n   * Branch filter this target deploys under, if any.\n   */\n  readonly branchCondition?: string;\n}\n\n/**\n * Inputs to {@link DiffReportJob.attach}.\n */\nexport interface DiffReportJobAttachOptions {\n  /**\n   * Plan workflow the report belongs to. One report job per build workflow.\n   */\n  readonly buildWorkflow: BuildWorkflow;\n\n  /**\n   * Rendered repository-guard expression, if the workflow is pinned.\n   */\n  readonly homeRepositoryCondition?: string;\n\n  /**\n   * Render the merged diffs into the job summary.\n   */\n  readonly summary: boolean;\n\n  /**\n   * Upload the merged diffs as a single run artifact.\n   */\n  readonly artifact: boolean;\n\n  /**\n   * Targets the attaching component contributes.\n   */\n  readonly targets: Array<DiffReportTarget>;\n}\n\n/**\n * The run URL, assembled entirely from runtime context so the generated\n * workflow keeps working when a consumer repo is forked, mirrored, or cloned\n * into another organization.\n */\nconst RUN_URL =\n  \"${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\";\n\n/**\n * The job that turns a plan workflow's per-target `cdk diff` jobs into one\n * reviewable summary and one artifact.\n *\n * The diffs themselves stay in their own jobs, in parallel — a diff is a\n * read-only comparison and there is no reason to serialize them, and each needs\n * its own account's credentials anyway. What does not scale is the *review*:\n * under the `plan-apply` gate the diff is the only review surface, so a\n * seven-service repo would otherwise mean seven job summaries to open and\n * reconcile by hand. This job downloads every target's part, renders them under\n * one heading each, and uploads the merged directory as a single artifact.\n *\n * Every deploy component sharing the build workflow contributes here, so the\n * report spans services rather than stopping at one.\n *\n * @see `docs/packages/@codedrifters/configulator/workflows/aws-deploy-workflow.md`\n */\nexport class DiffReportJob extends Component {\n  public static of(\n    project: Project,\n    buildWorkflow: BuildWorkflow,\n  ): DiffReportJob | undefined {\n    const isDefined = (c: Component): c is DiffReportJob =>\n      c instanceof DiffReportJob && c.buildWorkflow === buildWorkflow;\n    return project.components.find(isDefined);\n  }\n\n  /**\n   * Add a component's targets to the plan workflow's diff report, creating the\n   * report job the first time it is called for that workflow.\n   */\n  public static attach(\n    project: Project,\n    options: DiffReportJobAttachOptions,\n  ): DiffReportJob {\n    const existing = DiffReportJob.of(project, options.buildWorkflow);\n\n    if (existing) {\n      existing.record(options);\n      return existing;\n    }\n\n    return new DiffReportJob(project, options);\n  }\n\n  /**\n   * Plan workflow this report belongs to.\n   */\n  public readonly buildWorkflow: BuildWorkflow;\n\n  private readonly homeRepositoryCondition?: string;\n\n  /**\n   * Every contributed target, in attach order.\n   */\n  private readonly targets: Array<DiffReportTarget> = [];\n\n  /**\n   * Publish settings are OR-ed rather than first-wins: one report means one\n   * answer, and a component that asked for a summary should get one even when\n   * a sibling did not.\n   */\n  private summary = false;\n\n  private artifact = false;\n\n  constructor(project: Project, options: DiffReportJobAttachOptions) {\n    super(project);\n\n    this.buildWorkflow = options.buildWorkflow;\n    this.homeRepositoryCondition = options.homeRepositoryCondition;\n    this.record(options);\n\n    /**\n     * Registered on the workflow directly rather than through\n     * `addPostBuildJob`, which would prepend a download of the build artifact\n     * this job has no use for — it consumes the diff parts, not the assembly.\n     * The per-target diff jobs remain post-build jobs, so the invariant that\n     * keeps projen uploading the build artifact is unaffected.\n     *\n     * Registration has to happen now rather than at `preSynthesize`, because\n     * `addBuildCompleteJob` enumerates the workflow's jobs at the end of the\n     * `AwsDeployWorkflow` constructor to build the aggregate gate's `needs`. A\n     * job added later would be missing from that gate.\n     */\n    this.buildWorkflow.workflow.addJob(DIFF_REPORT_JOB_ID, {\n      name: \"Diff report\",\n      needs: [\"build\"],\n      runsOn: [\"ubuntu-latest\"],\n      permissions: {\n        contents: JobPermission.READ,\n      },\n      steps: [],\n    });\n  }\n\n  preSynthesize(): void {\n    this.buildWorkflow.workflow.updateJob(DIFF_REPORT_JOB_ID, {\n      name: \"Diff report\",\n      /**\n       * `build` is a direct dependency so the job can read its\n       * self-mutation output, which is otherwise unreachable — the `needs`\n       * context only carries direct dependencies, not transitive ones.\n       */\n      needs: [\n        \"build\",\n        ...Array.from(new Set(this.targets.map((target) => target.jobName))),\n      ],\n      runsOn: [\"ubuntu-latest\"],\n      permissions: {\n        contents: JobPermission.READ,\n      },\n      if: this.renderJobCondition(),\n      steps: [\n        ...this.renderDownloadStep(),\n        ...this.renderSummaryStep(),\n        ...this.renderUploadStep(),\n        ...this.renderFailureStep(),\n      ],\n    });\n\n    super.preSynthesize();\n  }\n\n  /**\n   * Fold one component's contribution in.\n   */\n  private record = (options: DiffReportJobAttachOptions): void => {\n    this.targets.push(...options.targets);\n    this.summary = this.summary || options.summary;\n    this.artifact = this.artifact || options.artifact;\n  };\n\n  /**\n   * Compose the report's own condition.\n   *\n   * `!cancelled()` leads, and it is load-bearing: a job whose `needs` failed or\n   * were skipped is skipped by default, so without a status function the report\n   * would vanish in exactly the cases it is most wanted — one target's diff\n   * failing, or some targets not applying to this branch.\n   */\n  private renderJobCondition = (): string => {\n    const branchConditions = this.targets.map(\n      (target) => target.branchCondition,\n    );\n    const anyBranch = branchConditions.some((condition) => !condition);\n    const branchClause = anyBranch\n      ? undefined\n      : Array.from(new Set(branchConditions)).join(\" || \");\n\n    return (\n      \"${{ \" +\n      [\n        \"!cancelled()\",\n        \"!needs.build.outputs.self_mutation_happened\",\n        ...(this.homeRepositoryCondition ? [this.homeRepositoryCondition] : []),\n        ...(branchClause ? [`(${branchClause})`] : []),\n      ].join(\" && \") +\n      \" }}\"\n    );\n  };\n\n  /**\n   * Pull every target's part into one directory.\n   *\n   * `continueOnError` because a run where every target's diff job was skipped\n   * by its branch filter matches no parts at all, and a report with nothing to\n   * report is not a failure.\n   */\n  private renderDownloadStep = (): Array<JobStep> => {\n    return [\n      WorkflowSteps.downloadArtifact({\n        name: \"Download target diffs\",\n        continueOnError: true,\n        with: {\n          pattern: `${DIFF_PART_ARTIFACT_PREFIX}-*`,\n          mergeMultiple: true,\n          path: DIFF_OUTPUT_DIRECTORY,\n        },\n      }),\n    ];\n  };\n\n  /**\n   * Render every target's diff into the job summary, one collapsed `<details>`\n   * block per target.\n   *\n   * A target whose part is absent renders as \"did not run\", which is what\n   * distinguishes a target that was skipped or whose diff failed before it\n   * captured anything from one that simply had no changes — the latter has a\n   * file, carrying the CDK CLI's own no-differences wording, rather than being\n   * detected by matching on it.\n   *\n   * A capture carrying {@link DIFF_NEW_STACK_MARKER} lines has its banners\n   * lifted out of the `<details>` block and quoted under the heading, so a\n   * target that will be created from scratch reads as such without expanding\n   * anything.\n   */\n  private renderSummaryStep = (): Array<JobStep> => {\n    if (!this.summary || this.targets.length === 0) {\n      return [];\n    }\n\n    const budget = Math.floor(DIFF_SUMMARY_BYTE_LIMIT / this.targets.length);\n    const rows = this.targets.map(\n      (target) => `'${target.label}|${target.outputFile}'`,\n    );\n\n    return [\n      {\n        name: \"Render diff report\",\n        if: \"!cancelled()\",\n        shell: \"bash\",\n        run: [\n          \"{\",\n          \"  while IFS='|' read -r label file; do\",\n          '    echo \"## cdk diff — $label\"',\n          '    echo \"\"',\n          '    if [ ! -f \"$file\" ]; then',\n          \"      echo '_Did not run._'\",\n          '      echo \"\"',\n          \"      continue\",\n          \"    fi\",\n          `    if grep -q '^${DIFF_NEW_STACK_MARKER}' \"$file\"; then`,\n          `      grep '^${DIFF_NEW_STACK_MARKER}' \"$file\" | sed 's/^/> **/; s/$/**/'`,\n          '      echo \"\"',\n          \"    fi\",\n          \"    echo '<details><summary>cdk diff output</summary>'\",\n          '    echo \"\"',\n          \"    echo '```'\",\n          `    if [ \"$(wc -c < \"$file\")\" -gt ${budget} ]; then`,\n          `      head -c ${budget} \"$file\"`,\n          `      printf '\\\\n... truncated at ${budget} bytes ...\\\\n'`,\n          \"    else\",\n          '      cat \"$file\"',\n          \"    fi\",\n          \"    echo '```'\",\n          '    echo \"\"',\n          \"    echo '</details>'\",\n          '    echo \"\"',\n          `  done < <(printf '%s\\\\n' ${rows.join(\" \")})`,\n          ...(this.artifact\n            ? [\n                `  echo 'Full diff: the \\`${DIFF_ARTIFACT_NAME}\\` artifact on [this run](${RUN_URL}).'`,\n              ]\n            : []),\n          '} >> \"$GITHUB_STEP_SUMMARY\"',\n        ].join(\"\\n\"),\n      },\n    ];\n  };\n\n  /**\n   * Fail the report when any target's diff failed.\n   *\n   * Runs last, so the summary and the artifact are published first — a reviewer\n   * still gets the whole picture, including whatever the failing target managed\n   * to capture. But the report must not end up green: everything gated behind\n   * it `needs` it, and a job whose `needs` failed is skipped, which is what\n   * keeps a failed diff from letting a gated deploy through to *Waiting for\n   * approval*. Without this the report would always succeed and a diff failure\n   * would only soft-block behind a human.\n   *\n   * Only `failure` counts. A target skipped by its branch filter reports\n   * `skipped`, which is normal and must not fail the report.\n   */\n  private renderFailureStep = (): Array<JobStep> => {\n    const jobNames = Array.from(\n      new Set(this.targets.map((target) => target.jobName)),\n    );\n\n    if (jobNames.length === 0) {\n      return [];\n    }\n\n    return [\n      {\n        name: \"Fail if any target's diff failed\",\n        if: \"!cancelled()\",\n        shell: \"bash\",\n        run: [\n          ...jobNames.map(\n            (jobName) =>\n              `if [ \"\\${{ needs.${jobName}.result }}\" = \"failure\" ]; then echo \"::error::Diff job ${jobName} failed\"; failed=1; fi`,\n          ),\n          'if [ \"${failed:-0}\" = \"1\" ]; then exit 1; fi',\n        ].join(\"\\n\"),\n      },\n    ];\n  };\n\n  /**\n   * Upload the merged directory as the one artifact meant to be read.\n   */\n  private renderUploadStep = (): Array<JobStep> => {\n    if (!this.artifact || this.targets.length === 0) {\n      return [];\n    }\n\n    return [\n      WorkflowSteps.uploadArtifact({\n        name: \"Upload combined diff\",\n        if: \"!cancelled()\",\n        with: {\n          name: DIFF_ARTIFACT_NAME,\n          path: DIFF_OUTPUT_DIRECTORY,\n          ifNoFilesFound: \"ignore\",\n        },\n      }),\n    ];\n  };\n}\n\n/**\n * Upload step for a single target's captured diff, run inside that target's own\n * diff job.\n *\n * Guarded on `!cancelled()` rather than success, so a `cdk diff` that exits\n * non-zero still hands whatever it captured to the report.\n */\nexport const renderDiffPartUploadStep = (options: {\n  label: string;\n  artifactName: string;\n  outputFile: string;\n}): JobStep => {\n  return WorkflowSteps.uploadArtifact({\n    name: `Upload diff ${options.label}`,\n    if: \"!cancelled()\",\n    with: {\n      name: options.artifactName,\n      path: options.outputFile,\n      ifNoFilesFound: \"ignore\",\n      retentionDays: DIFF_PART_RETENTION_DAYS,\n    },\n  });\n};\n","import { Component, Project } from \"projen\";\n\n/**\n * Shape of an `owner/repo` slug. GitHub permits alphanumerics, `-`, `_`, and\n * `.` in both segments, separated by exactly one slash.\n */\nconst HOME_REPOSITORY_PATTERN = /^[A-Za-z0-9._-]+\\/[A-Za-z0-9._-]+$/;\n\n/**\n * Render the GitHub Actions expression fragment that pins a job to one\n * repository, validating the slug at synth time.\n *\n * Validation is deliberately eager: a typo'd slug matches no repository, so\n * every guarded job would skip silently while the aggregate `complete` gate\n * still reported success. Failing synth surfaces that immediately.\n *\n * @see `docs/packages/@codedrifters/configulator/workflows/aws-deploy-workflow.md`\n * @param homeRepository - `owner/repo` slug, or `undefined` to emit no guard.\n * @param componentName - Component name used in the thrown error message.\n * @returns The condition fragment, or `undefined` when the workflow is unpinned.\n */\nexport const renderHomeRepositoryCondition = (\n  homeRepository: string | undefined,\n  componentName: string,\n): string | undefined => {\n  if (homeRepository === undefined) {\n    return undefined;\n  }\n\n  if (!HOME_REPOSITORY_PATTERN.test(homeRepository)) {\n    throw new Error(\n      `${componentName} requires \\`homeRepository\\` to be an \\`owner/repo\\` slug, got \"${homeRepository}\"`,\n    );\n  }\n\n  return `github.repository == '${homeRepository}'`;\n};\n\n/**\n * Inputs to {@link WorkflowHomeRepository.require}.\n */\nexport interface WorkflowHomeRepositoryOptions {\n  /**\n   * Workflow the pin applies to. Object identity is the key, so a projen\n   * `BuildWorkflow` and a `GithubWorkflow` are both valid.\n   */\n  readonly workflow: Component;\n\n  /**\n   * Workflow file name, used in the thrown error message.\n   */\n  readonly workflowName: string;\n\n  /**\n   * `owner/repo` slug this component declared, or `undefined` for no pin.\n   */\n  readonly homeRepository?: string;\n\n  /**\n   * Component name used in the thrown error message.\n   */\n  readonly componentName: string;\n}\n\n/**\n * Render a slug for an error message, distinguishing \"no pin\" from a pin.\n */\nconst describePin = (homeRepository: string | undefined): string =>\n  homeRepository === undefined ? \"unset\" : `\"${homeRepository}\"`;\n\n/**\n * The `homeRepository` pin declared against one workflow file.\n *\n * The pin is a property of the workflow, not of whichever component declared\n * it: it guards every cloud-touching job in the file, and under the\n * `plan-apply` gate the shared `validate-plan` job carries it for every apply\n * job that needs it. A skipped `needs` job skips its dependents, so one\n * component's pin would otherwise silently govern services that never asked to\n * be pinned. This component records the first declaration and rejects any later\n * one that disagrees.\n *\n * @see `docs/packages/@codedrifters/configulator/workflows/aws-deploy-workflow.md`\n */\nexport class WorkflowHomeRepository extends Component {\n  public static of(\n    project: Project,\n    workflow: Component,\n  ): WorkflowHomeRepository | undefined {\n    const isDefined = (c: Component): c is WorkflowHomeRepository =>\n      c instanceof WorkflowHomeRepository && c.workflow === workflow;\n    return project.components.find(isDefined);\n  }\n\n  /**\n   * Record a pin against a workflow, throwing when it disagrees with what an\n   * earlier component declared for the same one.\n   *\n   * @param project - Project the record is attached to. Use the root project,\n   * so components on sibling sub-projects find each other.\n   */\n  public static require(\n    project: Project,\n    options: WorkflowHomeRepositoryOptions,\n  ): WorkflowHomeRepository {\n    const { workflow, workflowName, homeRepository, componentName } = options;\n    const existing = WorkflowHomeRepository.of(project, workflow);\n\n    if (!existing) {\n      return new WorkflowHomeRepository(project, options);\n    }\n\n    if (existing.homeRepository !== homeRepository) {\n      throw new Error(\n        `${componentName} requires every component sharing the workflow \"${workflowName}\" to declare the same \\`homeRepository\\`, got ${describePin(homeRepository)} here and ${describePin(existing.homeRepository)} already declared. The pin guards every job in one workflow file, so it cannot differ between them.`,\n      );\n    }\n\n    return existing;\n  }\n\n  /**\n   * Workflow this pin applies to.\n   */\n  public readonly workflow: Component;\n\n  /**\n   * `owner/repo` slug every component sharing the workflow must declare, or\n   * `undefined` when the workflow is unpinned.\n   */\n  public readonly homeRepository?: string;\n\n  constructor(project: Project, options: WorkflowHomeRepositoryOptions) {\n    super(project);\n\n    this.workflow = options.workflow;\n    this.homeRepository = options.homeRepository;\n  }\n}\n","import { JobStep } from \"projen/lib/github/workflows-model\";\nimport { VERSION } from \"../versions\";\n\n/**\n * Steps that put Node on the runner.\n *\n * Occasionally fails on GitHub-internal issues, hence the short timeout.\n */\nexport const renderSetupNode = (): Array<JobStep> => {\n  return [\n    {\n      name: \"Setup Node\",\n      uses: `actions/setup-node@${VERSION.SETUP_NODE_ACTION_VERSION}`,\n      with: {\n        [\"node-version\"]: VERSION.NODE_WORKFLOWS,\n      },\n      timeoutMinutes: 1,\n    },\n  ];\n};\n\n/**\n * Steps that put pnpm on the runner, pinned to the project's version.\n */\nexport const renderSetupPnpm = (pnpmVersion: string): Array<JobStep> => {\n  return [\n    {\n      name: \"Setup PNPM\",\n      uses: `pnpm/action-setup@${VERSION.PNPM_ACTION_SETUP_VERSION}`,\n      with: {\n        version: pnpmVersion,\n      },\n    },\n  ];\n};\n","import { Component } from \"projen\";\nimport { GitHub, GithubWorkflow } from \"projen/lib/github\";\nimport { JobPermission } from \"projen/lib/github/workflows-model\";\nimport { renderHomeRepositoryCondition } from \"./home-repository\";\nimport { AwsDeploymentTarget } from \"../aws/aws-deployment-target\";\nimport { MonorepoProject } from \"../projects/monorepo-project\";\n\n/**\n * Default branch-delete patterns that trigger the teardown workflow.\n */\nexport const DEFAULT_TEARDOWN_BRANCH_PATTERNS: ReadonlyArray<string> = [\n  \"feat/*\",\n  \"fix/*\",\n  \"feature/*\",\n];\n\n/**\n * Options for {@link AwsTeardownWorkflow}.\n */\nexport interface AwsTeardownWorkflowOptions {\n  /**\n   * Targets to scan for orphaned CloudFormation stacks.\n   */\n  readonly awsDestructionTargets: Array<AwsDeploymentTarget>;\n\n  /**\n   * Name of the tag containing the repo name. Used to find CloudFormation\n   * stacks associated with this repo.\n   */\n  readonly repoTagName: string;\n\n  /**\n   * Name of the tag containing the stage type (e.g. dev, stage, prod).\n   */\n  readonly stageTypeTagName: string;\n\n  /**\n   * Name of the tag containing the environment type (e.g. primary, secondary).\n   */\n  readonly environmentTypeTagName: string;\n\n  /**\n   * Name of the tag where branch names are stored. Used to determine if a\n   * stack is orphaned (no matching branch).\n   */\n  readonly branchNameTagName: string;\n\n  /**\n   * Branch patterns whose deletion triggers the teardown workflow.\n   *\n   * @default [\"feat/*\", \"fix/*\", \"feature/*\"]\n   */\n  readonly deleteBranchPatterns?: Array<string>;\n\n  /**\n   * Pin the teardown jobs to one repository, as an `owner/repo` slug.\n   *\n   * Guards every teardown job with `github.repository == '<owner>/<repo>'` so a\n   * mirror or clone of the consumer repo does not delete stacks it does not\n   * own. Especially load-bearing here: a clone's branch list differs from the\n   * home repo's, so an unguarded scheduled run would classify live stacks as\n   * orphans.\n   *\n   * @see `docs/packages/@codedrifters/configulator/workflows/aws-deploy-workflow.md`\n   * @default - no repository guard is emitted\n   */\n  readonly homeRepository?: string;\n}\n\n/**\n * Resolve the set of branch-delete patterns to wire into the workflow's\n * `on.delete.branches` trigger.\n *\n * Precedence:\n * 1. Explicit `deleteBranchPatterns` from options.\n * 2. Wildcard patterns (containing `*`) derived from the destruction\n *    targets' configured branches, deduped.\n * 3. {@link DEFAULT_TEARDOWN_BRANCH_PATTERNS} as a last-resort fallback.\n */\nconst resolveBranchPatterns = (\n  explicit: Array<string> | undefined,\n  targets: ReadonlyArray<AwsDeploymentTarget>,\n): Array<string> => {\n  if (explicit && explicit.length > 0) {\n    return [...explicit];\n  }\n\n  const derived = Array.from(\n    new Set(\n      targets\n        .flatMap((target) => target.branches.map((b) => b.branch))\n        .filter((branch): branch is string => typeof branch === \"string\")\n        .filter((branch) => branch.includes(\"*\")),\n    ),\n  );\n\n  if (derived.length > 0) {\n    return derived;\n  }\n\n  return [...DEFAULT_TEARDOWN_BRANCH_PATTERNS];\n};\n\n/**\n * Scheduled GitHub Actions workflow that tears down orphaned CloudFormation\n * stacks whose associated branch no longer exists.\n */\nexport class AwsTeardownWorkflow extends Component {\n  constructor(\n    public rootProject: MonorepoProject,\n    options: AwsTeardownWorkflowOptions,\n  ) {\n    super(rootProject);\n\n    const {\n      awsDestructionTargets,\n      repoTagName,\n      stageTypeTagName,\n      environmentTypeTagName,\n      branchNameTagName,\n      deleteBranchPatterns,\n      homeRepository,\n    } = options;\n\n    if (!repoTagName) {\n      throw new Error(\"AwsTeardownWorkflow requires `repoTagName`\");\n    }\n    if (!stageTypeTagName) {\n      throw new Error(\"AwsTeardownWorkflow requires `stageTypeTagName`\");\n    }\n    if (!environmentTypeTagName) {\n      throw new Error(\"AwsTeardownWorkflow requires `environmentTypeTagName`\");\n    }\n    if (!branchNameTagName) {\n      throw new Error(\"AwsTeardownWorkflow requires `branchNameTagName`\");\n    }\n\n    if (!(rootProject instanceof MonorepoProject)) {\n      throw new Error(\n        \"AwsTeardownWorkflow requires the root project to be a MonorepoProject\",\n      );\n    }\n\n    const github = GitHub.of(this.rootProject);\n\n    if (!github) {\n      throw new Error(\n        \"AwsTeardownWorkflow requires a GitHub component in the root project\",\n      );\n    }\n\n    const branchPatterns = resolveBranchPatterns(\n      deleteBranchPatterns,\n      awsDestructionTargets,\n    );\n\n    /**\n     * Optional repository pin. Unset (the default) emits no `if:` at all, so\n     * the generated workflow is unchanged.\n     */\n    const homeRepositoryCondition = renderHomeRepositoryCondition(\n      homeRepository,\n      \"AwsTeardownWorkflow\",\n    );\n\n    const workflow = new GithubWorkflow(github, \"teardown-dev\");\n    workflow.on({\n      workflowDispatch: {},\n      schedule: [\n        {\n          cron: \"32 6 * * *\",\n        },\n      ],\n      delete: {\n        branches: branchPatterns,\n      },\n    });\n\n    awsDestructionTargets.forEach((target) => {\n      const {\n        awsStageType,\n        deploymentTargetRole,\n        account,\n        region,\n        ciDeploymentConfig,\n      } = target;\n      const { roleArn } = ciDeploymentConfig ?? {};\n\n      workflow.addJob(\n        `teardown-${awsStageType}-${deploymentTargetRole}-${account}-${region}`.toLowerCase(),\n        {\n          name: `Teardown Stacks in ${awsStageType}/${deploymentTargetRole}/${account}/${region}`,\n          runsOn: [\"ubuntu-latest\"],\n          ...(homeRepositoryCondition\n            ? { if: `\\${{ ${homeRepositoryCondition} }}` }\n            : {}),\n          permissions: {\n            contents: JobPermission.READ,\n            idToken: JobPermission.WRITE,\n          },\n          env: {\n            REPO: \"${{ github.repository }}\",\n            REGIONS: [region].join(\" \"),\n          },\n          steps: [\n            {\n              name: `AWS Creds ${account}/${region}`,\n              uses: \"aws-actions/configure-aws-credentials@v6\",\n              with: {\n                \"role-to-assume\": roleArn,\n                \"aws-region\": region,\n                \"role-duration-seconds\": 900,\n              },\n            },\n            {\n              name: \"Fetch All Branches\",\n              id: \"fetch_branches\",\n              uses: \"actions/github-script@v9\",\n              with: {\n                script: [\n                  \"const all = await github.paginate(github.rest.repos.listBranches, {\",\n                  \"  owner: context.repo.owner,\",\n                  \"  repo: context.repo.repo,\",\n                  \"  per_page: 100\",\n                  \"});\",\n                  \"const names = all.map(b => b.name);\",\n                  \"console.log(`Found branches: ${names}`);\",\n                  'core.setOutput(\"json\", JSON.stringify(names));',\n                ].join(\"\\n\"),\n              },\n            },\n            {\n              name: \"Save Branches to File\",\n              run: [\n                'echo \"Saving branches to file\"',\n                \"echo '${{ steps.fetch_branches.outputs.json }}' | jq -r '.[]' | sort -u > branches.txt\",\n                'echo \"Branches:\"',\n                \"cat branches.txt\",\n              ].join(\"\\n\"),\n            },\n            {\n              name: \"Find Stacks by Tag\",\n              id: \"find_stacks\",\n              run: [\n                \"set -euo pipefail\",\n                \": > candidates.txt  # columns: arn region branchTag\",\n                \"# Build tag filters\",\n                `TAG_FILTERS=( \"Key=${repoTagName},Values=$REPO\" )`,\n                `TAG_FILTERS+=( \"Key=${stageTypeTagName},Values=${awsStageType}\" )`,\n                `TAG_FILTERS+=( \"Key=${environmentTypeTagName},Values=${deploymentTargetRole}\" )`,\n                \"for r in $REGIONS; do\",\n                `  echo \"Scanning region: $r\"`,\n                \"  aws resourcegroupstaggingapi get-resources \\\\\",\n                '    --region \"$r\" \\\\',\n                '    --resource-type-filters \"cloudformation:stack\" \\\\',\n                '    --tag-filters \"${TAG_FILTERS[@]}\" \\\\',\n                ` | jq -r --arg r \"$r\" '`,\n                \"    .ResourceTagMappingList[]\",\n                \"    | . as $res\",\n                `    | ($res.Tags[] | select(.Key==\"${branchNameTagName}\") | .Value) as $branch`,\n                '    | [$res.ResourceARN, $r, ($branch // \"\")]',\n                \"    | @tsv\",\n                \"    ' >> candidates.txt\",\n                \"done\",\n                \"echo 'Tagged stacks:'\",\n                `(echo -e \"ARN\\\\tREGION\\\\tBRANCH\"; cat candidates.txt) | column -t -s $'\\\\t'`,\n              ].join(\"\\n\"),\n            },\n            {\n              name: \"Determine Orphan Stacks (No Matching Branch)\",\n              run: [\n                \"set -euo pipefail\",\n                \": > orphans.txt  # arn region branch\",\n                \"while IFS=$'\\\\t' read -r arn region branch; do\",\n                '  [ -z \"$arn\" ] && continue',\n                '  if [ -z \"$branch\" ]; then',\n                \"    # If no Branch tag, treat as not-a-preview; skip\",\n                \"    continue\",\n                \"  fi\",\n                '  if ! grep -Fxq \"$branch\" branches.txt; then',\n                '    echo -e \"$arn\\\\t$region\\\\t$branch\" >> orphans.txt',\n                \"  fi\",\n                \"done < candidates.txt\",\n                \"\",\n                \"if [ -s orphans.txt ]; then\",\n                '  echo \"Orphan stacks (no matching branch):\"',\n                \"  (echo -e \\\"ARN\\\\tREGION\\\\tBRANCH\\\"; cat orphans.txt) | column -t -s $'\\\\t'\",\n                \"else\",\n                '  echo \"No orphan stacks found.\"',\n                \"fi\",\n              ].join(\"\\n\"),\n            },\n            {\n              name: \"Delete Orphan Stacks\",\n              if: \"hashFiles('orphans.txt') != ''\",\n              run: [\n                \"set -euo pipefail\",\n                \"while IFS=$'\\\\t' read -r arn region branch; do\",\n                '  [ -z \"$arn\" ] && continue',\n                \"  stack_name=$(cut -d'/' -f2 <<<\\\"$arn\\\")\",\n                '  echo \"Deleting $stack_name (branch=$branch) in $region\"',\n                '  aws cloudformation delete-stack --region \"$region\" --stack-name \"$stack_name\" || true',\n                \"done < orphans.txt\",\n              ].join(\"\\n\"),\n            },\n          ],\n        },\n      );\n    });\n  }\n}\n","import { SampleFile, TextFile } from \"projen\";\nimport { merge } from \"ts-deepmerge\";\nimport { resolveReactViteSiteProjectOutdir } from \"./resolve-outdir\";\nimport {\n  TestRunner,\n  TypeScriptProject,\n  TypeScriptProjectOptions,\n} from \"./typescript-project\";\nimport { TurboRepo } from \"../turbo\";\n\n/**\n * Configuration options for {@link ReactViteSiteProject}.\n *\n * Inherits every option from {@link TypeScriptProjectOptions}. Additional\n * deps the caller wants on top of the baked-in React / Vite / Tailwind /\n * Vitest stack go through the standard `deps` / `devDeps` arrays — they\n * merge with the project's defaults rather than replacing them.\n */\nexport interface ReactViteSiteProjectOptions extends TypeScriptProjectOptions {\n  /**\n   * Emit minimal React + Vite starter files (`index.html`, `src/main.tsx`,\n   * `src/App.tsx`, `src/routes.tsx`, `src/index.css`, `src/setupTests.ts`).\n   *\n   * @default false\n   */\n  readonly sampleCode?: boolean;\n}\n\n/**\n * Vite + React 19 + Tailwind v4 + Vitest site scaffolded on top of\n * {@link TypeScriptProject}.\n *\n * Replaces the inherited `tsc` compile step with `vite build`, wires\n * Vitest as the test runner (with jsdom + Testing Library defaults),\n * registers ESLint rules for React, applies team-friendly VSCode\n * defaults, and pins Node via `.nvmrc`. Defaults `outdir` to\n * `sites/<scope>/<name>` per the monorepo-layout contract (ADR-006).\n *\n * The Tailwind v4 integration goes through `@tailwindcss/vite` — no\n * PostCSS pipeline — matching the canonical CodeDrifters React-site\n * scaffold.\n *\n * @see ./react-vite-site-project.ts — implementation\n * @see ./add-storybook.ts — opt-in Storybook add-on\n * @see ./add-playwright.ts — opt-in Playwright E2E add-on\n */\nexport class ReactViteSiteProject extends TypeScriptProject {\n  constructor(userOptions: ReactViteSiteProjectOptions) {\n    /*************************************************************************\n     *\n     * Resolve outdir\n     *\n     * When the caller omits `outdir`, derive it from the scoped package\n     * name (`packageName ?? name`) as `sites/<scope>/<name>`. This\n     * enforces the monorepo-layout contract (ADR-006) without requiring\n     * every React-site sub-project to restate its own path. Resolution\n     * runs before `super()` so the derived value is passed explicitly —\n     * otherwise the TypeScriptProject base class would default it to\n     * `packages/<scope>/<name>` instead.\n     *\n     ************************************************************************/\n\n    const resolvedOutdir =\n      userOptions.outdir ??\n      resolveReactViteSiteProjectOutdir(\n        userOptions.packageName ?? userOptions.name,\n      );\n\n    /**\n     * React sites consume Vitest as their test runner (Jest does not\n     * cooperate with Vite's ESM-only config) and never expose a library\n     * API surface, so the inherited `@microsoft/api-extractor` wiring\n     * is opt-in for these projects. Callers can flip\n     * `apiExtractor: { ... }` back on if they genuinely re-export a\n     * typed surface.\n     *\n     * Use `ts-deepmerge`'s `merge()` (not a shallow spread) so a default\n     * nested object like\n     * `tsconfig: { compilerOptions: { declaration: false } }` survives a\n     * user override that only sets unrelated tsconfig fields.\n     */\n    const defaultOptions: Partial<ReactViteSiteProjectOptions> = {\n      testRunner: TestRunner.VITEST,\n      apiExtractor: false,\n      // ESLint inherited from TypeScriptProject lints `src` only. projen 0.100\n      // removed the `lintProjenRc` option and no longer auto-lints the projenrc\n      // file, so the previous explicit opt-out is unnecessary — downstream\n      // sites configure projen through their own root project.\n      eslintOptions: {\n        dirs: [\"src\"],\n      },\n      // VSCode workspace defaults (Prettier formatter, ESLint on save)\n      // need a project-level `.vscode/` folder. The inherited\n      // TypeScriptProject does not enable it on sub-projects by\n      // default; flip it on so the React-site VSCode wiring below\n      // actually renders.\n      vscode: true,\n      tsconfig: {\n        compilerOptions: {\n          declaration: false,\n        },\n      },\n    };\n    const merged = merge(\n      defaultOptions,\n      userOptions,\n    ) as ReactViteSiteProjectOptions;\n    const options: ReactViteSiteProjectOptions = {\n      ...merged,\n      outdir: resolvedOutdir,\n    };\n\n    super(options);\n\n    /**\n     * Vite + Tailwind v4 ships as ESM; the site package must be a module.\n     */\n    this.package.addField(\"type\", \"module\");\n\n    /**\n     * Pin the Node.js version for local development. Mirrors the\n     * `.nvmrc` the monorepo root carries — keeps a fresh checkout's\n     * locally installed Node matched to whatever projen synthesises\n     * against in CI.\n     */\n    new TextFile(this, \".nvmrc\", { lines: [\"v24.11.0\"] });\n\n    /**\n     * Vite-friendly TypeScript config. The inherited TypeScriptProject\n     * config is tuned for library output (`declaration: true`, `outDir`,\n     * `rootDir`) which conflicts with Vite's bundler-mode resolution.\n     * Override the projen-managed `tsconfig.json` in place — addOverride\n     * replaces values cleanly without fighting projen's file registry.\n     */\n    this.tsconfig?.file.addOverride(\"compilerOptions.target\", \"ES2020\");\n    this.tsconfig?.file.addOverride(\"compilerOptions.lib\", [\n      \"ES2020\",\n      \"DOM\",\n      \"DOM.Iterable\",\n    ]);\n    this.tsconfig?.file.addOverride(\"compilerOptions.module\", \"ESNext\");\n    this.tsconfig?.file.addOverride(\n      \"compilerOptions.moduleResolution\",\n      \"bundler\",\n    );\n    this.tsconfig?.file.addOverride(\"compilerOptions.jsx\", \"react-jsxdev\");\n    this.tsconfig?.file.addOverride(\"compilerOptions.noEmit\", true);\n    this.tsconfig?.file.addOverride(\"compilerOptions.skipLibCheck\", true);\n    this.tsconfig?.file.addOverride(\"compilerOptions.strict\", true);\n    this.tsconfig?.file.addOverride(\n      \"compilerOptions.noUncheckedIndexedAccess\",\n      true,\n    );\n    this.tsconfig?.file.addOverride(\"compilerOptions.noImplicitOverride\", true);\n    this.tsconfig?.file.addOverride(\n      \"compilerOptions.exactOptionalPropertyTypes\",\n      true,\n    );\n    this.tsconfig?.file.addOverride(\"compilerOptions.resolveJsonModule\", true);\n    this.tsconfig?.file.addOverride(\"compilerOptions.declaration\", false);\n    this.tsconfig?.file.addOverride(\"compilerOptions.paths\", {\n      \"@/*\": [\"./src/*\"],\n    });\n    this.tsconfig?.file.addOverride(\"include\", [\"src\"]);\n\n    /**\n     * Pull the vitest/vite type roots into the main tsconfig. projen\n     * 0.100.4+'s typescript-eslint project service resolves co-located\n     * `src/**` `.tsx` test files to this config (not the test-dir\n     * tsconfig), so the test-runner globals must live here for ESLint to\n     * type-check them cleanly. `include: [\"src\"]` above already covers\n     * those files (TypeScriptProject no longer excludes test files).\n     */\n    this.tsconfig?.file.addOverride(\"compilerOptions.types\", [\n      \"vitest/globals\",\n      \"vite/client\",\n    ]);\n\n    /**\n     * Vite config: Tailwind v4 plugin loaded before React (matches the\n     * canonical example in Tailwind's docs) and an `@/*` path alias\n     * pointed at `./src`.\n     */\n    new SampleFile(this, \"vite.config.ts\", {\n      contents: `import { defineConfig } from 'vite';\nimport react from '@vitejs/plugin-react';\nimport tailwindcss from '@tailwindcss/vite';\nimport path from 'path';\n\nexport default defineConfig({\n  plugins: [tailwindcss(), react()],\n  resolve: { alias: { '@': path.resolve(__dirname, 'src') } },\n});\n`,\n    });\n\n    /**\n     * `src/vite-env.d.ts` — typed `ImportMetaEnv` stub so sites have a\n     * declared home for their `VITE_*` env vars and `import.meta.env`\n     * accesses type-check. Emitted unconditionally via `SampleFile` so\n     * sites without `sampleCode: true` still get the template; the\n     * write-once semantics protect any edits a downstream site has\n     * already made.\n     */\n    new SampleFile(this, \"src/vite-env.d.ts\", {\n      contents: `/// <reference types=\"vite/client\" />\n\ninterface ImportMetaEnv {\n  // Declare your VITE_* env vars here, e.g.\n  // readonly VITE_API_BASE_URL: string;\n}\n\ninterface ImportMeta {\n  readonly env: ImportMetaEnv;\n}\n`,\n    });\n\n    /**\n     * Vitest config: extends Vite config so plugins (React, Tailwind)\n     * apply during tests, and sets jsdom + globals + Testing Library\n     * setup file. The inherited TypeScriptProject's `Vitest` component\n     * already emitted a baseline `vitest.config.ts` from `super()`; we\n     * remove it and write our own so Vite plugins propagate into the\n     * test environment. Skipped when the caller selected Jest — in\n     * that case the project has no Vitest config at all and the file\n     * stays absent.\n     */\n    if (options.testRunner !== TestRunner.JEST) {\n      this.tryRemoveFile(\"vitest.config.ts\");\n      new SampleFile(this, \"vitest.config.ts\", {\n        contents: `import { defineConfig, mergeConfig } from 'vitest/config';\nimport react from '@vitejs/plugin-react';\nimport viteConfig from './vite.config';\n\nexport default mergeConfig(\n  viteConfig,\n  defineConfig({\n    plugins: [react()],\n    test: {\n      environment: 'jsdom',\n      globals: true,\n      setupFiles: ['./src/setupTests.ts'],\n      passWithNoTests: true,\n    },\n  })\n);\n`,\n      });\n    }\n\n    /**\n     * Replace projen's tsc-driven compile with `vite build`. Sites are\n     * not npm tarballs — neutralise `package` too so the inherited\n     * `build` task doesn't emit `dist/js/*.tgz` alongside the site\n     * output.\n     */\n    this.compileTask.reset();\n    this.compileTask.exec(\"vite build\");\n    this.packageTask.reset();\n\n    /**\n     * Point `watch` at Vite's dev server (projen's default runs `tsc -w`,\n     * which is meaningless for a Vite site).\n     */\n    this.tasks.tryFind(\"watch\")?.reset(\"vite\");\n\n    /**\n     * Vite / Vitest lifecycle tasks. Add only the ones projen does not\n     * already provide.\n     */\n    if (!this.tasks.tryFind(\"dev\")) {\n      this.addTask(\"dev\", {\n        description: \"Start the Vite dev server\",\n        exec: \"vite\",\n        receiveArgs: true,\n      });\n    }\n    if (!this.tasks.tryFind(\"preview\")) {\n      this.addTask(\"preview\", {\n        description: \"Preview the built site locally\",\n        exec: \"vite preview\",\n        receiveArgs: true,\n      });\n    }\n\n    /**\n     * Runtime React + router deps.\n     */\n    this.addDeps(\"react\", \"react-dom\", \"react-router-dom\");\n\n    /**\n     * Dev deps: Vite + Tailwind plugin, Vitest + Testing Library,\n     * React type defs, and ESLint plugins for React.\n     */\n    this.addDevDeps(\n      \"vite\",\n      \"@vitejs/plugin-react\",\n      \"@tailwindcss/vite\",\n      \"tailwindcss\",\n      \"jsdom\",\n      \"@testing-library/react\",\n      \"@testing-library/jest-dom\",\n      \"@testing-library/user-event\",\n      \"@types/react\",\n      \"@types/react-dom\",\n      \"eslint-plugin-react\",\n      \"eslint-plugin-react-hooks\",\n      \"eslint-plugin-jsx-a11y\",\n    );\n\n    /**\n     * Wire ESLint to lint React JSX. The base TypeScriptProject already\n     * enables `eslint`; we layer on the React plugins / configs and the\n     * settings to detect the installed React version automatically.\n     */\n    this.eslint?.addExtends(\"plugin:react/recommended\");\n    this.eslint?.addExtends(\"plugin:react/jsx-runtime\");\n    this.eslint?.addExtends(\"plugin:react-hooks/recommended\");\n    this.eslint?.addExtends(\"plugin:jsx-a11y/recommended\");\n    this.eslint?.addOverride({\n      files: [\"**/*.{tsx,jsx}\"],\n      // Projen's ESLint override type does not include `settings`, but\n      // `settings` is a valid ESLint override key. Cast to `any` so the\n      // generated `.eslintrc.json` carries the React-version detection\n      // settings on the JSX glob.\n      settings: {\n        react: {\n          version: \"detect\",\n        },\n      },\n    } as any);\n    this.eslint?.addRules({\n      // We use TypeScript; prop-types are unnecessary.\n      \"react/prop-types\": \"off\",\n      // New JSX transform — React no longer needs to be in scope.\n      \"react/react-in-jsx-scope\": \"off\",\n    });\n\n    /**\n     * Test files import dev-only assertion helpers (e.g.\n     * `@testing-library/jest-dom`). Loosen\n     * `import/no-extraneous-dependencies` for tests and the Vitest\n     * setup file so ESLint does not flag them.\n     */\n    this.eslint?.addOverride({\n      files: [\n        \"**/*.{test,spec}.ts\",\n        \"**/*.{test,spec}.tsx\",\n        \"**/__tests__/**\",\n        \"src/setupTests.ts\",\n      ],\n      rules: {\n        \"import/no-extraneous-dependencies\": [\n          \"error\",\n          { devDependencies: true },\n        ],\n      },\n    });\n\n    /**\n     * VSCode workspace defaults — Prettier as the default formatter,\n     * ESLint + organizeImports on save for TS/TSX/JS/JSX, and\n     * recommended extensions.\n     */\n    this.vscode?.settings.addSettings({\n      \"editor.defaultFormatter\": \"esbenp.prettier-vscode\",\n      \"editor.formatOnSave\": true,\n      // Prettier must format the whole file; \"modifications\" mode is\n      // known to mis-merge ranges with Prettier and can corrupt saves.\n      \"editor.formatOnSaveMode\": \"file\",\n      \"prettier.requireConfig\": true,\n\n      \"eslint.useFlatConfig\": false,\n      \"eslint.workingDirectories\": [{ directory: \".\", changeProcessCWD: true }],\n      // Prettier is the default formatter; ESLint's fixAll must not\n      // re-apply prettier/prettier (would double-format).\n      \"eslint.codeActionsOnSave.rules\": [\"!prettier/prettier\", \"*\"],\n      \"eslint.format.enable\": false,\n\n      \"[typescript]\": {\n        \"editor.codeActionsOnSave\": {\n          \"source.fixAll.eslint\": \"always\",\n          \"source.organizeImports\": \"always\",\n        },\n      },\n      \"[typescriptreact]\": {\n        \"editor.codeActionsOnSave\": {\n          \"source.fixAll.eslint\": \"always\",\n          \"source.organizeImports\": \"always\",\n        },\n      },\n      \"[javascript]\": {\n        \"editor.codeActionsOnSave\": {\n          \"source.fixAll.eslint\": \"always\",\n        },\n      },\n      \"[javascriptreact]\": {\n        \"editor.codeActionsOnSave\": {\n          \"source.fixAll.eslint\": \"always\",\n        },\n      },\n\n      \"eslint.validate\": [\n        \"javascript\",\n        \"javascriptreact\",\n        \"typescript\",\n        \"typescriptreact\",\n      ],\n    });\n\n    this.vscode?.extensions.addRecommendations(\"dbaeumer.vscode-eslint\");\n    this.vscode?.extensions.addRecommendations(\"esbenp.prettier-vscode\");\n\n    /**\n     * Extend turbo inputs so the compile task invalidates on Vite-\n     * specific source paths. Outputs (`dist/**`) are already added by\n     * the base class.\n     */\n    const turbo = TurboRepo.of(this);\n    if (turbo?.compileTask) {\n      turbo.compileTask.inputs.push(\n        \"public/**\",\n        \"index.html\",\n        \"vite.config.ts\",\n      );\n    }\n\n    /**\n     * Optional starter files. Matches the\n     * `createBaseReactSite` reference shape — minimal but runnable.\n     */\n    if (userOptions.sampleCode === true) {\n      const siteName = options.name;\n      new SampleFile(this, \"index.html\", {\n        contents: `<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"/>\n    <title>${siteName}</title>\n  </head>\n  <body>\n    <div id=\"root\"></div>\n    <script type=\"module\" src=\"/src/main.tsx\"></script>\n  </body>\n</html>\n`,\n      });\n      new SampleFile(this, \"src/routes.tsx\", {\n        contents: `import { createBrowserRouter } from 'react-router-dom';\nimport App from './App';\n\nexport const router = createBrowserRouter([\n  { path: '/', element: <App /> },\n]);\n`,\n      });\n      new SampleFile(this, \"src/main.tsx\", {\n        contents: `import React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport { RouterProvider } from 'react-router-dom';\nimport { router } from './routes';\nimport './index.css';\n\nReactDOM.createRoot(document.getElementById('root')!).render(\n  <React.StrictMode>\n    <RouterProvider router={router} />\n  </React.StrictMode>\n);\n`,\n      });\n      new SampleFile(this, \"src/App.tsx\", {\n        contents: `export default function App() {\n  return (\n    <main className=\"p-4\">\n      <h1 className=\"text-2xl font-bold\">Hello from ${siteName}</h1>\n    </main>\n  );\n}\n`,\n      });\n      new SampleFile(this, \"src/index.css\", {\n        contents: `@import \"tailwindcss\";\n`,\n      });\n      new SampleFile(this, \"src/setupTests.ts\", {\n        contents: `import '@testing-library/jest-dom';\n`,\n      });\n    }\n  }\n}\n","import { SampleFile } from \"projen\";\nimport { AstroProject, AstroProjectOptions } from \"./astro-project\";\nimport { MONOREPO_LAYOUT } from \"./monorepo-layout\";\nimport { AstroIntegrationSpec } from \"../astro/astro-config-options\";\nimport { TurboRepo } from \"../turbo\";\nimport { VERSION } from \"../versions\";\n\n/**\n * Role a {@link StarlightProject} plays inside the monorepo (ADR-006).\n *\n * - `\"docs\"` — the monorepo-wide Starlight docs site. Singleton: at most one\n *   docs-role project may exist per `MonorepoProject`. Defaults `outdir` to\n *   `docs/`.\n * - `\"site\"` — a user-facing Starlight site deployed from `sites/`. Behaves\n *   like a regular {@link AstroProject} for placement: defaults `outdir` to\n *   `sites/<scope>/<name>`.\n */\nexport const STARLIGHT_ROLE = {\n  DOCS: \"docs\",\n  SITE: \"site\",\n} as const;\n\nexport type StarlightRole =\n  (typeof STARLIGHT_ROLE)[keyof typeof STARLIGHT_ROLE];\n\n/**\n * A single Starlight social icon link.\n */\nexport interface StarlightSocialLink {\n  readonly icon: string;\n  readonly label: string;\n  readonly href: string;\n}\n\n/**\n * Starlight logo configuration.\n */\nexport interface StarlightLogo {\n  readonly src: string;\n  readonly alt?: string;\n}\n\n/**\n * Starlight edit-link configuration.\n */\nexport interface StarlightEditLink {\n  readonly baseUrl: string;\n}\n\n/**\n * Sidebar item accepted by Starlight's `sidebar` config.\n *\n * Covers the shapes Starlight 0.39+ accepts:\n * - link (`{ label, link, badge? }`)\n * - group with nested items (`{ label, collapsed?, items }`)\n * - bare autogenerated entry, nested inside a group's `items` array\n *   (`{ autogenerate: { directory, collapsed? } }`)\n * - internal slug reference (`{ label, slug }`)\n *\n * Plus one legacy shape kept for one deprecation cycle:\n * - top-level autogenerated group (`{ label, collapsed?, autogenerate }`).\n *   Starlight v0.39.0 removed runtime support for this shape; the\n *   `StarlightProject` emitter translates it to the nested form\n *   `{ label, collapsed?, items: [{ autogenerate }] }` before writing\n *   `astro.config.mjs`. Migrate to the nested form directly — this\n *   variant will be removed in a future release.\n */\nexport type StarlightSidebarItem =\n  | {\n      readonly label: string;\n      readonly link: string;\n      readonly badge?:\n        string | { readonly text: string; readonly variant?: string };\n    }\n  | {\n      readonly label: string;\n      readonly collapsed?: boolean;\n      readonly items: ReadonlyArray<StarlightSidebarItem>;\n    }\n  | {\n      readonly autogenerate: {\n        readonly directory: string;\n        readonly collapsed?: boolean;\n      };\n    }\n  | {\n      /** @deprecated Use `{ label, items: [{ autogenerate }] }` instead. Translated by the emitter for one cycle. */\n      readonly label: string;\n      readonly collapsed?: boolean;\n      readonly autogenerate: {\n        readonly directory: string;\n        readonly collapsed?: boolean;\n      };\n    }\n  | { readonly label: string; readonly slug: string };\n\n/**\n * Configuration options for StarlightProject.\n */\nexport interface StarlightProjectOptions extends AstroProjectOptions {\n  /**\n   * Starlight site title (required).\n   */\n  readonly starlightTitle: string;\n\n  /**\n   * Role this Starlight project plays in the monorepo (ADR-006).\n   *\n   * - `\"docs\"` (default) — the monorepo-wide docs singleton. `outdir`\n   *   defaults to `docs/`. Only one docs-role `StarlightProject` may\n   *   exist per `MonorepoProject`; a second one fails synth.\n   * - `\"site\"` — a regular user-facing Starlight site. `outdir`\n   *   defaults to `sites/<scope>/<name>` (same rule as\n   *   `AstroProject`). Multiple site-role projects are allowed.\n   *\n   * @default \"docs\"\n   */\n  readonly role?: StarlightRole;\n\n  /**\n   * Starlight site description.\n   */\n  readonly starlightDescription?: string;\n\n  /**\n   * Social links rendered in the Starlight header.\n   */\n  readonly social?: ReadonlyArray<StarlightSocialLink>;\n\n  /**\n   * Sidebar config (passed through verbatim). When omitted, Starlight\n   * autogenerates the sidebar from the `src/content/docs/` tree.\n   */\n  readonly sidebar?: ReadonlyArray<StarlightSidebarItem>;\n\n  /**\n   * Custom CSS files loaded by Starlight.\n   */\n  readonly customCss?: ReadonlyArray<string>;\n\n  /**\n   * Site logo displayed in the Starlight header.\n   */\n  readonly logo?: StarlightLogo;\n\n  /**\n   * \"Edit this page\" link configuration.\n   */\n  readonly editLink?: StarlightEditLink;\n\n  /**\n   * `@astrojs/starlight` package version.\n   *\n   * @default VERSION.STARLIGHT_VERSION\n   */\n  readonly starlightVersion?: string;\n\n  /**\n   * sharp package version (required peer for Starlight's image pipeline).\n   *\n   * @default VERSION.SHARP_VERSION\n   */\n  readonly sharpVersion?: string;\n\n  /**\n   * Emit the sample Starlight landing page (`src/content/docs/index.mdx`).\n   *\n   * Does not gate `src/content.config.ts` — that file declares the `docs`\n   * collection and is always emitted, since Starlight's content layer is\n   * non-functional without it.\n   *\n   * @default false\n   */\n  readonly sampleContent?: boolean;\n}\n\n/**\n * Docs site scaffolded on top of {@link AstroProject} using the\n * Starlight Astro integration.\n */\nexport class StarlightProject extends AstroProject {\n  /**\n   * Role this Starlight project plays in the monorepo (ADR-006).\n   *\n   * - `\"docs\"` — monorepo-wide docs singleton at `/docs`.\n   * - `\"site\"` — user-facing Starlight site under `sites/<scope>/<name>`.\n   */\n  public readonly role: StarlightRole;\n\n  constructor(userOptions: StarlightProjectOptions) {\n    const role: StarlightRole = userOptions.role ?? STARLIGHT_ROLE.DOCS;\n\n    const starlightConfig = buildStarlightConfig(userOptions);\n    const starlightSpec: AstroIntegrationSpec = {\n      name: \"starlight\",\n      importPath: \"@astrojs/starlight\",\n      defaultImport: true,\n      args: JSON.stringify(starlightConfig, null, 2),\n    };\n\n    /*************************************************************************\n     *\n     * Resolve outdir\n     *\n     * Docs-role projects default to `docs/` (ADR-006 docs singleton).\n     * Site-role projects fall through to `AstroProject`'s own default —\n     * `sites/<scope>/<name>` — so we leave `outdir` undefined for them\n     * and let AstroProject resolve it from the scoped package name.\n     *\n     ************************************************************************/\n\n    const resolvedOutdir =\n      userOptions.outdir ??\n      (role === STARLIGHT_ROLE.DOCS ? MONOREPO_LAYOUT.DOCS : undefined);\n\n    /**\n     * Prepend the Starlight integration so it appears first in the\n     * rendered `integrations` array (matches Starlight docs convention).\n     */\n    /**\n     * Exclude Starlight and sharp from projen's per-package ncu upgrade\n     * workflow — same pattern AstroProject uses for `astro` — so\n     * VERSION.STARLIGHT_VERSION / VERSION.SHARP_VERSION remain the single\n     * source of truth.\n     */\n    const mergedOptions: AstroProjectOptions = {\n      ...userOptions,\n      outdir: resolvedOutdir,\n      integrations: [starlightSpec, ...(userOptions.integrations ?? [])],\n      depsUpgradeOptions: {\n        ...userOptions.depsUpgradeOptions,\n        exclude: [\n          ...(userOptions.depsUpgradeOptions?.exclude ?? []),\n          \"@astrojs/starlight\",\n          \"sharp\",\n        ],\n      },\n    };\n\n    super(mergedOptions);\n\n    this.role = role;\n\n    const starlightVersion =\n      userOptions.starlightVersion ?? VERSION.STARLIGHT_VERSION;\n    const sharpVersion = userOptions.sharpVersion ?? VERSION.SHARP_VERSION;\n\n    this.addDeps(\n      `@astrojs/starlight@${starlightVersion}`,\n      `sharp@${sharpVersion}`,\n    );\n\n    /**\n     * Extend turbo compile inputs with Starlight's content collection tree.\n     */\n    const turbo = TurboRepo.of(this);\n    if (turbo?.compileTask) {\n      turbo.compileTask.inputs.push(\"src/content/**\");\n    }\n\n    /**\n     * Required content config. Starlight's content layer resolves every page\n     * through the `docs` collection declared here, so a site without this file\n     * builds only `404.html` — a warning, never an error. Emitted\n     * unconditionally, and as a `SampleFile` (write-if-missing) because the\n     * config is user-space: consumers extend the schema or add collections and\n     * must never have those edits overwritten on regen.\n     */\n    new SampleFile(this, \"src/content.config.ts\", {\n      contents: DEFAULT_CONTENT_CONFIG_TS,\n    });\n\n    /**\n     * Optional sample landing page.\n     */\n    if (userOptions.sampleContent === true) {\n      new SampleFile(this, \"src/content/docs/index.mdx\", {\n        contents: DEFAULT_INDEX_MDX,\n      });\n    }\n  }\n}\n\n/**\n * Build the JSON-serializable Starlight config object from user options.\n */\nfunction buildStarlightConfig(\n  options: StarlightProjectOptions,\n): Record<string, unknown> {\n  const config: Record<string, unknown> = {\n    title: options.starlightTitle,\n  };\n  if (options.starlightDescription !== undefined) {\n    config.description = options.starlightDescription;\n  }\n  if (options.social !== undefined) {\n    config.social = options.social;\n  }\n  if (options.sidebar !== undefined) {\n    config.sidebar = options.sidebar.map(translateSidebarItem);\n  }\n  if (options.customCss !== undefined) {\n    config.customCss = options.customCss;\n  }\n  if (options.logo !== undefined) {\n    config.logo = options.logo;\n  }\n  if (options.editLink !== undefined) {\n    config.editLink = options.editLink;\n  }\n  return config;\n}\n\n/**\n * Translate a single sidebar item from the legacy top-level\n * `{ label, collapsed?, autogenerate }` shape to the Starlight 0.39+\n * nested form `{ label, collapsed?, items: [{ autogenerate }] }`.\n *\n * Recurses through any `items` array so nested groups are translated\n * at any depth. Items that are not in the legacy shape are returned\n * unchanged (apart from a recursive walk of their `items`, when present).\n */\nfunction translateSidebarItem(item: StarlightSidebarItem): unknown {\n  if (item === null || typeof item !== \"object\") {\n    return item;\n  }\n\n  const record = item as Record<string, unknown>;\n\n  /**\n   * Legacy shape: a group with both a top-level `label` and a top-level\n   * `autogenerate` field. Rewrite to the nested-items form.\n   */\n  if (\n    typeof record.label === \"string\" &&\n    record.autogenerate !== undefined &&\n    record.items === undefined\n  ) {\n    const translated: Record<string, unknown> = {\n      label: record.label,\n      items: [{ autogenerate: record.autogenerate }],\n    };\n    if (record.collapsed !== undefined) {\n      translated.collapsed = record.collapsed;\n    }\n    return translated;\n  }\n\n  /**\n   * Group with nested `items` — recurse so legacy shapes nested inside\n   * a parent group are also translated.\n   */\n  if (Array.isArray(record.items)) {\n    return {\n      ...record,\n      items: (record.items as ReadonlyArray<StarlightSidebarItem>).map(\n        translateSidebarItem,\n      ),\n    };\n  }\n\n  return item;\n}\n\nconst DEFAULT_INDEX_MDX = `---\ntitle: Welcome\ndescription: Starlight-powered documentation site.\n---\n\n# Hello, Starlight!\n\nEdit \\`src/content/docs/index.mdx\\` to replace this page.\n`;\n\nconst DEFAULT_CONTENT_CONFIG_TS = `import { defineCollection } from \"astro:content\";\nimport { docsLoader } from \"@astrojs/starlight/loaders\";\nimport { docsSchema } from \"@astrojs/starlight/schema\";\n\nexport const collections = {\n  docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),\n};\n`;\n"],"mappings":"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ACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG,+BAA+B;AAAA,IAClC;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG,yBAAyB;AAAA,IAC5B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;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AAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;A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;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,iBAAiB,GAAG,gBAAgB;AAAA,IACpC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc,GAAG,gBAAgB;AAAA,IACjC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO,GAAG,qBAAqB,WAAW,sBAAsB,QAAQ;AAAA,IACxE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;AAYO,SAAS,8BACd,IACA,aACQ;AACR,MAAI,CAAC,GAAG,SAAS;AACf,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,SAAS,WAAW;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAmBO,SAAS,gCACd,KACQ;AACR,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,I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IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEA,IAAM,iBAA6B;AAAA,EACjC,MAAM;AAAA,EACN,aACE;AAAA,EACF,wBAAwB;AAAA,EACxB,cAAc;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEA,IAAM,kBAA8B;AAAA,EAClC,MAAM;AAAA,EACN,aACE;AAAA,EACF,wBAAwB;AAAA,EACxB,cAAc;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEA,IAAM,kBAA8B;AAAA,EAClC,MAAM;AAAA,EACN,aACE;AAAA,EACF,wBAAwB;AAAA,EACxB,cAAc;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAkCO,IAAM,2BAAoD;AAAA,EAC/D,eAAe,qBAAqB;AAAA,EACpC,eAAe,qBAAqB;AAAA,EACpC,iBAAiB,uBAAuB;AAAA,EACxC,YAAY,kBAAkB;AAAA,EAC9B,gBAAgB,sBAAsB;AAAA,EACtC,+BAA+B;AACjC;AAMO,SAAS,gBACd,QAA4B,qBAC5B,cAAuC,0BACtB;AACjB,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;AAAA,IACF,aAAa,MAAM;AAAA,IACnB,QAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,OAAO;AAAA,MACL;AAAA,QACE,MAAM;AAAA,QACN,aAAa;AAAA,QACb,OAAO,iBAAiB;AAAA,QACxB,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,EAAE,KAAK,IAAI;AAAA,QACX,MAAM,CAAC,SAAS;AAAA,MAClB;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,aACE;AAAA,QACF,OAAO,iBAAiB;AAAA,QACxB,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,EAAE,KAAK,IAAI;AAAA,QACX,WAAW;AAAA,UACT,QAAQ,EAAE,SAAS,KAAK;AAAA,QAC1B;AAAA,QACA,MAAM,CAAC,SAAS;AAAA,MAClB;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,aACE;AAAA,QACF,OAAO,iBAAiB;AAAA,QACxB,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,EAAE,KAAK,IAAI;AAAA,QACX,MAAM,CAAC,SAAS;AAAA,MAClB;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,aACE;AAAA,QACF,OAAO,iBAAiB;AAAA,QACxB,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,EAAE,KAAK,IAAI;AAAA,QACX,MAAM,CAAC,SAAS;AAAA,MAClB;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,aACE;AAAA,QACF,OAAO,iBAAiB;AAAA,QACxB,cAAc,CAAC,WAAW,UAAU;AAAA,QACpC,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,EAAE,KAAK,IAAI;AAAA,QACX,MAAM,CAAC,QAAQ;AAAA,MACjB;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,aACE;AAAA,QACF,OAAO,iBAAiB;AAAA,QACxB,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,EAAE,KAAK,IAAI;AAAA,QACX,MAAM,CAAC,UAAU;AAAA,MACnB;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,aACE;AAAA,QACF,OAAO,iBAAiB;AAAA,QACxB,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,EAAE,KAAK,IAAI;AAAA,QACX,MAAM,CAAC,UAAU;AAAA,MACnB;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,aACE;AAAA,QACF,OAAO,iBAAiB;AAAA,QACxB,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,EAAE,KAAK,IAAI;AAAA,QACX,MAAM,CAAC,UAAU;AAAA,MACnB;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,aACE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAOF,OAAO,iBAAiB;AAAA,QACxB,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,EAAE,KAAK,IAAI;AAAA,QACX,MAAM,CAAC,UAAU;AAAA,MACnB;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,aACE;AAAA,QACF,OAAO,iBAAiB;AAAA,QACxB,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,sCAAsC,MAAM,QAAQ;AAAA,UACpD;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,EAAE,KAAK,IAAI;AAAA,QACX,MAAM,CAAC,SAAS;AAAA,MAClB;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,aACE;AAAA,QACF,OAAO,iBAAiB;AAAA,QACxB,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA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AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AClDA,SAAS,uBACP,OACA,eACe;AACf,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;AAAA,IACF,OAAO,YAAY;AAAA,IACnB,UAAU;AAAA,IACV,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,IACvC,QAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,uCAAuC,MAAM,QAAQ;AAAA,MACrD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,M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A;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,0BAA0B;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,6CAA6C,MAAM,QAAQ;AAAA,MAC3D;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,0BAA0B;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,oCAAoC,MAAM,QAAQ;AAAA,MAClD;AAAA,M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ACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,2NAA2N,MAAM,QAAQ;AAAA,MACzO;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ,MAAM,QAAQ;AAAA,MACtB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,kDAA6C,yBAAyB;AAAA,MACtE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,+BAA+B;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,yBAAyB;AAAA,MAC5B;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,8BAA8B;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,0BAA0B;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,0BAA0B;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,oCAAoC,0BAA0B;AAAA,MAC9D;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AACF;AAGA,SAAS,6BACP,OACA,eACY;AACZ,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;A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ACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACF;AAQO,IAAM,uBACX,0BAA0B;;;AC5kC5B,SAAS,mCACP,OACA,eACA,MACe;AACf,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;AAAA,IACF,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,IACvC,QAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,+DAA+D,MAAM,aAAa;AAAA,MAClF;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,wGAAwG,MAAM,QAAQ;AAAA,MACtH,mHAAmH,MAAM,UAAU;AAAA,MACnI,uHAAuH,MAAM,YAAY;AAAA,MACzI;AAAA,MACA,QAAQ,MAAM,QAAQ;AAAA,MACtB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,MAAM,QAAQ;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,kDAA6C,yBAAyB;AAAA,MACtE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,+BAA+B;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,yBAAyB;AAAA,MAC5B;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,8BAA8B;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,0BAA0B;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,0BAA0B;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,mBAAmB,eAAe,eAAe,iBAAiB,EAAE,QAAQ;AAAA,MAC5E,iBAAiB,eAAe,eAAe,iBAAiB,EAAE,MAAM;AAAA,MACxE;AAAA,MACA,GAAG,8BAA8B;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,mBAAmB,eAAe,eAAe,mBAAmB,EAAE,QAAQ;AAAA,MAC9E,iBAAiB,eAAe,eAAe,mBAAmB,EAAE,MAAM;AAAA,MAC1E;AAAA,MACA,GAAG,8BAA8B;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,qBAAqB,0BAA0B;AAAA,MAC/C;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,0CAA0C,MAAM,QAAQ;AAAA,MACxD;AAAA,MACA;AAAA,MACA,8CAA8C,0BAA0B;AAAA,MACxE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,0BAA0B;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,0BAA0B;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,0BAA0B;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA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,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,0BAA0B,MAAM,QAAQ;AAAA,MACxC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;A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AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAQO,IAAM,sBAAsC;AAAA,EACjD,MAAM;AAAA,EACN,aACE;AAAA,EACF,SAAS,0BAA0B;AACrC;AAyBO,SAAS,4BAAoC;AAClD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAUO,IAAM,sBAAsC;AAAA,EACjD,MAAM;AAAA,EACN,aACE;AAAA,EACF,SAAS,0BAA0B;AACrC;AAiCO,SAAS,uCAA+C;AAC7D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAUO,IAAM,iCAAiD;AAAA,EAC5D,MAAM;AAAA,EACN,aACE;AAAA,EACF,SAAS,qCAAqC;AAChD;AAoBO,SAAS,iCAAyC;AAKvD,QAAM,aAAa;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACX,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,4CACE,WAAW,QAAQ,MAAM,KAAK,IAC9B;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAaO,IAAM,2BAA2C;AAAA,EACtD,MAAM;AAAA,EACN,aACE;AAAA,EACF,SAAS,+BAA+B;AAC1C;AAmBO,SAAS,oBACd,QAA4B,qBACX;AACjB,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;AAAA,IACF,aAAa,MAAM;AAAA,IACnB,OAAO;AAAA,MACL;AAAA,QACE,MAAM;AAAA,QACN,aACE;AAAA,QACF,OAAO,iBAAiB;AAAA,QACxB,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,EAAE,KAAK,IAAI;AAAA,QACX,WAAW;AAAA,UACT,QAAQ,EAAE,SAAS,KAAK;AAAA,QAC1B;AAAA,QACA,MAAM,CAAC,UAAU;AAAA,MACnB;AAAA,IACF;AAAA,IACA,QAAQ,CAAC,qBAAqB,GAAG,wBAAwB,CAAC;AAAA,IAC1D,WAAW,CAAC,sBAAsB,KAAK,CAAC;AAAA,IACxC,YAAY;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,QAAQ;AAAA,MACN;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACF;AAQO,IAAM,iBAAkC,oBAAoB;;;ACprCnE,SAAS,cAAc;;;AC+BhB,SAAS,mCAA2C;AACzD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAMO,IAAM,gCAAgD;AAAA,EAC3D,MAAM;AAAA,EACN,aACE;AAAA,EACF,SAAS,iCAAiC;AAC5C;;;AD9RA,IAAM,wBAAwC;AAAA,EAC5C,MAAM;AAAA,EACN,aACE;AAAA,EACF,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAmBA,IAAM,+BAA+C;AAAA,EACnD,MAAM;AAAA,EACN,aACE;AAAA,EACF,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;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A,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,0BAA0B;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,0CAA0C,MAAM,QAAQ;AAAA,MACxD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,0BAA0B;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,gEAAgE,eAAe,eAAe,gBAAgB,EAAE,QAAQ;AAAA,MACxH,iBAAiB,eAAe,eAAe,gBAAgB,EAAE,MAAM;AAAA,MACvE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,8BAA8B,EAAE,QAAQ,OAAO,QAAQ,KAAK,CAAC;AAAA,MAChE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,0BAA0B;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AACF;AAGA,SAAS,6BACP,OACA,eACY;AACZ,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;AAAA,IACF,wBAAwB;AAAA,IACxB,eAAe;AAAA,IACf,SAAS;AAAA,IACT,OAAO;AAAA,IACP,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,IACvC,cAAc;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,MAAM,QAAQ;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,uCAAuC,MAAM,QAAQ;AAAA,MACrD;AAAA,MACA;AAAA,MACA,OAAO,MAAM,cAAc;AAAA,MAC3B,OAAO,MAAM,cAAc;AAAA,MAC3B,OAAO,MAAM,cAAc;AAAA,MAC3B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,iBAAiB,eAAe,eAAe,mBAAmB,EAAE,QAAQ,oBAAoB,eAAe,eAAe,mBAAmB,EAAE,MAAM;AAAA,MACzJ;AAAA,MACA;AAAA,MACA,GAAG,8BAA8B;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AACF;AAUO,SAAS,6BACd,QAA4B,qBAC5B,gBAAuC,iCACtB;AACjB,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;AAAA,IACF,aAAa,MAAM;AAAA,IACnB,OAAO;AAAA,MACL;AAAA,QACE,MAAM;AAAA,QACN,aACE;AAAA,QACF,OAAO,iBAAiB;AAAA,QACxB,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,EAAE,KAAK,IAAI;AAAA,QACX,WAAW;AAAA,UACT,QAAQ,EAAE,SAAS,KAAK;AAAA,QAC1B;AAAA,QACA,MAAM,CAAC,UAAU;AAAA,MACnB;AAAA,IACF;AAAA,IACA,QAAQ,CAAC,6BAA6B,OAAO,aAAa,CAAC;AAAA,IAC3D,WAAW,CAAC,sCAAsC,OAAO,aAAa,CAAC;AAAA,IACvE,QAAQ;AAAA,MACN;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACF;AAQO,IAAM,0BACX,6BAA6B;;;ACnlBxB,IAAM,aAA8B;AAAA,EACzC,MAAM;AAAA,EACN,aAAa;AAAA,EACb,aAAa,CAAC,YAAqB,OAAO,SAAS,MAAM;AAAA,EACzD,wBAAwB,CAAC,YACvB,oBAAoB,SAAS,MAAM;AAAA,EACrC,OAAO;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,aAAa;AAAA,MACb,OAAO,iBAAiB;AAAA,MACxB,cAAc,CAAC,gBAAgB,cAAc;AAAA,MAC7C,SAAS;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,IAAI;AAAA,MACX,MAAM,CAAC,SAAS;AAAA,IAClB;AAAA,EACF;AAAA,EACA,mBAAmB;AAAA,IACjB,OAAO,CAAC,kBAAkB;AAAA,EAC5B;AACF;;;AC3BA,SAAS,8BACP,OACA,MACe;AACf,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;AAAA,IACF,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,IACvC,QAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,8DAA8D,MAAM,gBAAgB,UAAU,MAAM,gBAAgB,kCAAkC,MAAM,OAAO;AAAA,MACnK;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,kDAA6C,yBAAyB;AAAA,MACtE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,iCAAiC;AAAA,MACpC;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,+BAA+B;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,yBAAyB;AAAA,MAC5B;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,8BAA8B;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,cAAc,0BAA0B;AAAA,MACxC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ,0BAA0B;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS,0BAA0B;AAAA,MACnC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,6BAA6B,0BAA0B;AAAA,MACvD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AACF;AAGA,SAAS,2BACP,OACA,eACY;AACZ,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;AAAA,IACF,wBAAwB;AAAA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;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,+BAA+B;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,yBAAyB;AAAA,MAC5B;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,8BAA8B;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,8BAA8B;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,0BAA0B;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,uCAAuC,0BAA0B;AAAA,MACjE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,0BAA0B;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,iCAAiC;AAAA,MACpC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MAC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IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,0BAA0B,KAAK,iBAAiB,0BAA0B,CAAC;AAAA,IACxF;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,qCAAqC;AAAA,IACrC;AAAA,IACA,GAAG,oCAAoC;AAAA,IACvC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAkBO,SAAS,2BACd,OACA,YAA+B,iBAAiB,GAChD,WAA6B,gBAAgB,GAC7B;AAChB,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;AAAA,IACF,SAAS,wBAAwB,OAAO,WAAW,QAAQ;AAAA,EAC7D;AACF;AAEA,IAAM,wBAAwB;AAAA,EAC5B;AAAA,EACA,iBAAiB;AAAA,EACjB,gBAAgB;AAClB;AAkBO,SAAS,gCACd,oBAA+C,yBAAyB,GACxD;AAChB,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;AAAA,IACF,SAAS,8BAA8B,iBAAiB;AAAA,EAC1D;AACF;AAEA,IAAM,6BAA6B;AAAA,EACjC,yBAAyB;AAC3B;AA8EA,SAAS,qBAA6B;AACpC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,mCAAmC,kCAAkC,EAAE;AAAA,IACvE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG,oCAAoC;AAAA,IACvC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAUO,SAAS,wBAAwC;AACtD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;AAAA,IACF,SAAS,mBAAmB;AAAA,EAC9B;AACF;AAEA,IAAM,mBAAmB,sBAAsB;AAiC/C,SAAS,qCAA6C;AACpD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AASO,SAAS,wCAAwD;AACtE,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;AAAA,IACF,SAAS,mCAAmC;AAAA,EAC9C;AACF;AAEA,IAAM,mCACJ,sCAAsC;AAQxC,IAAM,uBAAsC;AAAA,EAC1C,MAAM;AAAA,EACN,aACE;AAAA,EACF,OAAO,YAAY;AAAA,EACnB,UAAU;AAAA,EACV,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,EACvC,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,kDAAkD,+BAA+B;AAAA,IACjF;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,wCAAwC,sBAAsB;AAAA,IAC9D;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,mDAAmD,oBAAoB;AAAA,IACvE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,kDAAkD,0BAA0B,KAAK,iBAAiB,0BAA0B,CAAC;AAAA,IAC7H;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ,sBAAsB;AAAA,IAC9B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAQA,IAAM,sBAAqC;AAAA,EACzC,MAAM;AAAA,EACN,aACE;AAAA,EACF,OAAO,YAAY;AAAA,EACnB,UAAU;AAAA,EACV,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,EACvC,QAAQ;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,yBAAyB,sBAAsB;AAAA,IAC/C;AAAA,IACA;AAAA,IACA,uCAAuC,sBAAsB;AAAA,IAC7D;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG,+BAA+B;AAAA,IAClC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG,2BAA2B,IAAI,CAAC,MAAM,aAAa,CAAC,IAAI;AAAA,IAC3D;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAUA,IAAM,oCAAoC;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,EAAE,KAAK,IAAI;AAmBJ,SAAS,oCACd,OACA,YAA+B,iBAAiB,GAChD,YAA8B,gBAAgB,GAC9C,iBAAyC,sBAAsB,GAC/D,oBAA+C,yBAAyB,GACxE,iBAAwC,CAAC,GACjC;AACR,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,uBAAuB,OAAO,cAAc;AAAA,IAC5C;AAAA,IACA,uBAAuB,WAAW,cAAc;AAAA,IAChD;AAAA,IACA,gCAAgC,cAAc;AAAA,IAC9C;AAAA,IACA,4BAA4B,cAAc;AAAA,IAC1C;AAAA,IACA,+BAA+B,iBAAiB;AAAA,EAClD,EAAE,KAAK,IAAI;AACb;AAmBO,SAAS,0BACd,YACA,iBACA,gBACA,sBACA,yBACA,iBAAwC,CAAC,GAUzC;AACA,QAAM,QAAQ,kBAAkB,UAAU;AAC1C,QAAM,YAAY,iBAAiB,eAAe;AAClD,QAAM,WAAW,gBAAgB,cAAc;AAC/C,QAAM,iBAAiB;AAAA,IACrB;AAAA,IACA;AAAA,EACF;AACA,QAAM,4BAA4B;AAAA,IAChC;AAAA,EACF;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,MAClB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,WAAW,2BAA2B,OAAO,WAAW,QAAQ;AAAA,IAChE,4BAA4B;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AACF;AAcA,IAAM,qBAAmC;AAAA,EACvC,MAAM;AAAA,EACN,aACE;AAAA,EACF,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEA,IAAM,sBAAoC;AAAA,EACxC,MAAM;AAAA,EACN,aACE;AAAA,EACF,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEA,IAAM,cAA4B;AAAA,EAChC,MAAM;AAAA,EACN,aACE;AAAA,EACF,SAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAaA,IAAM,6BAA6B;AAAA,EACjC,WAAW,CAAC,sBAAsB,mBAAmB;AAAA,EAErD,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EAEA,UAAU,CAAC,oBAAoB,qBAAqB,WAAW;AAAA,EAE/D,mBAAmB;AAAA,IACjB,OAAO;AAAA;AAAA,MAEL;AAAA,IACF;AAAA,EACF;AACF;AA2BO,IAAM,mCACX;AAAA,EACE,OAAO;AAAA,EACP,WAAW,iBAAiB;AAAA,EAC5B,UAAU,gBAAgB;AAAA,EAC1B,gBAAgB,sBAAsB;AAAA,EACtC,mBAAmB,yBAAyB;AAAA,EAC5C,gBAAgB,CAAC;AACnB;AAkBK,SAAS,wBACd,cAA+C,kCAC9B;AACjB,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;AAAA;AAAA,IAGF,aAAa,MAAM;AAAA,IAEnB,OAAO;AAAA,MACL;AAAA,QACE,MAAM;AAAA,QACN,aACE;AAAA,QACF,OAAO,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA,QAKxB,cAAc;AAAA,UACZ;AAAA,UACA;AAAA,QACF;AAAA,QACA,SAAS;AAAA,UACP,YAAY;AAAA,UACZ,YAAY;AAAA,UACZ,YAAY;AAAA,UACZ,YAAY;AAAA,UACZ,YAAY;AAAA,UACZ,YAAY;AAAA,QACd;AAAA,QACA,WAAW;AAAA,UACT,QAAQ,EAAE,SAAS,KAAK;AAAA,QAC1B;AAAA,QACA,MAAM,CAAC,UAAU;AAAA,MACnB;AAAA,IACF;AAAA,IACA,GAAG;AAAA,EACL;AACF;AAQO,IAAM,qBAAsC,wBAAwB;;;AC//G3E,SAAS,kCACP,OACA,eACA,MACe;AACf,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;AAAA,IACF,OAAO;AAAA,IACP,UAAU;AAAA,IACV,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,IACvC,QAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,6DAA6D,MAAM,UAAU;AAAA,MAC7E;AAAA,MACA;AAAA,MACA;AAAA,MACA,mIAAmI,MAAM,aAAa;AAAA,MACtJ,mIAAmI,MAAM,YAAY;AAAA,MACrJ,8EAA8E,MAAM,YAAY;AAAA,MAChG;AAAA,MACA,QAAQ,MAAM,QAAQ;AAAA,MACtB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,qBAAqB,MAAM,QAAQ;AAAA,MACnC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,kDAA6C,yBAAyB;AAAA,MACtE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,+BAA+B;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,yBAAyB;AAAA,MAC5B;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,8BAA8B;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,0BAA0B;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;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A;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,0BAA0B;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AACF;AAGA,SAAS,wBACP,OACA,eACY;AACZ,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;AAAA,IACF,wBAAwB;AAAA,IACxB,eAAe;AAAA,IACf,SAAS;AAAA,IACT,OAAO;AAAA,IACP,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,IACvC,cAAc;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,uCAAuC,MAAM,QAAQ;AAAA,MACrD;AAAA,MACA;AAAA,MACA,OAAO,MAAM,UAAU;AAAA,MACvB,OAAO,MAAM,UAAU;AAAA,MACvB;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,MAAM,aAAa;AAAA,MAC1B,OAAO,MAAM,YAAY;AAAA,MACzB,OAAO,MAAM,YAAY;AAAA,MACzB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,iBAAiB,eAAe,eAAe,iBAAiB,EAAE,QAAQ,oBAAoB,eAAe,eAAe,iBAAiB,EAAE,MAAM;AAAA,MACrJ;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,8BAA8B;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AACF;AAGA,SAAS,wBACP,OACA,eACY;AACZ,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;AAAA,IACF,wBAAwB;AAAA,IACxB,eAAe;AAAA,IACf,SAAS;AAAA,IACT,OAAO;AAAA,IACP,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,IACvC,cAAc;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,mBAAmB,MAAM,QAAQ;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,iBAAiB,eAAe,eAAe,gBAAgB,EAAE,QAAQ,oBAAoB,eAAe,eAAe,gBAAgB,EAAE,MAAM;AAAA,MACnJ;AAAA,MACA;AAAA,MACA,GAAG,8BAA8B;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AACF;AAgBO,SAAS,yBACd,QAA4B,qBAC5B,gBAAuC,iCACvC,OAAmB,YAAY,UACd;AACjB,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;AAAA,IACF,aAAa,MAAM;AAAA,IACnB,OAAO;AAAA,MACL;AAAA,QACE,MAAM;AAAA,QACN,aACE;AAAA,QACF,OAAO,iBAAiB;AAAA,QACxB,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,EAAE,KAAK,IAAI;AAAA,QACX,WAAW;AAAA,UACT,QAAQ,EAAE,SAAS,KAAK;AAAA,QAC1B;AAAA,QACA,MAAM,CAAC,UAAU;AAAA,MACnB;AAAA,IACF;AAAA,IACA,QAAQ;AAAA,MACN,wBAAwB,OAAO,aAAa;AAAA,MAC5C,wBAAwB,OAAO,aAAa;AAAA,IAC9C;AAAA,IACA,WAAW,CAAC,kCAAkC,OAAO,eAAe,IAAI,CAAC;AAAA,IACzE,QAAQ;AAAA,MACN;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACF;AAQO,IAAM,sBAAuC,yBAAyB;;;ACnhC7E,SAAS,gBAAgB;AACzB,SAAS,aAAAC,YAAoB,gBAAgB;AAMtC,IAAM,sBAAsB;AAAA,EACjC,WAAW;AAAA,EACX,UAAU;AAAA,EACV,WAAW;AAAA,EACX,cAAc;AAAA,EACd,SAAS;AAAA,EACT,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,WAAW;AAAA,EACX,UAAU;AAAA,EACV,UAAU;AACZ;AAs+BA,IAAM,uBAAuB;AAAA;AAAA,EAE3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAeA,IAAM,qBAAoD;AAAA;AAAA,EAExD,UAAU;AAAA,EACV,SAAS;AAAA,EACT,UAAU;AAAA;AAAA,EAEV,mBAAmB;AAAA,EACnB,0BAA0B;AAAA,EAC1B,uBAAuB;AAAA,EACvB,0BAA0B;AAAA,EAC1B,aAAa;AAAA,EACb,qBAAqB;AAAA,EACrB,iBAAiB;AAAA,EACjB,qBAAqB;AAAA,EACrB,aAAa;AAAA,EACb,uBAAuB;AAAA,EACvB,yBAAyB;AAAA,EACzB,oCAAoC;AAAA;AAAA,EAEpC,wBAAwB;AAAA,EACxB,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,cAAc;AAAA;AAAA,EAEd,GAAG,OAAO,YAAY,qBAAqB,IAAI,CAAC,QAAQ,CAAC,KAAK,GAAG,CAAC,CAAC;AACrE;AAEO,IAAM,gBAAN,MAAM,uBAAsBA,WAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ3C,OAAc,GAAG,SAA6C;AAC5D,UAAM,YAAY,CAAC,MACjB,aAAa;AACf,WAAO,QAAQ,KAAK,WAAW,KAAK,SAAS;AAAA,EAC/C;AAAA,EAuLA,YAAY,SAAkB,UAAgC,CAAC,GAAG;AAChE,UAAM,OAAO;AAYb,YAAQ,kBAAkB,cAAc,GAAG,oBAAoB,MAAM;AAcrE,SAAK,WAAW,QAAQ,YAAY;AAKpC,SAAK,oBACH,QAAQ,qBAAqB,oBAAoB;AAKnD,SAAK,2BAA2B,QAAQ,2BACpC,CAAC,mBAAmB,GAAG,QAAQ,wBAAwB,IACvD,CAAC,iBAAiB;AAKtB,SAAK,wBAAwB,QAAQ,wBACjC,QAAQ,wBACR,CAAC;AAKL,SAAK,2BAA2B,QAAQ,2BACpC,QAAQ,2BACR,CAAC;AAKL,SAAK,cAAc,QAAQ,eAAe,CAAC;AAK3C,SAAK,cAAc,QAAQ,eAAe,CAAC;AAK3C,SAAK,iBAAiB,QAAQ;AAK9B,SAAK,gBAAgB,QAAQ;AAO7B,SAAK,sBAAsB,QAAQ;AACnC,SAAK,kBAAkB,QAAQ;AAC/B,SAAK,sBAAsB,QAAQ;AAKnC,SAAK,cAAc,QAAQ;AAC3B,SAAK,wBAAwB,QAAQ;AASrC,SAAK,0BAA0B,QAAQ,2BAA2B;AAClE,SAAK,qCACH,QAAQ;AAWV,SAAK,kBAAkB,CAAC;AACxB,eAAW,OAAO;AAAA,MAChB,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,GAAgD;AAC9C,YAAM,QAAQ,QAAQ,GAAG;AACzB,UAAI,UAAU,QAAW;AACvB,aAAK,gBAAgB,GAAG,IAAI;AAAA,MAC9B;AAAA,IACF;AAOA,SAAK,qBAAqB,EAAE,GAAG,QAAQ,mBAAmB;AAC1D,eAAW,eAAe,OAAO,KAAK,KAAK,kBAAkB,GAAG;AAC9D,YAAM,cAAc,mBAAmB,WAAW;AAClD,UAAI,gBAAgB,QAAW;AAC7B,cAAM,IAAI;AAAA,UACR,uBAAuB,WAAW,+BAA+B,KAAK,YAAY,IAAI,6BACvE,WAAW,iCAAiC,WAAW;AAAA,QACxE;AAAA,MACF;AAAA,IACF;AAKA,YAAQ,iBAAiB,KAAK,QAAQ;AActC,YAAQ,cAAc,KAAK,QAAQ;AAKnC,QAAI,SAAS,KAAK,SAAS,KAAK,UAAU;AAAA,MACxC,KAAK,MAAM;AACT,cAAM,aAAkB,CAAC;AACzB,cAAM,WAAW,IAAI,MAAc;AAKnC,mBAAW,cAAc,QAAQ,aAAa;AAE5C,mBAAS,KAAK,SAAS,KAAK,QAAQ,QAAQ,WAAW,MAAM,CAAC;AAAA,QAChE;AAOA,cAAM,aAAa,IAAI,IAAI,QAAQ;AACnC,mBAAW,kBAAkB,KAAK,aAAa;AAC7C,qBAAW,IAAI,cAAc;AAAA,QAC/B;AAKA,YAAI,KAAK,YAAY,SAAS,GAAG;AAC/B,mBAAS,SAAS;AAClB,mBAAS,KAAK,GAAG,UAAU;AAAA,QAC7B;AAKA,mBAAW,oBAAoB,KAAK;AAKpC,YAAI,KAAK,yBAAyB,SAAS,GAAG;AAC5C,qBAAW,2BAA2B,KAAK;AAAA,QAC7C;AAeA,cAAM,yBAA0B,KAAK,gBAClC,0BAA0B,CAAC;AAE9B,cAAM,oBAAwD,CAAC;AAC/D,mBAAW,OAAO,KAAK,uBAAuB;AAC5C,4BAAkB,GAAG,IAAI;AAAA,QAC3B;AACA,mBAAW,OAAO,KAAK,0BAA0B;AAC/C,4BAAkB,GAAG,IAAI;AAAA,QAC3B;AACA,mBAAW,OAAO,wBAAwB;AACxC,4BAAkB,GAAG,IAAI;AAAA,QAC3B;AACA,mBAAW,CAAC,KAAK,OAAO,KAAK,OAAO,QAAQ,KAAK,WAAW,GAAG;AAC7D,4BAAkB,GAAG,IAAI;AAAA,QAC3B;AAiBA,cAAM,YAA2B,CAAC;AAClC,cAAM,WAA0B,CAAC;AACjC,mBAAW,CAAC,KAAK,OAAO,KAAK,OAAO,QAAQ,iBAAiB,GAAG;AAC9D,cAAI,SAAS;AACX,sBAAU,KAAK,GAAG;AAAA,UACpB,OAAO;AACL,qBAAS,KAAK,GAAG;AAAA,UACnB;AAAA,QACF;AACA,kBAAU,KAAK;AACf,iBAAS,KAAK;AAEd,YAAI,UAAU,SAAS,GAAG;AACxB,qBAAW,wBAAwB;AAAA,QACrC;AACA,YAAI,SAAS,SAAS,GAAG;AACvB,qBAAW,2BAA2B;AAAA,QACxC;AAQA,YAAI,uBAAuB,SAAS,GAAG;AACrC,qBAAW,yBAAyB;AAAA,QACtC;AAEA,YAAI,OAAO,KAAK,iBAAiB,EAAE,SAAS,GAAG;AAC7C,qBAAW,cAAc;AAAA,QAC3B;AAKA,YACE,KAAK,kBACL,OAAO,KAAK,KAAK,cAAc,EAAE,SAAS,GAC1C;AACA,qBAAW,UAAU,KAAK;AAAA,QAC5B;AAKA,YAAI,KAAK,iBAAiB,OAAO,KAAK,KAAK,aAAa,EAAE,SAAS,GAAG;AACpE,qBAAW,WAAW,KAAK;AAAA,QAC7B;AAQA,YAAI,KAAK,wBAAwB,QAAW;AAC1C,qBAAW,sBAAsB,KAAK;AAAA,QACxC;AACA,YAAI,KAAK,oBAAoB,QAAW;AACtC,qBAAW,kBAAkB,KAAK;AAAA,QACpC;AACA,YAAI,KAAK,wBAAwB,QAAW;AAC1C,qBAAW,sBAAsB,KAAK;AAAA,QACxC;AACA,YAAI,KAAK,gBAAgB,QAAW;AAClC,qBAAW,cAAc,KAAK;AAAA,QAChC;AAWA,cAAM,eAAe,KAAK,gBAAgB;AAE1C,YAAI,iBAAiB,QAAW;AAC9B,qBAAW,eAAe;AAAA,QAC5B,WAAW,KAAK,0BAA0B,QAAW;AACnD,qBAAW,wBAAwB,KAAK;AAAA,QAC1C;AACA,YAAI,KAAK,4BAA4B,QAAW;AAC9C,qBAAW,0BAA0B,KAAK;AAAA,QAC5C;AACA,YAAI,KAAK,uCAAuC,QAAW;AACzD,qBAAW,qCACT,KAAK;AAAA,QACT;AAQA,mBAAW,eAAe,sBAAsB;AAC9C,gBAAM,QAAQ,KAAK,gBAAgB,WAAW;AAC9C,cAAI,UAAU,QAAW;AACvB,uBAAW,WAAW,IAAI;AAAA,UAC5B;AAAA,QACF;AASA,cAAM,SAAS,KAAK,gBAAgB;AACpC,cAAM,eAAe,KAAK,gBAAgB;AAC1C,YAAI,WAAW,QAAW;AACxB,qBAAW,SAAS;AAAA,QACtB,WAAW,iBAAiB,QAAW;AACrC,qBAAW,eAAe;AAAA,QAC5B;AAOA,mBAAW,CAAC,aAAa,KAAK,KAAK,OAAO;AAAA,UACxC,KAAK;AAAA,QACP,GAAG;AACD,qBAAW,WAAW,IAAI;AAAA,QAC5B;AAKA,eAAO;AAAA,UACL,GAAI,SAAS,SAAS,IAAI,EAAE,SAAS,IAAI,CAAC;AAAA,UAC1C,GAAI,aAAa,EAAE,GAAG,WAAW,IAAI,CAAC;AAAA,QACxC;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBO,QAAQ,aAA8B;AAC3C,QAAI,eAAe,KAAK,iBAAiB;AACvC,aAAO,KAAK,gBAAgB,WAAW;AAAA,IACzC;AACA,WAAO,KAAK,mBAAmB,WAAW;AAAA,EAC5C;AACF;AAKO,IAAM,sBAAsB;;;ACtrD5B,IAAM,aAA8B;AAAA,EACzC,MAAM;AAAA,EACN,aAAa;AAAA,EACb,aAAa,CAAC,YAAqB,aAAa,SAAS,aAAa;AAAA,EACtE,OAAO;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,aAAa;AAAA,MACb,OAAO,iBAAiB;AAAA,MACxB,cAAc,CAAC,gBAAgB,uBAAuB,gBAAgB;AAAA,MACtE,SAAS;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,IAAI;AAAA,MACX,MAAM,CAAC,UAAU;AAAA,IACnB;AAAA,EACF;AACF;;;ACFO,IAAM,4BAA4B;AAWlC,IAAM,qCAAqC;AAYlD,SAAS,0BACP,QACuB;AACvB,QAAM,YAAY,OAAO,eAAe;AACxC,QAAM,OACJ,UAAU,WAAW,IACjB;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,EACF,IACA;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG,UAAU,IAAI,CAAC,SAAS,SAAS,IAAI,IAAI;AAAA,EAC9C;AAEN,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAUO,SAAS,qBACd,QACY;AACZ,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;AAAA,IACF,wBAAwB;AAAA,IACxB,eAAe;AAAA,IACf,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,IACvC,cAAc;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,0BAA0B,MAAM;AAAA,MACnC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,mEAAgE,kCAAkC;AAAA,MAClG;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,6EAAmE,yBAAyB;AAAA,MAC5F;AAAA,MACA,sCAAsC,yBAAyB;AAAA,MAC/D;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,2BAA2B,IAAI,CAAC,MAAM,UAAU,CAAC,IAAI;AAAA,MACxD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,4DAA4D,+BAA+B;AAAA,MAC3F;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,iCAAiC;AAAA,MACpC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA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A,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,6BAA6B,yBAAyB;AAAA,IACtD,OAAO,kBAAkB;AAAA,IACzB;AAAA,IACA,OAAO,yBAAyB;AAAA,IAChC,2BAA2B,kBAAkB;AAAA,IAC7C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,oBAAoB,yBAAyB;AAAA,IAC7C,QAAQ,kBAAkB;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG,2BAA2B,IAAI,CAAC,MAAM,WAAW,CAAC,IAAI;AAAA,IACzD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,2MAA2M,iCAAiC;AA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A;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,EAAE,KAAK,IAAI;AAAA,QACX,MAAM,CAAC,UAAU,QAAQ;AAAA,MAC3B;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,aACE;AAAA,QACF,OAAO,iBAAiB;AAAA,QACxB,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,EAAE,KAAK,IAAI;AAAA,QACX,WAAW;AAAA,UACT,QAAQ,EAAE,SAAS,KAAK;AAAA,QAC1B;AAAA,QACA,MAAM,CAAC,UAAU;AAAA,MACnB;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,aACE;AAAA,QACF,OAAO,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA,QAKxB,cAAc;AAAA,UACZ;AAAA,UACA;AAAA;AAAA;AAAA,UAGA;AAAA,QACF;AAAA,QACA,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,OAAO,yBAAyB;AAAA,UAChC,OAAO,kBAAkB,+cAA+c,yBAAyB,yDAAoD,yBAAyB;AAAA,UAC9kB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,0CAAqC,iCAAiC;AAAA,UACtE;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,EAAE,KAAK,IAAI;AAAA,QACX,WAAW;AAAA,UACT,QAAQ,EAAE,SAAS,KAAK;AAAA,QAC1B;AAAA,QACA,MAAM,CAAC,UAAU;AAAA,MACnB;AAAA,IACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA,QAAQ,CAAC,eAAe,gBAAgB,qBAAqB,MAAM,CAAC;AAAA,IACpE,WAAW,CAAC,kBAAkB;AAAA,IAC9B,QAAQ;AAAA,MACN;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACF;AAUA,SAAS,8BACP,OACuB;AACvB,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO,CAAC,QAAQ;AAAA,EAClB;AACA,SAAO,MAAM,IAAI,CAACC,UAAS,UAAUA,KAAI,GAAG;AAC9C;AAUA,SAAS,4BACP,WACuB;AACvB,MAAI,UAAU,WAAW,GAAG;AAC1B,WAAO,CAAC,QAAQ;AAAA,EAClB;AACA,SAAO,UAAU,IAAI,CAAC,aAAa,UAAU,QAAQ,GAAG;AAC1D;AAQO,IAAM,iBAAkC,oBAAoB;;;ACrwF5D,IAAM,eAAgC;AAAA,EAC3C,MAAM;AAAA,EACN,aAAa;AAAA,EACb,aAAa,CAAC,YAAqB,OAAO,SAAS,QAAQ;AAAA,EAC3D,OAAO;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,aACE;AAAA;AAAA;AAAA;AAAA;AAAA,MAKF,OAAO,iBAAiB;AAAA,MACxB,SAAS;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA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AA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ,MAAM,QAAQ;AAAA,MACtB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,2BAA2B,0BAA0B;AAAA,MACrD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;A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AA,MACA;AAAA,MACA,mBAAmB,0BAA0B;AAAA,MAC7C;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AACF;AAGA,SAAS,kCACP,OACA,eACY;AACZ,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;AAAA,IACF,wBAAwB;AAAA,IACxB,eAAe;AAAA,IACf,SAAS;AAAA,IACT,OAAO;AAAA,IACP,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,IACvC,cAAc;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,KAAK,MAAM,QAAQ;AAAA,MACnB;AAAA,MACA;AAAA,MACA,oBAAoB,MAAM,YAAY;AAAA,MACtC,yBAAyB,MAAM,QAAQ;AAAA,MACvC,mCAAmC,MAAM,QAAQ;AAAA,MACjD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,iBAAiB,eAAe,eAAe,iBAAiB,EAAE,QAAQ,oBAAoB,eAAe,eAAe,iBAAiB,EAAE,MAAM;AAAA,MACrJ;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,8BAA8B;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AACF;AAGA,SAAS,6BACP,OACA,eACY;AACZ,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;AAAA,IACF,wBAAwB;AAAA,IACxB,eAAe;AAAA,IACf,SAAS;AAAA,IACT,OAAO;AAAA,IACP,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,IACvC,gBAAgB;AAAA,IAChB,cAAc;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,KAAK,MAAM,QAAQ;AAAA,MACnB;AAAA,MACA;AAAA,MACA,KAAK,MAAM,QAAQ;AAAA,MACnB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,+CAA+C,eAAe,eAAe,qBAAqB,EAAE,QAAQ;AAAA,MAC5G,eAAe,eAAe,eAAe,qBAAqB,EAAE,MAAM;AAAA,MAC1E;AAAA,MACA;AAAA,MACA,GAAG,8BAA8B;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AACF;AAGA,SAAS,2BACP,OACA,eACY;AACZ,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;AAAA,IACF,wBAAwB;AAAA,IACxB,eAAe;AAAA,IACf,SAAS;AAAA,IACT,OAAO;AAAA,IACP,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,IACvC,cAAc;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,KAAK,MAAM,QAAQ;AAAA,MACnB;AAAA,MACA;AAAA,MACA,KAAK,MAAM,QAAQ;AAAA,MACnB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,+CAA+C,eAAe,eAAe,mBAAmB,EAAE,QAAQ;AAAA,MAC1G,eAAe,eAAe,eAAe,mBAAmB,EAAE,MAAM;AAAA,MACxE;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,8BAA8B;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AACF;AAuBO,SAAS,8BACd,QAA4B,qBAC5B,gBAAuC,iCACtB;AACjB,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;AAAA,IACF,aAAa,MAAM;AAAA,IACnB,OAAO;AAAA,MACL;AAAA,QACE,MAAM;AAAA,QACN,aACE;AAAA,QACF,OAAO,iBAAiB;AAAA,QACxB,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,iBAAiB,MAAM,QAAQ;AAAA,UAC/B;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,EAAE,KAAK,IAAI;AAAA,QACX,WAAW;AAAA,UACT,QAAQ,EAAE,SAAS,KAAK;AAAA,QAC1B;AAAA,QACA,MAAM,CAAC,UAAU;AAAA,MACnB;AAAA,IACF;AAAA,IACA,QAAQ;AAAA,MACN,kCAAkC,OAAO,aAAa;AAAA,MACtD,6BAA6B,OAAO,aAAa;AAAA,MACjD,2BAA2B,OAAO,aAAa;AAAA,IACjD;AAAA,IACA,WAAW,CAAC,uCAAuC,OAAO,aAAa,CAAC;AAAA,IACxE,QAAQ;AAAA,MACN;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACF;AAQO,IAAM,2BACX,8BAA8B;;;ACtqCzB,IAAM,sCAA6D;AAAA,EACxE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAeO,IAAM,+CACX;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAWK,IAAM,kCAAyD;AAAA,EACpE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAkBO,IAAM,iCAAwD;AAAA,EACnE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;;;AClJA,IAAM,aAAa,CAAC,UAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qCAqErB,MAAM,wBAAwB,UAAU,iCAAiC,MAAM,wBAAwB,UAAU;AAAA,qCACjH,MAAM,wBAAwB,aAAa;AAAA,8BAClD,MAAM,wBAAwB,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsCpE,IAAM,aAAa,CAAC,UAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gCAqG1B,MAAM,wBAAwB,QAAQ;AAAA,qCACjC,MAAM,wBAAwB,aAAa;AAAA,8BAClD,MAAM,wBAAwB,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsCvE,IAAM,cAAc,CAAC,UAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,8BA8D7B,MAAM,wBAAwB,QAAQ;AAAA,gCACpC,MAAM,wBAAwB,UAAU;AAAA,mCACrC,MAAM,wBAAwB,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsC5E,IAAM,aAAa,CAAC,UAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mCAiHvB,MAAM,wBAAwB,sBAAsB;AAAA,8BACzD,MAAM,wBAAwB,UAAU;AAAA,qCACjC,MAAM,wBAAwB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsChF,IAAM,cAAc,CAAC,UAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,8BA0F7B,MAAM,wBAAwB,QAAQ;AAAA,oCAChC,MAAM,wBAAwB,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuC3E,IAAM,cAAc,CAAC,UAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,8BAwE7B,MAAM,wBAAwB,UAAU;AAAA,qCACjC,MAAM,wBAAwB,aAAa;AAAA,gCAChD,MAAM,wBAAwB,QAAQ;AAAA,kCACpC,MAAM,wBAAwB,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsCpE,IAAM,aAAa,CAAC,UAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,8BA4E5B,MAAM,wBAAwB,UAAU;AAAA,mCACnC,MAAM,wBAAwB,QAAQ;AAAA,gCACzC,MAAM,wBAAwB,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsCvE,IAAM,cAAc,CAAC,UAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6BA6F9B,MAAM,wBAAwB,UAAU;AAAA,qCAChC,MAAM,wBAAwB,aAAa;AAAA,iCAC/C,MAAM,wBAAwB,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsCvE,IAAM,cAAc,CAAC,UAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+BA4E5B,MAAM,wBAAwB,aAAa;AAAA,8BAC5C,MAAM,wBAAwB,QAAQ;AAAA,0BAC1C,MAAM,wBAAwB,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsCjE,IAAM,aAAa,CAAC,UAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,8BA8E5B,MAAM,wBAAwB,UAAU;AAAA,qCACjC,MAAM,wBAAwB,aAAa;AAAA,8BAClD,MAAM,wBAAwB,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsCpE,IAAM,aAAa,CAAC,UAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gCA+E1B,MAAM,wBAAwB,QAAQ;AAAA,iCACrC,MAAM,wBAAwB,QAAQ;AAAA,qCAClC,MAAM,wBAAwB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsChF,IAAM,2BAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqCjC,IAAM,6BAA6B,CAAC,UAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oCAUtC,MAAM,wBAAwB,QAAQ,QAAQ,MAAM,wBAAwB,QAAQ;AAAA,sCAClF,MAAM,wBAAwB,UAAU,QAAQ,MAAM,wBAAwB,UAAU;AAAA,2CACnF,MAAM,wBAAwB,aAAa,QAAQ,MAAM,wBAAwB,aAAa;AAAA,qCACpG,MAAM,wBAAwB,SAAS,QAAQ,MAAM,wBAAwB,SAAS;AAAA,uCACpF,MAAM,wBAAwB,sBAAsB,QAAQ,MAAM,wBAAwB,sBAAsB;AAAA,qCAClH,MAAM,wBAAwB,QAAQ,QAAQ,MAAM,wBAAwB,QAAQ;AAAA,gCACzF,MAAM,wBAAwB,IAAI,QAAQ,MAAM,wBAAwB,IAAI;AAAA,wCACpE,MAAM,wBAAwB,WAAW,QAAQ,MAAM,wBAAwB,WAAW;AAAA,wCAC1F,MAAM,wBAAwB,WAAW,QAAQ,MAAM,wBAAwB,WAAW;AAAA,8BACpG,MAAM,wBAAwB,EAAE,QAAQ,MAAM,wBAAwB,EAAE;AAAA,wCAC9D,MAAM,wBAAwB,YAAY,QAAQ,MAAM,wBAAwB,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gCAkEpG,MAAM,wBAAwB,UAAU;AAAA,qCACnC,MAAM,wBAAwB,aAAa;AAAA,8BAClD,MAAM,wBAAwB,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0CpE,IAAM,2BAA2B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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A;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,6DAAwD,MAAM,wBAAwB,sBAAsB;AAAA,MAC5G;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,gCAAgC,MAAM,wBAAwB,sBAAsB;AAAA,MACpF;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,yCAAyC,MAAM,QAAQ;AAAA,MACvD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,iCAAiC,MAAM,wBAAwB,QAAQ;AAAA,MACvE,sCAAsC,MAAM,wBAAwB,aAAa;AAAA,MACjF,+BAA+B,MAAM,wBAAwB,QAAQ;AAAA,MACrE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,qDAAqD,MAAM,wBAAwB,UAAU;AAAA,MAC7F;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,+BAA+B;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,yBAAyB;AAAA,MAC5B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ,MAAM,QAAQ;AAAA,MACtB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AACF;AAGA,SAAS,2BACP,OACA,eACY;AACZ,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;AAAA,IACF,wBAAwB;AAAA,IACxB,eAAe;AAAA,IACf,SAAS;AAAA,IACT,OAAO;AAAA,IACP,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,IACvC,gBAAgB,sCAAsC,KAAK;AAAA,IAC3D,cAAc;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,+CAA+C,MAAM,QAAQ;AAAA,MAC7D;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,uCAAuC,MAAM,QAAQ;AAAA,MACrD;AAAA,MACA;AAAA,MACA,OAAO,MAAM,gBAAgB;AAAA,MAC7B,OAAO,MAAM,gBAAgB;AAAA,MAC7B,OAAO,MAAM,gBAAgB;AAAA,MAC7B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,iBAAiB,eAAe,eAAe,WAAW,EAAE,QAAQ,gBAAgB,eAAe,eAAe,WAAW,EAAE,MAAM;AAAA,MACrI;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,8BAA8B;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AACF;AAyCO,SAAS,mCAA2C;AACzD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAYO,IAAM,6BAA6C;AAAA,EACxD,MAAM;AAAA,EACN,aACE;AAAA,EACF,SAAS,iCAAiC;AAC5C;AAoBO,SAAS,8BACd,QAA4B,qBAC5B,gBAAuC,iCACtB;AACjB,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;AAAA,IACF,aAAa,MAAM;AAAA,IACnB,OAAO;AAAA,MACL;AAAA,QACE,MAAM;AAAA,QACN,aACE;AAAA,QACF,OAAO,iBAAiB;AAAA,QACxB,SAAS;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,EAAE,KAAK,IAAI;AAAA,QACX,WAAW;AAAA,UACT,QAAQ,EAAE,SAAS,KAAK;AAAA,QAC1B;AAAA,QACA,MAAM,CAAC,UAAU;AAAA,MACnB;AAAA,IACF;AAAA,IACA,QAAQ,CAAC,2BAA2B,OAAO,aAAa,CAAC;AAAA,IACzD,WAAW,CAAC,gCAAgC,KAAK,CAAC;AAAA,IAClD,YAAY,CAAC,0BAA0B;AAAA,IACvC,QAAQ;AAAA,MACN;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aACE;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACF;AAQO,IAAM,2BACX,8BAA8B;;;AC3+FhC,SAAS,iCACP,OACA,eACe;AACf,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aACE;AAAA,IACF,OAAO,YAAY;AAAA,IACnB,UAAU;AAAA,IACV,WAAW,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAAA,IACvC,QAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,0EAA0E,MAAM,OAAO;AAAA,MACvF,4DAA4D,MAAM,QAAQ;AAAA,MAC1E,gEAAgE,MAAM,QAAQ;AAAA,MAC9E,gDAAgD,MAAM,QAAQ;AAAA,MAC9D,uEAAuE,MAAM,wBAAwB;AAAA,MACrG,8FAA8F,MAAM,gBAAgB;AAAA,MACpH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,+BAA+B;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,yBAAyB;AAAA,MAC5B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,qQAAgQ,MAAM,QAAQ;AAAA,MAC9Q;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA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MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,KAAK,MAAM,QAAQ;AAAA,MACnB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,0CAAqC,MAAM,QAAQ;AAAA,MACnD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,sBAAsB,MAAM,QAAQ;AAAA,MACpC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,4BAA4B,MAAM,QAAQ;AAAA,MAC1C;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,KAAK,MAAM,QAAQ;AAAA,MACnB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,aAAa,MAAM,wBAAwB,QAAQ;AAAA,MACnD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,MAAM,gBAAgB;AAAA,MAC7B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MAC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MACA;AAAA,MACA;AAAA,MACA,GAAG,8BAA8B;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,0BAA0B;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,0BAA0B;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,0BAA0B;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAA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AAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,0BAA0B;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MAC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A,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,kDAA6C,yBAAyB;AAAA,MACtE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,+BAA+B;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,yBAAyB;AAAA,MAC5B;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,8BAA8B;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ,MAAM,QAAQ;AAAA,MACtB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,0BAA0B;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,mBAAmB,eAAe,eAAe,kBAAkB,EAAE,QAAQ;AAAA,MAC7E,iBAAiB,eAAe,eAAe,kBAAkB,EAAE,MAAM;AAAA,MACzE;AAAA,MACA,GAAG,8BAA8B;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,mBAAmB,eAAe,eAAe,iBAAiB,EAAE,QAAQ;AAAA,MAC5E,iBAAiB,eAAe,eAAe,iBAAiB,EAAE,MAAM;AAAA,MACxE;AAAA,MACA,GAAG,8BAA8B;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,0BAA0B;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,0BAA0B;AAAA,MAChC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MAC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ACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,EAAE,KAAK,IAAI;AASX,IAAM,oCAAoC;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAC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","names":["Component","SampleFile","TextFile","prefix","path","Component","Component","Component","path","path","Component","Component","Component","Component","JsonFile","TextFile","TextFile","JsonFile","fs","JsonFile","TextFile","GENERATED_MARKER","TextFile","JsonFile","path","Component","TextFile","SampleFile","unblockDependentsProcedure","Component","JsonFile","Component","JsonFile","Component","TextFile","spec","import_utils","relative","Component","Component","Component","Component","relative","import_utils","Component","Component","path","path","fs","path","fromMarkdown","DEFAULT_DOCS_ROOT","walkMarkdownFiles","toPosix","stripYamlFrontmatter","path","toPosix","fs","path","path","ts","Component","JsonFile","SampleFile","SampleFile","SampleFile","merge","toPosix","prefix","NodePackageManager","UpgradeDependenciesSchedule","merge","Component","TextFile","Component","TextFile","Component","Component","path","Component","JobPermission","JobPermission","GitHub","GitHub","GitHub","patchStepArray","GitHub","STEP_ARRAY_FIELDS","patchComponentStepArrays","GitHub","patchStepArray","getEagerSteps","readStepArray","Component","TextFile","path","Component","YamlFile","JobPermission","DEFAULT_WORKFLOW_NAME","Component","JsonFile","relative","Component","NodePackageManager","UpgradeDependenciesSchedule","merge","merge","SampleFile","ReleasableCommits","NodePackageManager","Transform","UpgradeDependenciesSchedule","ReleaseTrigger","merge","import_utils","Component","GitHub","WorkflowSteps","JobPermission","Component","JobPermission","Component","JobPermission","Component","WorkflowSteps","JobPermission","Component","Component","JobPermission","prefix","GitHub","WorkflowSteps","Component","GitHub","GithubWorkflow","JobPermission","Component","GitHub","GithubWorkflow","JobPermission","NodePackageManager","Transform","UpgradeDependenciesSchedule","ReleaseTrigger","ReleasableCommits","merge","spec","SampleFile","TextFile","merge","merge","TextFile","SampleFile","SampleFile","SampleFile"]}