diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index da1e5897..0c8ac67c 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -59,22 +59,35 @@ You are operating in a multi-repo, documentation-first architecture. You MUST ST 5. **EXPLICIT CONSENT FOR MODIFICATIONS:** NEVER rewrite, create, or delete any file (code, documentation, configuration, memory, or otherwise) without the user's explicit permission. If the user does not specifically request a code modification (e.g., using phrases like "we are just thinking," "what do you think," "let's plan"), you MUST ONLY provide text-based analysis and planning. You are FORBIDDEN from using file-modifying tools (`replace_string_in_file`, `edit_file`, `create_file`, etc.) until the user explicitly says "ok", "go ahead", "implement", or a similar unambiguous approval. +6. **AUTHORITY, RULE SCOPE, AND SKILL INVOCATION:** + When proposing structural changes (new files, conventions, categories, IDs, naming patterns, URL schemes, etc.), follow these three principles: + + - **Authority before proposal:** Before proposing new structures, conventions, categories, or IDs, verify the proposal against the **authoritative source** for that domain. If a registry, convention doc, or canonical reference exists, follow it (or its registered maintenance workflow for new entries). Do not invent ad-hoc when an authority exists. + + - **Rule implications are part of the rule:** Rules have **scope implications** beyond their literal text. Apply rules **conservatively** — if a rule prohibits action X, do not work around it with novel patterns Y that achieve the same effect. Working around rule scope with ad-hoc patterns is a process violation, not a creative solution. + + - **Skill invocation preferred over reimplementation:** If a workspace skill's scope covers the current task, **invoke the skill explicitly** rather than manually performing similar steps. Skills canonicalize subtleties (validation rules, cross-references, edge cases) that ad-hoc reimplementation risks missing. Improvising a skill's logic is a process violation. + ## Session Setup -**Mandatory reads at session start** — in addition to this `copilot-instructions.md`, the agent MUST load the four workspace skills' `SKILL.md` files: +**Mandatory reads at session start** — in addition to this `copilot-instructions.md`, the agent MUST load the **two reactive workspace skills' `SKILL.md` files** (the three user-gated skills are lazy-loaded on demand — see notes below): - `docs-discovery/SKILL.md` — **reactive** (triggers on any domain question — must be ready BEFORE the first domain query arrives) - `docs-check/SKILL.md` — **reactive** (triggers at the end of every code-modifying response) -- `protocol-audit/SKILL.md` — **on-demand** (triggers on explicit "audit protocol" command) -- `adr-author/SKILL.md` — **on-demand + LLM-suggested** (triggers on explicit planning/design requests, or when the LLM flags an ADR-worthy conversation and the user confirms) + +The remaining three skills are **lazy-loaded** — `SKILL.md` is read on demand at invocation, not at session start. The 1-2 line summaries in `## Shared Agent Skills` below are sufficient for trigger recognition; the full skill content loads only when needed: + +- `protocol-audit/SKILL.md` — user-invoked ("audit protocol"); LLM-suggest-back when a `.github/copilot-instructions.md` or `SKILL.md` is modified during the session. +- `adr-author/SKILL.md` — user-invoked ("let's plan X", "design Y"); LLM-suggest-back on ADR-worthy conversation drift. +- `docs-archive/SKILL.md` — user-invoked ("archive ISSUES", "rotate logs"); LLM-suggest-back when active `_ISSUES.md` / `_TODO.md` / DEC log shows many closed prior entries. **Path resolution**: if this repo is the canonical protocol host (see `@repo` block below — typically AyCode.Core), the paths are local: `.github/skills//SKILL.md`. Otherwise, prefix with this repo's `own-dep-repos` AyCode.Core path (see the `## Shared Agent Skills` section below for explicit paths). -**Why mandatory**: workspace skills are NOT in Claude Code's native skill-registry / system-reminder. Without pre-loading their `SKILL.md` content, the agent cannot reliably recognize implicit triggers (e.g., "domain question → invoke docs-discovery" at the moment the question arrives, not retroactively). Pre-loading is a **one-time cost** per session (~10-13K tokens); Rule #3 (no-re-read) prevents repeated reads; re-read only if Rule #4 (Context Recovery) fires. +**Why mandatory**: workspace skills live as plain `SKILL.md` files in `.github/skills/` — LLMs do NOT auto-discover them via any built-in skill-registry. Without pre-loading their `SKILL.md` content, the agent cannot reliably recognize implicit triggers (e.g., "domain question → invoke docs-discovery" at the moment the question arrives, not retroactively). Pre-loading is a **one-time cost** per session (~5-8K tokens for the 2 reactive `SKILL.md` files; the 3 user-gated skills are lazy-loaded — no upfront cost); Rule #3 (no-re-read) prevents repeated reads; re-read only if Rule #4 (Context Recovery) fires. **Amortization — critical, do NOT re-evaluate per-turn**: the Session Setup cost is measured over the ENTIRE session, not per single turn. A typical session has many turns; the first domain question alone already recoups the investment (alternative — repeated source-code `Grep`/`Read` per turn — costs 10-20K tokens *per turn* with lower output quality). Do NOT flag pre-loaded content as "wasteful" for turns that don't invoke it — the design depends on cross-turn amortization + Rule #3 (no-re-read) + on-demand specificity of Rule #4 (Context Recovery). This amortization is the **central token-economics principle** of the entire protocol stack. -The first response's `[LOADED_DOCS: ...]` prefix must reflect **5 files** (this `copilot-instructions.md` + 4 SKILL.md). +The first response's `[LOADED_DOCS: ...]` prefix must reflect **3 files** (this `copilot-instructions.md` + 2 reactive SKILL.md). Lazy-loaded skills add to the count when invoked. ## Workspace Dependencies # own-dep-repos: "name: path" — paths are relative to this repo root (.github/..) @@ -99,7 +112,7 @@ The first response's `[LOADED_DOCS: ...]` prefix must reflect **5 files** (this ## Shared Agent Skills -Skills defined in other repos. **All four are pre-loaded at session start per the `## Session Setup` section above** (mandatory — ensures implicit triggers fire reliably): +Skills defined in other repos. **Two reactive skills are pre-loaded at session start; three user-gated skills are lazy-loaded on demand** — see `## Session Setup` above for the load matrix: - **protocol-audit** — Cross-repo consistency audit for `.github/copilot-instructions.md` across all 5 repos. Location: `AyCode.Core/.github/skills/protocol-audit/SKILL.md` @@ -117,6 +130,10 @@ Skills defined in other repos. **All four are pre-loaded at session start per th Location: `AyCode.Core/.github/skills/adr-author/SKILL.md` **Invoke on explicit user request** ("let's plan X", "decide Y vs Z", "design the W module") **or proactively flag** when the conversation looks ADR-worthy (user must confirm — never auto-invoke). +- **docs-archive** — Rotate closed entries (Status: Fixed/Resolved/Won't fix/Superseded by X) from active `_ISSUES.md`, `_TODO.md`, and `LLM_PROTOCOL_DECISIONS.md` into year-bucketed archive companions (`*_.md`). Year of the Status update determines destination file. Active files retain only Open/Partially Fixed entries plus a pointer to the archives. Archive files are NOT auto-loaded — agents read them on-demand when historical context becomes relevant. + Location: `AyCode.Core/.github/skills/docs-archive/SKILL.md` + **Invoke on explicit user request** ("archive ISSUES", "rotate logs") **or proactively flag** when an active artifact file has many closed prior entries (user must confirm — never auto-invoke). + ## Protocol History Cumulative log of LLM-protocol decisions (rule changes, new skills, structural shifts): diff --git a/FruitBankHybrid.Shared/FruitBankHybrid.Shared.csproj b/FruitBankHybrid.Shared/FruitBankHybrid.Shared.csproj index 23279bd2..afd1b00e 100644 --- a/FruitBankHybrid.Shared/FruitBankHybrid.Shared.csproj +++ b/FruitBankHybrid.Shared/FruitBankHybrid.Shared.csproj @@ -76,4 +76,17 @@ + + + + Never + Never + false + + + \ No newline at end of file diff --git a/FruitBankHybrid.Shared/README.md b/FruitBankHybrid.Shared/README.md index 08bfb4e5..9076e347 100644 --- a/FruitBankHybrid.Shared/README.md +++ b/FruitBankHybrid.Shared/README.md @@ -27,6 +27,7 @@ Main Blazor UI library shared across all three deployment targets (Server, WASM, - **`_Imports.razor`** — Global Blazor imports. - **`Routes.razor`** — Route definitions. +- **`appsettings.json`** — Canonical configuration source for all three hosts (Web, Web.Client, MAUI). Edit ONLY here. Pull mechanism per host: see `docs/ARCHITECTURE.md` (in repo root) → "Shared Configuration". ## Target Framework diff --git a/FruitBankHybrid.Shared/appsettings.json b/FruitBankHybrid.Shared/appsettings.json index b59b8e20..e8b753b9 100644 --- a/FruitBankHybrid.Shared/appsettings.json +++ b/FruitBankHybrid.Shared/appsettings.json @@ -7,10 +7,10 @@ }, "AyCode": { "ProjectId": "aad53443-2ee2-4650-8a99-97e907265e4e", - "Urls": { - "BaseUrl": "https://localhost:7144", - "ApiBaseUrl": "https://localhost:7144" - }, + "Urls": { + "BaseUrl": "https://localhost:59579", + "ApiBaseUrl": "https://localhost:59579" + }, "Logger": { "AppType": "Server", "LogLevel": "Detail", @@ -38,7 +38,7 @@ "AcBinaryHubProtocol": { "ProtocolMode": "AsyncSegment", "BufferSize": 4096, - "WaitForFlush": false, + "WaitForFlush": true, "FlushTimeout": "00:00:10" } } diff --git a/FruitBankHybrid.Web.Client/wwwroot/appsettings.json b/FruitBankHybrid.Web.Client/wwwroot/appsettings.json index b59b8e20..e8b753b9 100644 --- a/FruitBankHybrid.Web.Client/wwwroot/appsettings.json +++ b/FruitBankHybrid.Web.Client/wwwroot/appsettings.json @@ -7,10 +7,10 @@ }, "AyCode": { "ProjectId": "aad53443-2ee2-4650-8a99-97e907265e4e", - "Urls": { - "BaseUrl": "https://localhost:7144", - "ApiBaseUrl": "https://localhost:7144" - }, + "Urls": { + "BaseUrl": "https://localhost:59579", + "ApiBaseUrl": "https://localhost:59579" + }, "Logger": { "AppType": "Server", "LogLevel": "Detail", @@ -38,7 +38,7 @@ "AcBinaryHubProtocol": { "ProtocolMode": "AsyncSegment", "BufferSize": 4096, - "WaitForFlush": false, + "WaitForFlush": true, "FlushTimeout": "00:00:10" } } diff --git a/FruitBankHybrid.Web/appsettings.json b/FruitBankHybrid.Web/appsettings.json index b59b8e20..8ee8b7b3 100644 --- a/FruitBankHybrid.Web/appsettings.json +++ b/FruitBankHybrid.Web/appsettings.json @@ -7,10 +7,10 @@ }, "AyCode": { "ProjectId": "aad53443-2ee2-4650-8a99-97e907265e4e", - "Urls": { - "BaseUrl": "https://localhost:7144", - "ApiBaseUrl": "https://localhost:7144" - }, + "Urls": { + "BaseUrl": "https://localhost:59579", + "ApiBaseUrl": "https://localhost:59579" + }, "Logger": { "AppType": "Server", "LogLevel": "Detail", diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 2d4ec719..40c884e1 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -51,6 +51,18 @@ nopCommerce 4.80.9 requires .NET 9 All three share the same UI components from `FruitBankHybrid.Shared`. +## Shared Configuration + +`FruitBankHybrid.Shared/appsettings.json` is the **canonical configuration source** for all three hosts. Edits go ONLY into the Shared file — never edit the host-side copies (they are build artifacts). Each host pulls it from disk via a different mechanism; the Razor SDK auto-publish behavior is suppressed in `FruitBankHybrid.Shared.csproj` to avoid NETSDK1152 ("multiple publish output files with the same relative path") collisions when the Shared file would otherwise also flow into each host's publish output through the project reference. + +| Host | How it pulls the config | Resulting path | +|---|---|---| +| `FruitBankHybrid.Web` | `` (`BeforeBuild`) | `appsettings.json` (project root, ASP.NET Core ContentRoot) | +| `FruitBankHybrid.Web.Client` | `` (multiple early `BeforeTargets`) | `wwwroot/appsettings.json` (static web asset) | +| `FruitBankHybrid` (MAUI) | `` | manifest resource — loaded via `GetManifestResourceStream` in `MauiProgram.cs` | + +A clean build (delete `obj/`) is required the first time on Web.Client because the static-asset manifest is cached in `obj/`. + ## Data Flow ```