EA-2136 sync architecture instruction files from org baseline - #64
EA-2136 sync architecture instruction files from org baseline#64bwell-dev wants to merge 1 commit into
Conversation
Updates from icanbwell/.github: - AGENTS.md: Organization-wide AI agent instruction baseline - CLAUDE.md: Symlink for Claude Code compatibility - copilot-instructions.md: Lightweight instructions for GitHub Copilot - policies/approved-tech.yaml: Technology approval list - .github/workflows: PR architecture review and commit message validation - .claude/skills: Claude Code skills (api-design-guardian, sync-to-async, etc.) - CODEOWNERS: EA ownership of instruction files Source commit: 62f8288431418749382e0b673b363841d8f8977d
| pull_request_target: | ||
| types: [opened, synchronize, reopened] |
There was a problem hiding this comment.
Using unsafe GitHub Actions trigger may allow privilege escalation via CI/CD - critical severity
Using pull_request_target or workflow_run as a trigger is not recommended, as it may allow an attacker to elevate its privileges via the CI/CD pipeline by exfiltrating secrets (e.g. by reading out the caches of the GitHub Actions pipeline or listing loaded secrets in the environment). If the affected repository is open source, the attacker doesn't have to be an insider but could be any GitHub user.
| pull_request_target: | |
| types: [opened, synchronize, reopened] | |
| pull_request: | |
| types: [opened, synchronize, reopened] |
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Check For Issue Key | ||
| uses: gsactions/commit-message-checker@v2 |
There was a problem hiding this comment.
3rd party Github Actions should be pinned - high severity
A third-party GitHub Action was imported, and is not pinned via a hash. This leaves your CI/CD at risk for potential supply chain attacks, if the affected GitHub Action is compromised.
| uses: gsactions/commit-message-checker@v2 | |
| uses: gsactions/commit-message-checker@16fa2d5de096ae0d35626443bcd24f1e756cafee # v2.0.0 |
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info
There was a problem hiding this comment.
2 Open source vulnerabilities detected - high severity
Aikido detected 2 vulnerabilities across 1 package, it includes 1 high and 1 medium vulnerabilities.
Details
Remediation:
brace-expansion— 2 CVEs (high) — fixed in 5.0.8
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info
| @@ -0,0 +1,906 @@ | |||
| #!/usr/bin/env node | |||
There was a problem hiding this comment.
New ~900-line CLI script mixes many responsibilities (arg parsing, registry parsing, route walking, ts-morph tracing). Consider splitting tracing, registry parsing, and route utilities into separate modules to improve maintainability.
Details
✨ AI Reasoning
The change introduced a single large script that combines multiple distinct responsibilities: argument parsing, repo root detection, cached config discovery, registry parsing, route-tree walking, component/registry lookup helpers, and a heavy ts-morph based tracing routine and main CLI flow. Grouping all of this into one ~900-line file increases cognitive load and slows navigation, testing, and reuse. Splitting tracing (ts-morph), registry parsing, route utilities, and CLI entrypoint into focused modules would localize complexity and improve maintainability.
🔧 How do I fix it?
Split large files into smaller, focused modules. Each file should have a single responsibility.
Reply @AikidoSec feedback: [FEEDBACK] to get better review comments in the future.
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info
| ### Dependency Inversion | ||
| Depend on abstractions at module and service boundaries. Inject dependencies through constructors. Never instantiate infrastructure inside business logic. Never use service locators when constructor injection is available. | ||
|
|
||
| ### IoC Container (`simple_container`) | ||
|
|
||
| This project uses the `simple_container` library for inversion of control. All service registrations live in `languagemodelcommon/container/container_factory.py`. | ||
|
|
||
| **Rules:** | ||
| - Register new services as singletons in `LanguageModelCommonContainerFactory.register_services_in_container()` — do not instantiate services directly in calling code. | ||
| - When creating a new service class, add its registration to `container_factory.py` and inject its dependencies from the container (not by constructing them inline). | ||
| - Tests can override registrations by constructing a test container with mock implementations. | ||
|
|
||
| ### Environment Variables (`LanguageModelCommonEnvironmentVariables`) | ||
|
|
||
| Access environment variables through the `LanguageModelCommonEnvironmentVariables` class (`languagemodelcommon/utilities/environment/language_model_common_environment_variables.py`), not via `os.environ` directly. This class is registered in the IoC container. | ||
|
|
||
| **Rules:** | ||
| - Add new environment variable access as `@property` methods on `LanguageModelCommonEnvironmentVariables`. | ||
| - Inject the environment variables class via the container — do not instantiate it inline or call `os.environ.get()` in business logic. | ||
| - Provide sensible defaults in the property when the variable is optional. | ||
|
|
||
| --- | ||
|
|
||
| ## Architectural Boundaries |
There was a problem hiding this comment.
🔴 This sync overwrites AGENTS.md (symlinked as CLAUDE.md) with the org baseline, silently deleting several repo-specific sections that document conventions still actively used here: the IoC Container (simple_container) section, the Environment Variables (LanguageModelCommonEnvironmentVariables) section, the mandatory keyword-only-arguments rule, and the Branch Protection warning. It also reverts 'Don't Guess Commands' to reference a nonexistent Pipfile/build.gradle instead of this repo's actual pyproject.toml/uv.lock. This contradicts both the file's own precedence rule ('repo-level ... must not weaken') and the PR description's claim of being 'purely additive.'
Extended reasoning...
What's wrong
The diff to AGENTS.md (lines 121-126, 168-173, 284-290, 302-307) is not purely additive as the PR description claims — it deletes four blocks of repo-specific guidance that were previously merged into this file and replaces one of them with content that is now factually incorrect for this repo:
- IoC Container (
simple_container) section — deleted.languagemodelcommon/container/container_factory.pyexists today and implements exactly the registration pattern this section documented (LanguageModelCommonContainerFactory.register_services_in_container()). - Environment Variables (
LanguageModelCommonEnvironmentVariables) section — deleted.languagemodelcommon/utilities/environment/language_model_common_environment_variables.pyexists and is the sanctioned way to access env vars in this codebase (used widely, per verifier grep counts of 80+ references). - "Keyword arguments are mandatory in Python code" rule — deleted. Verified: 17+ files and 25+ call sites in
languagemodelcommon/use*,-style keyword-only signatures, so this convention is still actively enforced in the code even though the instruction describing it is gone. - "Don't Guess Commands" reverted — the pre-sync text correctly pointed agents at
pyproject.toml/uv.lock("This repo usesuv"). The synced version reverts this toMakefile, package.json scripts, build.gradle, or Pipfile. I confirmedpyproject.tomlanduv.lockexist at the repo root and noPipfileexists — so post-sync, the file actively misdirects an agent toward tooling this repo does not use, while removing the correct guidance. - Branch Protection section — deleted, removing the explicit warning against direct commits/pushes to
main.
Why this happens
The sync process appears to pull the org-wide AGENTS.md baseline from icanbwell/.github and overwrite the local file wholesale, rather than merging/preserving repo-specific additions layered on top of the baseline. Since CLAUDE.md is a symlink to AGENTS.md in this repo (per the PR description), there is no separate repo-level override file where this content could have survived — the single shared file lost its repo-specific layer entirely.
Why nothing else catches this
This is a documentation/instruction file, not code, so it has no tests, no linter, and no CI check that would flag semantic loss of content during a sync. The file's own stated precedence rule ("repo-level instruction files ... may add stricter requirements or repo-specific context but must not weaken or contradict these directives... Repo-level overrides may only tighten rules, never loosen them") is aspirational text inside the very file that just violated it — nothing enforces it mechanically.
Impact
Future AI agents (Claude Code, Copilot, etc.) working in this repo after this PR merges will no longer be told about the IoC container registration pattern, the environment-variable access class, the keyword-only-argument convention, or the branch protection constraint — even though all four are still real, active conventions in the codebase. Worse, for the "Don't Guess Commands" section, the agent is now given an actively wrong pointer (Pipfile) for a repo that uses uv/pyproject.toml, which could cause it to search for or reference tooling that doesn't exist.
Proof (step-by-step)
- Check out the repo at the merge commit (
a55878e). find . -name container_factory.py→ returnslanguagemodelcommon/container/container_factory.py— exists, and is still used the way the deleted section describes.find . -name language_model_common_environment_variables.py→ returnslanguagemodelcommon/utilities/environment/language_model_common_environment_variables.py— exists.ls pyproject.toml uv.lock→ both present at repo root.ls Pipfile→ "No such file or directory".- Read
AGENTS.mdpost-sync, "Don't Guess Commands" section → now says "Check the Makefile, package.json scripts, build.gradle, or Pipfile" — thepyproject.toml/uv.lock/uvreference from the pre-sync file is gone, and the file instead names a build tool (Pipfile) that does not exist in this repo. - Read the diff hunks at lines 121-126, 168-173, 302-307 → each is a pure deletion (
-lines only, no matching+re-addition elsewhere), confirming content loss rather than relocation.
Suggested fix
Re-apply the four repo-specific sections on top of the synced org baseline — ideally by restructuring so CLAUDE.md/AGENTS.md is not purely a passthrough symlink to the org file, but instead has a small repo-level override/addendum section (as the file's own precedence model already assumes exists) that survives future syncs.
|
|
||
| Let me check if there's an existing FDR for this... | ||
|
|
||
| [Search Confluence via Atlassian MCP: | ||
| cloudId: dc9c52d9-3f1d-4037-9c66-a57f1079b857 | ||
| cql: "type=page AND space=ENTARCH AND title~'FDR' AND title~'MedicationRequest'" | ||
| ] |
There was a problem hiding this comment.
🟡 fhir-resource-design/SKILL.md:42 hardcodes a literal Confluence cloudId (dc9c52d9-3f1d-4037-9c66-a57f1079b857) in its FDR-search example, which directly contradicts the sibling tech-design and tech-design-review skills added in this same PR that explicitly say to discover the cloudId at runtime via getAccessibleAtlassianResources and 'never hardcode it.' Separately, design-doc-trigger/SKILL.md:392 tells the agent to 'See AGENTS.md for current icanbwell Atlassian cloudId,' but AGENTS.md contains no literal cloudId anywhere — only dynamic-fetch instructions — so that pointer is dangling. Recommend replacing the hardcoded value with a runtime-discovery instruction and fixing the AGENTS.md pointer to describe the dynamic-fetch flow instead.
Extended reasoning...
This PR adds a set of new Claude Code skill files (tech-design, tech-design-review, fhir-resource-design, design-doc-trigger, etc.) that guide an AI agent through b.well's architecture-review processes, including how to query Atlassian (Confluence/Jira) via MCP tools. Two of these new skills — tech-design/SKILL.md and tech-design-review/SKILL.md — establish an explicit rule for handling the Atlassian cloudId: discover it at runtime via getAccessibleAtlassianResources and never hardcode it, because orgs can have multiple cloud instances and a stale or wrong hardcoded id would silently misdirect Confluence/Jira queries to the wrong (or a decommissioned) site.
A third skill added in the exact same PR, fhir-resource-design/SKILL.md, violates that rule in its own worked example. Line 42 (verified directly against the file) reads:
\ncloudId: dc9c52d9-3f1d-4037-9c66-a57f1079b857\ncql: "type=page AND space=ENTARCH AND title~'FDR' AND title~'MedicationRequest'"\n
An agent following this skill's example verbatim — which is exactly what these instructional skill files are designed for the agent to do — would query Confluence with a hardcoded cloudId instead of resolving it dynamically, exactly the failure mode the sibling skills were written to prevent. Since all three files are new and shipped in the same PR, this isn't a case of an old file lagging behind a newly introduced rule; the contradiction is baked in at merge time.
Separately, design-doc-trigger/SKILL.md (also new in this PR) tells the agent, in its MCP Integration section: 'CloudId: See AGENTS.md for current icanbwell Atlassian cloudId (public instance identifier).' I grepped AGENTS.md directly and confirmed it contains no literal cloudId UUID anywhere — the only cloudId-related content is the dynamic-discovery instructions ('Get cloudId: mcp__plugin_atlassian_atlassian__getAccessibleAtlassianResources()' and the placeholder cloudId: "<from-step-1-above>"). An agent told to 'see AGENTS.md for the cloudId' will find instructions for fetching it, not a value — the pointer is dangling/misleading as written.
Proof by direct inspection:
grep -n 'dc9c52d9' .claude/skills/fhir-resource-design/SKILL.md→ line 42, the only hit for this literal UUID in the whole PR.- tech-design-review/SKILL.md and tech-design/SKILL.md both contain the phrase 'never hardcode it' next to
getAccessibleAtlassianResources. grep -n 'cloudId' AGENTS.md→ all four hits are about the dynamic-fetch flow (lines 362-389); none is a literal id.- design-doc-trigger/SKILL.md's 'CloudId: See AGENTS.md...' line therefore points to nothing concrete.
Impact is limited to agent-guidance quality (these are instructional Markdown files consumed by the AI assistant, not runtime application code), so nothing breaks at build or deploy time. But the whole point of these skill files is to steer agent behavior correctly and consistently, and here the PR ships self-contradictory guidance plus a broken cross-reference in the very same commit that introduced the 'never hardcode' rule. The fix is small: replace the literal cloudId in fhir-resource-design/SKILL.md's example with a runtime-discovery call (matching the sibling skills), and either inline the discovery instructions in design-doc-trigger/SKILL.md or point it at the correct dynamic-fetch section of AGENTS.md rather than implying a static value lives there.
|
Closing — opened by an aborted org-wide instruction-sync run. The sync's content-clobber gap is fixed and approved in icanbwell/.github#28, and the corrected sync will also ship the knowledge-substrate dirs the skills reference. A clean sync re-runs after #28 merges; no action needed. Branch deleted. |
Architecture Instruction File Sync
This PR updates the organization-wide AI agent instruction baseline files from
icanbwell/.github.Changes
Source commit: 62f8288431418749382e0b673b363841d8f8977d
Review Notes
Review and merge when ready. These are org-wide architecture instruction updates from EA team. These files are purely additive and don't modify existing code.
Related: EA-2130