From c062ded9a47e753a10b67fb00febf55a88d0656c Mon Sep 17 00:00:00 2001 From: Loretta Date: Sun, 26 Apr 2026 19:12:50 +0200 Subject: [PATCH] [LOADED_DOCS: 3 files, no new loads] Update ID format to use per-repo prefixes and random suffix Migrated all issue, TODO, and decision IDs to a new 4-part format: ---. Added per-repo prefix declarations in copilot-instructions.md and documented conventions in REPO_PREFIXES.md. Updated all topic registries, logs, cross-references, and documentation to use the new format. Introduced MIGRATION_ID_MAPPING.md for old-to-new ID mapping. Enhanced skills and protocol audit logic to validate and enforce per-repo prefixes and topic codes at runtime. Clarified Framework-First doctrine and ensured all references are unambiguous. --- .github/LLM_PROTOCOL_DECISIONS.md | 46 ++-- .github/MIGRATION_ID_MAPPING.md | 236 ++++++++++++++++++ .github/REPO_PREFIXES.md | 106 ++++++++ .github/copilot-instructions.md | 9 +- .github/skills/adr-author/SKILL.md | 2 +- .../adr-author/references/ADR_TEMPLATE.md | 2 +- .github/skills/docs-archive/SKILL.md | 2 +- .github/skills/docs-check/SKILL.md | 21 +- .../docs-check/references/TOPIC_CODES.md | 115 +++++---- .github/skills/docs-discovery/SKILL.md | 16 +- .github/skills/protocol-audit/SKILL.md | 37 ++- .../skills/protocol-audit/references/REPOS.md | 88 +++---- .../docs/BINARY/BINARY_IMPLEMENTATION.md | 8 +- AyCode.Core/docs/BINARY/BINARY_ISSUES.md | 46 ++-- AyCode.Core/docs/BINARY/BINARY_SGEN.md | 6 +- AyCode.Core/docs/BINARY/BINARY_TODO.md | 22 +- AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md | 68 ++--- AyCode.Core/docs/LOGGING/LOGGING_TODO.md | 44 ++-- AyCode.Core/docs/LOGGING/README.md | 4 +- AyCode.Core/docs/TOON/README.md | 2 +- AyCode.Core/docs/TOON/TOON_IMPLEMENTATION.md | 2 +- AyCode.Core/docs/TOON/TOON_INFERENCE.md | 2 +- AyCode.Core/docs/TOON/TOON_ISSUES.md | 8 +- AyCode.Core/docs/TOON/TOON_TODO.md | 24 +- AyCode.Core/docs/XCUT/README.md | 25 +- AyCode.Core/docs/XCUT/XCUT_ISSUES.md | 10 +- AyCode.Services/docs/SIGNALR/README.md | 2 +- .../docs/SIGNALR/SIGNALR_ISSUES.md | 32 +-- AyCode.Services/docs/SIGNALR/SIGNALR_TODO.md | 26 +- .../SIGNALR_BINARY_PROTOCOL_ISSUES.md | 4 +- .../SIGNALR_BINARY_PROTOCOL_TODO.md | 22 +- ...acbinary-decorator-feature-stack-design.md | 14 +- docs/AUTH/AUTH_ISSUES.md | 2 +- docs/AUTH/README.md | 4 +- docs/CONVENTIONS.md | 2 +- docs/adr/0001-user-bearer-token-flow.md | 14 +- 36 files changed, 738 insertions(+), 335 deletions(-) create mode 100644 .github/MIGRATION_ID_MAPPING.md create mode 100644 .github/REPO_PREFIXES.md diff --git a/.github/LLM_PROTOCOL_DECISIONS.md b/.github/LLM_PROTOCOL_DECISIONS.md index bba6d6a..04ef336 100644 --- a/.github/LLM_PROTOCOL_DECISIONS.md +++ b/.github/LLM_PROTOCOL_DECISIONS.md @@ -6,7 +6,7 @@ Append-only log of decisions about the AI AGENT CORE PROTOCOL and related LLM to ## Current protocol state (quick reference) -Active as of **2026-04-24**. For the full evolution history, see the dated table near the bottom of this file. Read this summary first to orient yourself before diving into the dated entries. +Active as of **2026-04-26**. For the full evolution history, see the dated table near the bottom of this file. Read this summary first to orient yourself before diving into the dated entries. **Session start flow**: - **Primary files**: agent reads `copilot-instructions.md` + 3 SKILL.md files (`docs-discovery`, `docs-check`, `protocol-audit`). First response's `[LOADED_DOCS: ...]` shows 4 files. @@ -27,22 +27,29 @@ Active as of **2026-04-24**. For the full evolution history, see the dated table - Project-specific variants of framework topics (e.g., the server-side logger in `AyCode.Core.Server`, the Nop bridge in `Mango.Nop.Services`) get their own `TOPIC/README.md` under the variant project's `docs/`. - `.csproj` files use recursive glob: `` so Pattern B nesting auto-shows in Visual Studio Solution Explorer without manual entries. -**Instruction files — 8 total**: +**Instruction files — 7 total** (was 8 before LLMP-DEC-51 / `Mango.FruitBank` deployment-host folder removal; deployment-context re-attributed to `FruitBank` per LLMP-DEC-52): - **5 primary** files contain the full numbered AI AGENT CORE PROTOCOL: `AyCode.Core`, `AyCode.Blazor`, `Libraries`, `FruitBank` (Mango/Source), `FruitBankHybridApp`. -- **3 inherit** files reference AyCode.Core's protocol via blockquote (no duplicated numbered rules): `Mango.Nop.Core` (sub-project framework), `Nop.Plugin.Misc.AIPlugin` (plugin source), `Mango.FruitBank` (nopCommerce deployment host). +- **2 inherit** files reference AyCode.Core's protocol via blockquote (no duplicated numbered rules): `Mango.Nop.Core` (sub-project framework), `Nop.Plugin.Misc.AIPlugin` (plugin source). - Each non-Core file has `## Shared Agent Skills` + `## Protocol History` sections. +- **Per-repo `prefix` field** (LLMP-DEC-58): every `@repo` block declares its own ID-prefix (`prefix = "ACCORE"`, `"ACBLAZOR"`, `"MGNOPLIB"`, `"MGNOPCORE"`, `"MGFBANKPLUG"`, `"FBANKNOP"`, `"FBANKAPP"` — 7 prefixes, 1 per repo). +- **`.github/` files follow Framework-First** (LLMP-DEC-58 narrows the previous workspace-meta-tooling exception): each repo declares its own info (prefix, topics, etc.); only `LLM_PROTOCOL_DECISIONS.md` (workspace-meta history) and transient migration artifacts (`MIGRATION_ID_MAPPING.md`) may cross layers. Cross-layer awareness in tooling uses runtime discovery via `own-dep-repos` walking, not centralized listings. -**Issue / TODO / Decision ID format** (globally unique): -- Format: `{TOPIC}-{TYPE}-{N}` (e.g., `LOG-I-5`, `SIG-T-3`, `BIN-B-1`, `XCUT-I-1`, `LLMP-DEC-4`) -- **Topic codes**: `LOG` (logger), `SIG` (SignalR), `SBP` (SignalR binary protocol), `BIN` (binary serializer), `TOON` (Toon serializer), `GRID` (MGGRID), `XCUT` (cross-cutting), `LLMP` (LLM-protocol meta — uses `DEC` type only). -- **Type codes**: `I` = issue, `T` = TODO, `B` = bug, `C` = critical (severity override), `DEC` = decision (LLMP-only). -- **Counter scope**: per (topic, type) pair. `LOG-I-1` and `LOG-T-1` independent. -- **Append-only**: IDs never change once assigned. Full registry + rules: `AyCode.Core/.github/skills/docs-check/references/TOPIC_CODES.md`. +**Issue / TODO / Decision ID format** (globally unique, 4-component as of LLMP-DEC-50..59): +- Format: `---` (e.g., `ACCORE-LOG-I-K7M2`, `ACCORE-SIG-T-D7Q4`, `ACCORE-BIN-B-XXXX`, `ACCORE-XCUT-I-X8Q1`, `ACBLAZOR-GRID-T-V4P7`, `LLMP-DEC-50`). +- **``** (repo namespace): declared per-repo in `copilot-instructions.md` `@repo` block (`prefix = "..."` field, LLMP-DEC-58). Format spec + the framework's own `ACCORE` listing: `AyCode.Core/.github/REPO_PREFIXES.md`. Higher-layer prefixes are declared in their own repos (Framework-First — no central enumeration). +- **``** (framework / ACCORE topics): `LOG` (logger), `AUTH` (authentication), `SIG` (SignalR), `SBP` (SignalR binary protocol), `BIN` (binary serializer), `TOON` (Toon serializer), `XCUT` (cross-cutting within ACCORE), `LLMP` (LLM-protocol meta — bare format, no prefix). Higher-layer topics live in each repo's own `/.github/TOPIC_CODES.md` (e.g., AyCode.Blazor's `GRID`); see `AyCode.Core/.github/skills/docs-check/references/TOPIC_CODES.md` for the per-repo extension convention. +- **``** (universal): `I` = issue, `T` = TODO, `B` = bug, `C` = critical (severity override), `DEC` = decision (LLMP-only). +- **``** (random suffix): 4-char `[A-Z0-9]`; ~1.7M combinations per `--` triplet. Generated at entry creation; uniqueness verified via glob over active + archive files; collision triggers regeneration. **Avoids parallel-branch ID-collisions at merge time.** +- **LLMP exception**: `LLMP-DEC-N` entries (workspace-meta Decision Log) skip the prefix and use sequential `N` — single-file serialization avoids parallel-branch concern. Bare format `LLMP-DEC-1`, `LLMP-DEC-2`, ... +- **Cross-repo search**: prefix-wildcard glob (`*-LOG-I-*`, `*-XCUT-I-*`) finds all matches workspace-wide, no central index needed (LLMP-DEC-55 — `docs-discovery/SKILL.md` Cross-repo ID search section). +- **Append-only**: IDs never change once assigned. Hash anchors in markdown cross-refs use lowercase: `LOGGING_ISSUES.md#accore-log-i-k7m2`. -**Agent skills — all three at `AyCode.Core/.github/skills/`**: -- **`docs-discovery`** — extracts topic tokens from user requests, globs `**/docs/TOPIC/**/*.md` (+ companion patterns), loads the paired main+ISSUES+TODO set before source-code search. Updates LOADED_DOCS via Rule #1 format. -- **`protocol-audit` v2.2** — reads `references/REPOS.md` and audits all 8 instruction files: Common invariants C1-C4 for all (C4 = `## Session Setup` presence, added in LLMP-DEC-33); Primary-only (P1-P10) for the 5 primary; Inherit-only (I1-I3) for the 3 inherit; Cross-cutting (X1, X3) for primary, (X1, X2) for non-Core primary, (X1, X2) for inherit. Reports PASS/FAIL per invariant-file cell, with patch suggestions. Does NOT auto-apply patches. -- **`docs-check` v1.0** — end-of-code-modifying-response skill: evaluates loaded `.md` for drift vs code, missing topic coverage, csproj-glob registration gaps, and new issue/TODO candidates. Emits the `[DOCUMENTATION CHECK]` section (or `[DOCUMENTATION CHECK] None.` single-line). Read-only on loaded docs; all patches as proposals per Rule #5. +**Agent skills — five at `AyCode.Core/.github/skills/`** (2 reactive pre-loaded at session start per LLMP-DEC-43; 3 user-gated lazy-loaded on demand): +- **`docs-discovery`** (reactive) — extracts topic tokens from user requests, globs `**/docs/TOPIC/**/*.md` (+ companion patterns), loads the paired main+ISSUES+TODO set before source-code search. Cross-repo wildcard search for ID-pattern matches (`*-LOG-I-*` etc.) added in LLMP-DEC-55. Updates LOADED_DOCS via Rule #1 format. +- **`docs-check`** (reactive) — end-of-code-modifying-response skill: evaluates loaded `.md` for drift vs code, missing topic coverage, csproj-glob registration gaps, and new issue/TODO candidates. Emits the `[DOCUMENTATION CHECK]` section (or `[DOCUMENTATION CHECK] None.` single-line). Read-only on loaded docs; all patches as proposals per Rule #5. +- **`protocol-audit`** (user-gated) — audits `.github/copilot-instructions.md` files discovered via runtime walk of `own-dep-repos` from the invocation point (LLMP-DEC-58 redesign — was central-`REPOS.md` driven before). Common invariants C1-C4 for all (C1: 5 required `@repo` fields incl. `prefix`; C3: `prefix` format check, repurposed in LLMP-DEC-58); Primary-only (P1-P10) for files content-classified as primary; Inherit-only (I1-I3) for inherit files; Cross-cutting (X1, X2, X3). Reports PASS/FAIL per invariant-file cell with patch suggestions. Does NOT auto-apply patches. +- **`adr-author`** (user-gated) — Architecture Decision Record authoring; structured interview producing `docs/adr/NNNN-.md` (product decisions) or new `LLMP-DEC-N` row (meta-protocol decisions). +- **`docs-archive`** (user-gated) — rotates `Status: Closed` entries from active `_ISSUES.md` / `_TODO.md` / `LLM_PROTOCOL_DECISIONS.md` into year-bucketed archive files; archive-time collision-check on random suffix. **Docs-sync enforcement (`[DOCUMENTATION CHECK]` at end of code-modifying responses)**: - **Keep all .md in sync** — if code and loaded docs disagree, notify and ask (do NOT silently edit). @@ -96,8 +103,8 @@ Quick lookup for **why** a rule is the way it is, to avoid: |------------------------|-----------------------------------------------------------------------------------------------------------| | `5× primary` | All 5 primary `copilot-instructions.md` (AyCode.Core, AyCode.Blazor, Libraries, FruitBank, FruitBankHybridApp) | | `4× non-Core primary` | The 4 primary files except AyCode.Core | -| `3× inherit` | The 3 inherit files (Mango.Nop.Core, Nop.Plugin.Misc.AIPlugin, Mango.FruitBank) | -| `all 8` | All 8 files: 5 primary + 3 inherit | +| `2× inherit` | The 2 inherit files (Mango.Nop.Core, Nop.Plugin.Misc.AIPlugin) — was 3× before LLMP-DEC-51 | +| `all 7` | All 7 files: 5 primary + 2 inherit (was `all 8` before LLMP-DEC-51) | | `/...` | A single specific file path | | `/...` | Skill directory under `.github/skills/` | @@ -160,6 +167,15 @@ The "primary" vs "inherit" distinction is defined in `protocol-audit/references/ | LLMP-DEC-50 | 2026-04-26 | New Rule #6 added to all primary `copilot-instructions.md` — Authority, Rule scope, Skill invocation (3 general behavioral principles) | **Diagnosis from real-world session evidence**: a parallel session reviewing FruitBank plugin docs surfaced 5 distinct misinterpretation patterns: (1) inventing topic codes ad-hoc without consulting the canonical registry; (2) proposing TOC-with-offset re-read patterns that work around the no-re-read rule's scope; (3) inventing custom URL schemes (`@Repo:`) outside markdown standard; (4) proposing empty `_ISSUES.md` files without applying the established Status convention; (5) manually reimplementing a skill's workflow instead of invoking the skill. Five distinct surfaces, **one root cause**: the session knew skills/rules existed at the surface but did not follow references to depth, did not treat authoritative registries as binding, and improvised over canonicalized procedures. **Plus self-evidence**: this assistant slipped THREE times using `vN.M` version-label colloquialism in conversation despite LLMP-DEC-47 explicitly forbidding the pattern — proof that Decision Log entries alone do NOT propagate to behavior. Decision Log governance is not session-start mandatory load; rules in `copilot-instructions.md` are. **Fix**: codify three **general** behavioral principles as Rule #6 in all 5 primary `copilot-instructions.md` files. (a) **Authority before proposal** — verify against authoritative source before inventing categories/IDs/conventions. (b) **Rule implications are part of the rule** — apply rules conservatively, don't work around scope with novel patterns. (c) **Skill invocation preferred over reimplementation** — invoke skills explicitly rather than ad-hoc reimplementation. **General, not workspace-specific**: the rule text mentions NO specific registry, skill, convention, or workspace artifact — it states principles applicable to any registry, any skill, any future workspace. **Why Rule #6, not Rule #2 extension**: Rules #1-5 are state/input/output mechanics (LOADED_DOCS prefix, docs-before-code, no-re-read, context-recovery, modification consent); Rule #6 is **behavioral correctness** of how proposals are formed — separate functional category, separate rule. **Coverage**: Authority covers misinterpretations 1, 3, 4; Rule implications covers 2; Skill invocation covers 5 — full 5/5 of observed patterns. **Why this might still not be enough**: even codified rules slip in agent behavior (the v-label evidence). Multi-LLM independent validation remains structurally necessary as the final safety net; rule-text shifts the probability, doesn't reach 100%. | `5× primary copilot-instructions.md` (new Rule #6 inserted after Rule #5, before `## Session Setup`) | | LLMP-DEC-51 | 2026-04-26 | Removed `Mango/FruitBank/` deployment-host folder — REPOS.md inherit count 3 → 2, total 8 → 7 | The `Mango/FruitBank/` folder was originally created (LLMP-DEC-16, LLMP-DEC-19) as a nopCommerce deployment host for the FruitBank company, intended to host `Nop.Plugin.Misc.AIPlugin`. User confirmed the folder is no longer used — empty except for the legacy `.github/copilot-instructions.md`. **Pre-removal content audit**: the file contained only deployment-host meta (host-role description, `@repo` block declaring `type=host, layer=4`, scope-guidance for what NOT to write here, pointers to plugin and framework docs). NO substantive content about the plugin (later renamed MGFBANKPLUG) or FruitBank-Nop code (later renamed FBANKNOP) — pure host-side metadata, irrelevant once the host doesn't exist. **Removed**: `Mango/FruitBank/.github/copilot-instructions.md`, the `.github/` folder, and the parent `Mango/FruitBank/` folder (now empty). **Updated**: `protocol-audit/references/REPOS.md` — inherit count 3 → 2, total entries 8 → 7. **Historical record preserved**: LLMP-DEC-15 (plugin file fill, separate concern), LLMP-DEC-16 (host file fill), LLMP-DEC-19 (host purpose resolution) remain in the Decision Log per append-only governance — they describe a past state of the workspace. **Phase 0.5 of the ID-format migration (LLMP-DEC-50 design context)**: this cleanup is prerequisite to Phase 1, so the upcoming `REPO_PREFIXES.md` reflects the actual 7-repo workspace topology (no MGFBANKHOST prefix needed). | deleted: `Mango/FruitBank/.github/copilot-instructions.md`, `Mango/FruitBank/.github/`, `Mango/FruitBank/`; updated: `protocol-audit/references/REPOS.md` (Inherit table row 8 removed; own-dep-repos Inherit table Mango.FruitBank row removed) | | LLMP-DEC-52 | 2026-04-26 | Corrective addition to LLMP-DEC-51: deployment-host context re-attributed to FBANKNOP (FruitBank nopCommerce Server) docs | **LLMP-DEC-51 over-pruned**: the agent's content audit before deletion concluded "no substantive content to migrate from the `Mango/FruitBank/` folder" — but the user identified that the deployment-context information (this FruitBank product targets a nopCommerce instance hosting `Nop.Plugin.Misc.AIPlugin` plugin for the FruitBank company) IS meaningful workspace-topology information, not pure host-side metadata. The deleted folder's role description and hosted-plugin pointer were workspace-relevant — they document a real relationship between FBANKNOP (the server-source product) and MGFBANKPLUG (the plugin source). Without that info, the workspace loses the explicit "this source compiles and deploys here" relationship statement. **Fix**: added a new `## Deployment & Hosting` section to `Mango/Source/FruitBank/.github/copilot-instructions.md` (FBANKNOP's primary instruction file). The section captures: (a) FBANKNOP is the nopCommerce server source for a runtime instance; (b) the runtime hosts MGFBANKPLUG; (c) deployment config / runtime state is external to source repo; (d) historical note that `Mango/FruitBank/` folder was the previous tracking location, now removed per LLMP-DEC-51, with the deployment-context info now living at FBANKNOP (where the source code resides). **Append-only preserved**: LLMP-DEC-51 itself is NOT modified — this corrective entry stands as the augmentation. **Why FBANKNOP, not MGFBANKPLUG**: per user judgment ("inkább a FBANKNOP a valószínűbb"), the deployment-context is more naturally attached to the broader server source (FBANKNOP) than to the plugin source (MGFBANKPLUG); the plugin is one component within the deployment, not the deployment itself. **Process lesson for future cleanups**: pre-deletion content audits must distinguish between (a) pure folder-meta (irrelevant once folder is gone) and (b) workspace-topology references that survive folder removal — the latter need explicit re-attribution, not deletion. | `Mango/Source/FruitBank/.github/copilot-instructions.md` (new `## Deployment & Hosting` section inserted between `## Workspace Dependencies` and `## Shared Agent Skills`) | +| LLMP-DEC-53 | 2026-04-26 | Phase 1 of ID-format migration: created `REPO_PREFIXES.md` workspace prefix registry | First foundation step of the per-repo prefix namespace migration designed in LLMP-DEC-50. **Created**: `AyCode.Core/.github/REPO_PREFIXES.md` — workspace-meta-tooling registry listing 7 repo prefixes (ACCORE, ACBLAZOR, MGNOPLIB, MGNOPCORE, MGFBANKPLUG, FBANKNOP, FBANKAPP) plus the LLMP-DEC bare exception (workspace-meta, single-file serialization). The registry includes: full ID format spec (`---`), 4-char random alphanumeric suffix `[A-Z0-9]` specification with generation rules (~1.7M combinations per topic-type-prefix triple), archive-time collision detection policy (skill aborts on collision, signals user, manual resolution), cross-references to `TOPIC_CODES.md` and `REPOS.md`, and add/remove workflow with explicit collision-check against C# class-name prefixes. **Workspace-meta-tooling exception preserved**: this registry lists prefixes across all layers (framework, shared libs, consumer products) — Framework-First Design Principle exception per existing convention (mirroring `TOPIC_CODES.md` and `REPOS.md` scope-note). **No entry IDs renamed yet** — this phase is purely the registry creation; existing IDs (LOG-I-N, BIN-I-N, etc.) remain unchanged. Phase 2 (TOPIC_CODES.md scope-note + format-rule update for the new 4-component ID), Phase 3 (skill `SKILL.md` updates with placeholder examples + ID-generation guidance + cross-repo glob), Phase 4 (mapping table — `OLD_ID → NEW_ID`), Phase 5 (per-topic rename of existing entries to new format), Phase 6 (cross-file cross-ref cleanup — ADRs, Decision Log, code comments, hash anchors), Phase 7 (final verification + completion entry) follow per the LLMP-DEC-50 plan. **User pre-Phase 1 commit established a rollback point**: if any phase produces unexpected state, `git reset` to the pre-migration tag is the safety net. | new file: `AyCode.Core/.github/REPO_PREFIXES.md` | +| LLMP-DEC-54 | 2026-04-26 | Phase 2 of ID-format migration: `TOPIC_CODES.md` updated for 4-component ID format and per-repo registry awareness | Phase 2 of the LLMP-DEC-50 migration. Updated `AyCode.Core/.github/skills/docs-check/references/TOPIC_CODES.md` in 8 sections to align with the new prefix scheme established in Phase 1 (LLMP-DEC-53, `REPO_PREFIXES.md`). **Changes**: (a) **Scope note** acknowledges per-repo `TOPIC_CODES.md` possibility (each repo may host its own at `/.github/skills/docs-check/references/TOPIC_CODES.md`); points to `REPO_PREFIXES.md` for the prefix scheme; flags that the legacy multi-repo Topic codes table will migrate in subsequent phases. (b) **Brief intro** updated to reference full 4-component ID format with cross-link to `REPO_PREFIXES.md`. (c) **Why this registry exists** — example IDs upgraded from 3-component (`LOG-I-5`) to 4-component (`ACCORE-LOG-I-K7M2`). (d) **Distinctions section** — `LOG-C-1` example upgraded to `ACCORE-LOG-C-K7M2`. (e) **ID format rules** restructured: 6 rules → 5 rules (former rules 2 "Sequential number" + 3 "Counter scope" merged into new rule 2 "Random suffix" with 4-char `[A-Z0-9]` spec); LLMP exception explicit; full prefixed form mandatory in hash anchors. (f) **Registry maintenance workflow** — 5 steps → 7 steps; per-repo `TOPIC_CODES.md` ownership clarification; topic codes need NOT be globally unique (prefix disambiguates); collision check both against C# class-name prefixes AND within same repo's TOPIC_CODES.md. (g) **Examples** updated: all 13 examples use full 4-component placeholder format with realistic `` illustrations + LLMP bare exception; explicit note that `` is illustrative not actual. (h) **Cross-references section** — bare-ID-may-be-used wording removed (full prefixed form mandatory); workspace-registries entry added cross-linking to `REPO_PREFIXES.md`. **No existing entry IDs renamed** — Phase 2 is purely the convention update; the Topic codes table currently still lists all workspace topics (legacy state), to be migrated to per-repo registries in Phase 4-5. **Phase 1 + Phase 2 together establish the FORMAT FOUNDATION**; Phase 3 (skill `SKILL.md` updates with placeholder examples + ID-generation guidance + cross-repo glob), Phase 4 (mapping table), Phase 5 (per-topic existing-entry rename), Phase 6 (cross-file ref cleanup), Phase 7 (final verification) follow. | `docs-check/references/TOPIC_CODES.md` (Scope note, brief intro, "Why this registry exists", Distinctions, ID format rules, Registry maintenance, Examples, Cross-references — 8 sections updated) | +| LLMP-DEC-55 | 2026-04-26 | Phase 3 of ID-format migration: skill `SKILL.md` files updated for 4-component ID format and per-repo registry awareness | Phase 3 of the LLMP-DEC-50 migration. Updated 4 skill `SKILL.md` files + 1 reference template to align with the format foundation established in Phases 1-2 (LLMP-DEC-53 `REPO_PREFIXES.md`, LLMP-DEC-54 `TOPIC_CODES.md`). **`docs-check/SKILL.md`** (5 edits): (a) Step 5 Proposed ID spec — `{TOPIC}-{TYPE}-{N}` → `---`, with both registries cross-linked, random-suffix generation procedure (glob + collision-check + regenerate), `` source clarification (active repo's). (b) Sub-category example — `## SIG-I-4 [PROTO]: ...` → `## ACCORE-SIG-I-K7M2 [PROTO]: ...`. (c) Topic code selection — per-repo TOPIC_CODES.md awareness, prefix-disambiguation note, cross-repo XCUT case flagged as not-formalized, new-topic proposal references Registry maintenance workflow. (d) Step 6 renamed "Status update on fix" → "Status update on close" — aligned with LLMP-DEC-44 vocabulary (Open/InProgress/Closed); example anchor updated to full prefixed form; Resolution sub-section requirement added per Status field conventions. (e) Output template — `[tentative: TOPIC-TYPE-N]` → `[tentative: ---]`. **`docs-discovery/SKILL.md`** (2 edits): (f) Archive file ID example — `LOG-I-X` → `ACCORE-LOG-I-K7M2`. (g) NEW section "Cross-repo ID search" — describes prefix-wildcard glob patterns (`**/*-LOG-I-*`, `**/*-MEAS-T-*`) for finding entries of a topic across all repos, complementing Step 2's topic-folder discovery; explicit "globs do the work, no central index" principle. **`docs-archive/SKILL.md`** (1 edit): (h) Year-derivation example updated — `Fixed 2026-04-25`, `Won't fix 2026-04-25`, `LOG-I-X` → `Status: Closed (2026-04-25)`, `### Resolution` sub-section, `ACCORE-LOG-I-K7M2`; explicit Status vocabulary alignment with TOPIC_CODES.md (only Closed archives). **`adr-author/SKILL.md`** (1 edit): (i) Step 8 #4 follow-up TODO format — `{TOPIC}-T-N` → `--T-` with cross-link to TOPIC_CODES.md and REPO_PREFIXES.md. **`adr-author/references/ADR_TEMPLATE.md`** (1 edit): (j) Related TODOs/Issues placeholder — `` → realistic 4-component placeholders with registry cross-link. **No existing entry IDs renamed** — Phase 3 is purely skill-text update; existing entries (e.g., `LOG-I-1` through `LOG-I-10` in LOGGING_ISSUES.md) remain in legacy 3-component format until Phase 5 migrates them. **Phases 1-3 complete = format foundation done**; Phase 4 (mapping table OLD_ID → NEW_ID for existing entries), Phase 5 (per-topic existing-entry rename), Phase 6 (cross-file ref cleanup including ADR / Decision Log / code comments), Phase 7 (final verification + completion entry) follow per LLMP-DEC-50. | `docs-check/SKILL.md` (Steps 5/6, output template); `docs-discovery/SKILL.md` (Archive section example + new "Cross-repo ID search" section); `docs-archive/SKILL.md` (year-derivation example + Status vocabulary alignment); `adr-author/SKILL.md` (Step 8 #4 follow-up TODO format); `adr-author/references/ADR_TEMPLATE.md` (Related TODOs/Issues placeholder) | +| LLMP-DEC-56 | 2026-04-26 | Phase 4 of ID-format migration: created `MIGRATION_ID_MAPPING.md` mapping table (79 entries surveyed and given new random `` suffix) | Phase 4 of LLMP-DEC-50 migration — survey + planning, no existing-entry rename. Workspace-wide grep `\b[A-Z]+-[A-Z]+-[0-9]+\b` over `.md` files: 79 unique entries identified — 77 in ACCORE (BIN: 19, LOG: 21, SIG: 15, SBP: 10, TOON: 11, XCUT: 1) + 2 in ACBLAZOR (GRID: 2). Other 5 repos: 0 entries. Each ID assigned a 4-char `[A-Z0-9]` random suffix; verified within-triplet uniqueness for all 12 `--` triplets. **Pending forward-refs documented separately**: `LOG-T-12` (referenced in `docs/AUTH/README.md` + ADR-0001 but not defined in `LOGGING_TODO.md`) and `SBP-T-9` (referenced in decorator-feature-stack ADR but not defined in `SIGNALR_BINARY_PROTOCOL_TODO.md`) — Phase 4 captures them in 'Pending forward-references' section, decision deferred to Phase 6. **Template/placeholder IDs noted**: `GRID-I-1` (MGGRID_ISSUES.md example line), `AUTH-I-N` (generic placeholder) — not migrated, reformatted alongside topic rename in Phase 5. **Original Phase 7 deletion plan** for this mapping file later revised by user — see LLMP-DEC-58. | new file: `AyCode.Core/.github/MIGRATION_ID_MAPPING.md` | +| LLMP-DEC-57 | 2026-04-26 | Phase 5 of ID-format migration: per-topic rename of all 79 existing entries from 3-component `--` to 4-component `---` format (132 edits) | Phase 5 of LLMP-DEC-50 migration — actual entry rename. Topic-by-topic execution driven by Phase 4 mapping (LLMP-DEC-56). **Strict scope**: topic-pair files (`_ISSUES.md` + `_TODO.md`) + sister docs in same topic folder (e.g., `BINARY/README.md`, `BINARY_SGEN.md`, `BINARY_IMPLEMENTATION.md`, `TOON_INFERENCE.md`); inter-topic body anchors deferred to Phase 6. **Per-topic edit counts**: GRID 6 (2 IDs + placeholder template reformat), XCUT 7 (1 canonical + 2 cross-ref pointer headers in BINARY_ISSUES/SIGNALR_ISSUES + intra-XCUT body anchors), SBP 11 (10 IDs + 2 intra-file body refs), TOON 14 (11 IDs + 3 sister-doc anchors), BIN 33 (19 IDs + intra-pair anchors + 2 sister docs; **prefix-collision-driven descending order** required because BIN-I-1 is substring of BIN-I-10..15), SIG 21 (15 IDs + intra-pair anchors + sister doc + malformed `#issue-02` anchor fixed), LOG 40 (21 IDs + intra-pair anchors + sister LOGGING/README; LOG-I and LOG-T both required descending order — LOG-I-1 is prefix of LOG-I-10, LOG-T-1 is prefix of LOG-T-10/11). **Replace_all=true used per (file, old-id)** with descending-suffix order for prefix-collision-prone topics. **Final intra-scope verification**: 0 bare 3-component IDs remaining in any topic-pair file or sister doc; all 79 IDs renamed to canonical 4-component format. **Inter-topic refs known-deferred to Phase 6**: cross-file body anchors targeting renamed IDs (e.g., `XCUT_ISSUES.md#xcut-i-1` from `BINARY_TODO.md`), inter-topic body uppercase IDs (e.g., 'XCUT-I-1 / BIN-T-1 have landed' in SIG-T-6 body), AUTH/ADR cross-refs. | 7 topics, ~25 files: BINARY/{ISSUES,TODO,SGEN,IMPLEMENTATION}.md; LOGGING/{ISSUES,TODO,README}.md; SIGNALR/{ISSUES,TODO,README}.md; SIGNALR_BINARY_PROTOCOL/{ISSUES,TODO}.md; TOON/{ISSUES,TODO,README,IMPLEMENTATION,INFERENCE}.md; XCUT/{ISSUES,README}.md + cross-ref pointer entries in BINARY_ISSUES.md and SIGNALR_ISSUES.md; MGGRID/{TODO,ISSUES}.md; **132 edits total** | +| LLMP-DEC-58 | 2026-04-26 | Phase 5.1 (Framework-First retightening): `.github/` registries restructured to per-repo declarations + runtime discovery; `prefix` field added to all 7 `@repo` blocks; MIGRATION_ID_MAPPING.md retention policy revised | **User-identified Framework-First violation**: `REPO_PREFIXES.md` (in AyCode.Core/Layer 0/.github/) listed all 7 prefixes including consumer-side ones — Layer 0 must not enumerate higher-layer consumers. The previous workspace-meta-tooling exception (LLMP-DEC-53 era) was over-permissive. **Principle clarified by user**: *"minden repo csak magával egyszintű vagy alacsonyabb layer-el lehet cross"* (every repo cross-references only same-level or lower layers); Framework-First applies to `.github/` tooling too, except narrow workspace-meta history (LLMP-DEC log + transient migration artifacts). Cross-layer awareness uses **runtime discovery via `own-dep-repos` walking**, not centralized listings. **Concrete changes**: (a) `REPO_PREFIXES.md` rewritten — only ACCORE listed; per-repo declaration convention documented; cross-repo wildcard search documented (`*-LOG-I-*`); LLMP exception preserved. (b) `protocol-audit/references/REPOS.md` rewritten — only AyCode.Core's own primary file listed; runtime discovery via `own-dep-repos` walk documented; file-type classification (primary/inherit) by content inspection (no central registry of files). (c) `protocol-audit/SKILL.md` updated — frontmatter description changed; Step 1 rewritten for runtime discovery; **C1 invariant 4 → 5 required fields** (added `prefix`); **C3 invariant repurposed** to `prefix` format check (was 'matches REPOS.md expectations' — circular under new design, removed). (d) `docs-check/references/TOPIC_CODES.md` rewritten — only ACCORE topics; per-repo extension convention documented (consumer-side topics live in `/.github/TOPIC_CODES.md`). (e) `AyCode.Blazor/.github/TOPIC_CODES.md` NEW — ACBLAZOR's own topic registry (just `GRID`). (f) `AyCode.Core/.github/copilot-instructions.md` Layer #126 'Exception for workspace meta-tooling' narrowed: only LLMP-DEC log + transient migration artifacts (e.g., `MIGRATION_ID_MAPPING.md`) may cross layers; all other `.github/` files follow Framework-First. (g) `prefix = ""` field added to all 7 `@repo` blocks: ACCORE / ACBLAZOR / MGNOPLIB / MGNOPCORE / MGFBANKPLUG / FBANKNOP / FBANKAPP. (h) Skill text cleanup: `docs-discovery/SKILL.md` cross-repo ID search examples (replaced specific consumer-prefix references with generic placeholders + ACCORE-internal example); `docs-check/SKILL.md` topic-code selection (removed hypothetical `MGFBANKPLUG-LOG`, generic phrasing). **MIGRATION_ID_MAPPING.md retention revised**: original Phase 7 plan was 'delete this file at migration end'; user revised to **'keep with LLM-targeted 2-week deletion-review reminder'** — any LLM reading the file from 2026-05-10 onward must surface a deletion-confirmation prompt to the user. Header note added with explicit date. | 12+ files: `REPO_PREFIXES.md` rewrite; `protocol-audit/references/REPOS.md` rewrite; `protocol-audit/SKILL.md` (frontmatter + Step 1 + C1 + C3); `docs-check/references/TOPIC_CODES.md` rewrite; `AyCode.Blazor/.github/TOPIC_CODES.md` NEW; `AyCode.Core/.github/copilot-instructions.md` Layer #126; **7 × @repo blocks** in 7 copilot-instructions.md files (`prefix` field); `docs-discovery/SKILL.md` + `docs-check/SKILL.md` (consumer-prefix example cleanup); `MIGRATION_ID_MAPPING.md` (retention header) | +| LLMP-DEC-59 | 2026-04-26 | Phase 6 of ID-format migration: cross-file cross-ref cleanup completed (37 edits across 13 files); migration end state — 0 OLD-format IDs in non-exception files workspace-wide | Phase 6 of LLMP-DEC-50 migration — final cross-file cross-ref cleanup. Inter-topic body anchors and uppercase ID body refs updated per the Phase 4 mapping (LLMP-DEC-56). **Files updated** (13): topic-pair files for inter-topic anchors (`XCUT_ISSUES.md`, `LOGGING_ISSUES.md`, `LOGGING_TODO.md`, `BINARY_TODO.md`, `SIGNALR_ISSUES.md`, `SIGNALR_TODO.md`, `SIGNALR_BINARY_PROTOCOL_TODO.md`); top-level cross-ref doc `CONVENTIONS.md` (4 anchor refs); AUTH topic body refs (`docs/AUTH/README.md` + `AUTH_ISSUES.md` — LOG-I-9 / LOG-I-10 renamed); ADR cross-refs (`docs/adr/0001-user-bearer-token-flow.md` — body + anchor refs renamed; `AyCode.Services/docs/adr/0001-acbinary-decorator-feature-stack-design.md` — SBP-T-5..8 renamed); `XCUT/README.md` outdated 'How XCUT-*-N IDs are numbered' section rewritten to reflect random-suffix format. **Pending forward-refs decision** (deferred from Phase 4): `LOG-T-12` and `SBP-T-9` chose **option (b)** per the LLMP-DEC-50 migration plan — rewrite references to 'forthcoming TODO' / 'no ID assigned yet' instead of reserving placeholder IDs; ID gets assigned when the entry is actually filed in `..._TODO.md`. **Pre-existing typo fixed**: `LOGGING_TODO.md` L88 had stale anchor `SIGNALR_TODO.md#log-t-5` (path → SIGNALR_TODO.md but anchor was `log-t-5`; intent was clearly `sig-t-5`) — corrected to `SIGNALR_TODO.md#accore-sig-t-m5l6`. **Code-comment refs (`.cs` files across all 7 repos)**: 0 OLD-format IDs found via cross-repo grep — no code edits required. **Migration end state**: 0 OLD-format IDs in any non-exception file workspace-wide; 3 allowed-exception files contain remaining OLD-format references — `MIGRATION_ID_MAPPING.md` (transient lookup table, see LLMP-DEC-58 retention policy), this `LLM_PROTOCOL_DECISIONS.md` (workspace-meta history), and `REPO_PREFIXES.md` (single pedagogical 'LOG-I-5' example illustrating the OLD format collision problem — kept intentionally to motivate the prefix design). **Migration scope summary** (Phases 1-6, LLMP-DEC-53/54/55/56/57/58/59): ~270 edits across ~25-30 files; 79 IDs renamed to 4-component random-suffix format; 5 of 7 repos clean of OLD format (the 2 with the legacy mapping/history files are the documented exceptions); all sister docs and ADRs updated; `.cs` code comments clean. | 13 files: 7 topic-pair / sister docs (inter-topic body anchors); 1 top-level (`CONVENTIONS.md`); 2 AUTH docs; 2 ADRs; 1 XCUT/README format-spec rewrite; **37 edits in Phase 6**; **~270 edits across all migration phases (1-6)** | +| LLMP-DEC-60 | 2026-04-26 | `## Current protocol state (quick reference)` summary section refreshed to reflect LLMP-DEC-50..59 outcomes (ID-format migration + Framework-First retightening + 7-instruction-file workspace) | After Phases 1-6 of the ID-format migration, the top-of-file summary section (introduced by LLMP-DEC-25 as a "what's currently active" snapshot, separate from the append-only dated entry table) had become stale on multiple counts: (a) "Active as of 2026-04-24" pre-dated all the migration entries; (b) ID format section described the OLD 3-component `--` format pre-LLMP-DEC-50; (c) instruction file count "8 total: 5 primary + 3 inherit" pre-dated LLMP-DEC-51 (`Mango.FruitBank` deletion → 7 total: 5 primary + 2 inherit); (d) skill list mentioned only 3 skills (was outdated since LLMP-DEC-43 introduced the 5-skill 2-reactive/3-user-gated matrix), used `vN.M` version labels (banned by LLMP-DEC-47), and described `protocol-audit` as reading the central `references/REPOS.md` (Phase 5.1 / LLMP-DEC-58 redesigned it for runtime discovery via `own-dep-repos` walking + content-based file-type classification); (e) Scope codes table referenced `3× inherit` and `all 8`. **Updates applied**: date → 2026-04-26; ID format → 4-component `---` with `` per-repo declaration + `` random-suffix spec + LLMP exception + cross-repo prefix-wildcard search note + cross-links to REPO_PREFIXES.md and per-repo TOPIC_CODES.md; instruction file count → 7 total (5 primary + 2 inherit) with brief notes on LLMP-DEC-51/52 (Mango.FruitBank deletion + FBANKNOP re-attribution) and LLMP-DEC-58 (per-repo `prefix` field added to all 7 `@repo` blocks); agent skills → 5 skills (2 reactive pre-loaded + 3 user-gated lazy-loaded) per LLMP-DEC-43, version labels removed; `protocol-audit` description updated for Phase 5.1 runtime-discovery design + new C1/C3 invariants; scope codes table → `2× inherit` + `all 7`; new note: `.github/` files follow Framework-First (LLMP-DEC-58 narrows the previous workspace-meta-tooling exception). **Append-only governance preserved**: dated entry table (LLMP-DEC-1..60) untouched; the summary section is by design a mutable snapshot per LLMP-DEC-25 (*"the dated entries remain the source of truth for *why* each decision was made; the summary is the *what* at a glance"*). | `AyCode.Core/.github/LLM_PROTOCOL_DECISIONS.md` (`## Current protocol state` section — date L9; "Instruction files" L30-33 + 2 new bullets on `prefix` field and Framework-First; ID format L35-40; agent skills L42-45; "Scope codes" table L99-100) | +| LLMP-DEC-61 | 2026-04-26 | Phase 7 (closure) of ID-format migration: migration formally complete | Phase 7 of LLMP-DEC-50 migration — **formal closure stamp**. All 7 phases of the original LLMP-DEC-50 plan executed: Phase 1 (LLMP-DEC-53) `REPO_PREFIXES.md` registry creation; Phase 2 (LLMP-DEC-54) `TOPIC_CODES.md` 4-component update; Phase 3 (LLMP-DEC-55) skill `SKILL.md` text updates with placeholders + cross-repo glob; Phase 4 (LLMP-DEC-56) `MIGRATION_ID_MAPPING.md` survey + 79-ID random-suffix generation; Phase 5 (LLMP-DEC-57) per-topic rename across 7 topics (132 edits); Phase 5.1 (LLMP-DEC-58) Framework-First retightening of `.github/` registries + per-repo `prefix` field added to all 7 `@repo` blocks + MIGRATION_ID_MAPPING retention policy revision; Phase 6 (LLMP-DEC-59) cross-file cross-ref cleanup (37 edits, 13 files); summary refresh (LLMP-DEC-60). **Final verification confirmed in LLMP-DEC-59 + cross-checked here**: 0 OLD-format IDs in any non-exception `.md` file or `.cs` file workspace-wide; the 3 allowed-exception files (`MIGRATION_ID_MAPPING.md` transient, `LLM_PROTOCOL_DECISIONS.md` workspace-meta history, `REPO_PREFIXES.md` single pedagogical 'LOG-I-5' example) intentionally retain OLD-format references for documented reasons. **Migration totals across LLMP-DEC-53..61**: ~270 edits, ~25-30 files modified, 79 IDs renamed to 4-component random-suffix format, 7 `@repo` blocks gained `prefix` field, 12+ registry/skill files restructured for Framework-First, 1 new file (`AyCode.Blazor/.github/TOPIC_CODES.md`). **Outstanding scheduled event** (NOT new work — auto-triggered): 2026-05-10 LLM-targeted deletion-review for `MIGRATION_ID_MAPPING.md` per LLMP-DEC-58 retention policy. Any LLM reading the file from that date onward must surface a deletion-confirmation prompt to the user; the prompt text is embedded in the file's header. **Migration formally complete** as of this entry; further protocol-stack work proceeds on the 4-component foundation. | `AyCode.Core/.github/LLM_PROTOCOL_DECISIONS.md` (this entry only — closure stamp; no file edits outside the Decision Log) | ## Known follow-ups diff --git a/.github/MIGRATION_ID_MAPPING.md b/.github/MIGRATION_ID_MAPPING.md new file mode 100644 index 0000000..4cc92d4 --- /dev/null +++ b/.github/MIGRATION_ID_MAPPING.md @@ -0,0 +1,236 @@ +# MIGRATION_ID_MAPPING — Phase 4 (deletion-pending) + +> ⚠️ **LLM-targeted deletion reminder**: This file was a Phase 4 transient artifact for the ID-format migration. **From 2026-05-10 onward** (2 weeks after Phase 5 completion 2026-04-26), any LLM agent that reads this file MUST surface the following single-line reminder to the user at the start of its next response: +> +> *"`MIGRATION_ID_MAPPING.md` is past its 2-week retention window (since 2026-05-10) — confirm if you want me to delete it now."* +> +> Until 2026-05-10 the file remains untouched as a reverse-lookup aid (git history, old chat transcripts, external references may still mention OLD IDs). +> +> **Phase 4 of the ID-format migration** (see `LLMP-DEC-50`). Maps existing 3-component IDs (`--`) to the new 4-component format (`---`). +> +> **Status:** generated 2026-04-26; Phase 5 (per-topic rename) completed 2026-04-26; Phase 6 (cross-ref cleanup) consumes this table. **Original Phase 7 plan (delete this file) is superseded** — this file now persists as a historical reverse-lookup aid, with a 2-week deletion-review window starting 2026-05-10 (per user instruction 2026-04-26). +> +> **Generation rules:** +> - Repo prefix per `REPO_PREFIXES.md` (file → repo → prefix). +> - Random 4-char `[A-Z0-9]` suffix; unique within each `--` triplet. +> - `LLMP-DEC-N` entries are NOT migrated (workspace-meta exception). +> - Template/placeholder IDs (e.g. `## GRID-I-1: ...` example line, `AUTH-I-N` placeholder) are NOT migrated. +> - "Pending" references (mentioned in docs but not yet defined as `_ISSUES.md`/`_TODO.md` entries) are NOT migrated — see "Pending forward-references" section below; they get rewritten/removed in Phase 6. + +--- + +## Summary + +| Repo | Prefix | Issue IDs | TODO IDs | Total | +|---|---|---:|---:|---:| +| AyCode.Core | `ACCORE` | 41 | 36 | 77 | +| AyCode.Blazor | `ACBLAZOR` | 0 | 2 | 2 | +| Mango.Nop Libraries | `MGNOPLIB` | 0 | 0 | 0 | +| Mango.Nop.Core (sub-folder) | `MGNOPCORE` | 0 | 0 | 0 | +| Nop.Plugin.Misc.AIPlugin | `MGFBANKPLUG` | 0 | 0 | 0 | +| FruitBank | `FBANKNOP` | 0 | 0 | 0 | +| FruitBankHybridApp | `FBANKAPP` | 0 | 0 | 0 | +| **Total** | | **41** | **38** | **79** | + +--- + +## ACCORE — AyCode.Core + +### BINARY (BIN) + +Canonical home: `AyCode.Core/docs/BINARY/BINARY_ISSUES.md`, `AyCode.Core/docs/BINARY/BINARY_TODO.md`. + +| OLD_ID | FILE (repo-relative) | NEW_ID | +|---|---|---| +| `BIN-I-1` | `AyCode.Core/docs/BINARY/BINARY_ISSUES.md` | `ACCORE-BIN-I-D2J5` | +| `BIN-I-2` | `AyCode.Core/docs/BINARY/BINARY_ISSUES.md` | `ACCORE-BIN-I-G7N3` | +| `BIN-I-3` | `AyCode.Core/docs/BINARY/BINARY_ISSUES.md` | `ACCORE-BIN-I-S1F8` | +| `BIN-I-4` | `AyCode.Core/docs/BINARY/BINARY_ISSUES.md` | `ACCORE-BIN-I-V5L2` | +| `BIN-I-5` | `AyCode.Core/docs/BINARY/BINARY_ISSUES.md` | `ACCORE-BIN-I-K8R4` | +| `BIN-I-6` | `AyCode.Core/docs/BINARY/BINARY_ISSUES.md` | `ACCORE-BIN-I-P3M6` | +| `BIN-I-7` | `AyCode.Core/docs/BINARY/BINARY_ISSUES.md` | `ACCORE-BIN-I-T9X1` | +| `BIN-I-8` | `AyCode.Core/docs/BINARY/BINARY_ISSUES.md` | `ACCORE-BIN-I-B4Y7` | +| `BIN-I-9` | `AyCode.Core/docs/BINARY/BINARY_ISSUES.md` | `ACCORE-BIN-I-H2C5` | +| `BIN-I-10` | `AyCode.Core/docs/BINARY/BINARY_ISSUES.md` | `ACCORE-BIN-I-N6Q3` | +| `BIN-I-11` | `AyCode.Core/docs/BINARY/BINARY_ISSUES.md` | `ACCORE-BIN-I-F1W8` | +| `BIN-I-12` | `AyCode.Core/docs/BINARY/BINARY_ISSUES.md` | `ACCORE-BIN-I-J4D2` | +| `BIN-I-13` | `AyCode.Core/docs/BINARY/BINARY_ISSUES.md` | `ACCORE-BIN-I-R5V9` | +| `BIN-I-14` | `AyCode.Core/docs/BINARY/BINARY_ISSUES.md` | `ACCORE-BIN-I-L7G3` | +| `BIN-I-15` | `AyCode.Core/docs/BINARY/BINARY_ISSUES.md` | `ACCORE-BIN-I-M3K6` | +| `BIN-T-1` | `AyCode.Core/docs/BINARY/BINARY_TODO.md` | `ACCORE-BIN-T-S8P4` | +| `BIN-T-2` | `AyCode.Core/docs/BINARY/BINARY_TODO.md` | `ACCORE-BIN-T-Q2N7` | +| `BIN-T-3` | `AyCode.Core/docs/BINARY/BINARY_TODO.md` | `ACCORE-BIN-T-W9F1` | +| `BIN-T-4` | `AyCode.Core/docs/BINARY/BINARY_TODO.md` | `ACCORE-BIN-T-T5J8` | + +### LOGGING (LOG) + +Canonical home: `AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md`, `AyCode.Core/docs/LOGGING/LOGGING_TODO.md`. + +| OLD_ID | FILE (repo-relative) | NEW_ID | +|---|---|---| +| `LOG-I-1` | `AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md` | `ACCORE-LOG-I-K7M2` | +| `LOG-I-2` | `AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md` | `ACCORE-LOG-I-R9P3` | +| `LOG-I-3` | `AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md` | `ACCORE-LOG-I-L4N8` | +| `LOG-I-4` | `AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md` | `ACCORE-LOG-I-B2H5` | +| `LOG-I-5` | `AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md` | `ACCORE-LOG-I-X7Q1` | +| `LOG-I-6` | `AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md` | `ACCORE-LOG-I-V3J6` | +| `LOG-I-7` | `AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md` | `ACCORE-LOG-I-T8F2` | +| `LOG-I-8` | `AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md` | `ACCORE-LOG-I-M4C9` | +| `LOG-I-9` | `AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md` | `ACCORE-LOG-I-P5W3` | +| `LOG-I-10` | `AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md` | `ACCORE-LOG-I-K1Z7` | +| `LOG-T-1` | `AyCode.Core/docs/LOGGING/LOGGING_TODO.md` | `ACCORE-LOG-T-H6Y4` | +| `LOG-T-2` | `AyCode.Core/docs/LOGGING/LOGGING_TODO.md` | `ACCORE-LOG-T-N2D8` | +| `LOG-T-3` | `AyCode.Core/docs/LOGGING/LOGGING_TODO.md` | `ACCORE-LOG-T-R7L3` | +| `LOG-T-4` | `AyCode.Core/docs/LOGGING/LOGGING_TODO.md` | `ACCORE-LOG-T-F4S6` | +| `LOG-T-5` | `AyCode.Core/docs/LOGGING/LOGGING_TODO.md` | `ACCORE-LOG-T-J9G2` | +| `LOG-T-6` | `AyCode.Core/docs/LOGGING/LOGGING_TODO.md` | `ACCORE-LOG-T-B8K5` | +| `LOG-T-7` | `AyCode.Core/docs/LOGGING/LOGGING_TODO.md` | `ACCORE-LOG-T-X1V4` | +| `LOG-T-8` | `AyCode.Core/docs/LOGGING/LOGGING_TODO.md` | `ACCORE-LOG-T-M7P2` | +| `LOG-T-9` | `AyCode.Core/docs/LOGGING/LOGGING_TODO.md` | `ACCORE-LOG-T-L3T8` | +| `LOG-T-10` | `AyCode.Core/docs/LOGGING/LOGGING_TODO.md` | `ACCORE-LOG-T-Q6Z1` | +| `LOG-T-11` | `AyCode.Core/docs/LOGGING/LOGGING_TODO.md` | `ACCORE-LOG-T-W4H9` | + +### SIGNALR_BINARY_PROTOCOL (SBP) + +Canonical home: `AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_ISSUES.md`, `..._TODO.md`. + +| OLD_ID | FILE (repo-relative) | NEW_ID | +|---|---|---| +| `SBP-I-1` | `AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_ISSUES.md` | `ACCORE-SBP-I-F6T2` | +| `SBP-I-2` | `AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_ISSUES.md` | `ACCORE-SBP-I-G4B5` | +| `SBP-T-1` | `AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_TODO.md` | `ACCORE-SBP-T-P8X9` | +| `SBP-T-2` | `AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_TODO.md` | `ACCORE-SBP-T-K3J7` | +| `SBP-T-3` | `AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_TODO.md` | `ACCORE-SBP-T-L1V4` | +| `SBP-T-4` | `AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_TODO.md` | `ACCORE-SBP-T-R6D2` | +| `SBP-T-5` | `AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_TODO.md` | `ACCORE-SBP-T-H7M5` | +| `SBP-T-6` | `AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_TODO.md` | `ACCORE-SBP-T-N9F3` | +| `SBP-T-7` | `AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_TODO.md` | `ACCORE-SBP-T-J5W8` | +| `SBP-T-8` | `AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_TODO.md` | `ACCORE-SBP-T-B3K6` | + +### SIGNALR (SIG) + +Canonical home: `AyCode.Services/docs/SIGNALR/SIGNALR_ISSUES.md`, `AyCode.Services/docs/SIGNALR/SIGNALR_TODO.md`. + +| OLD_ID | FILE (repo-relative) | NEW_ID | +|---|---|---| +| `SIG-I-1` | `AyCode.Services/docs/SIGNALR/SIGNALR_ISSUES.md` | `ACCORE-SIG-I-R4W7` | +| `SIG-I-2` | `AyCode.Services/docs/SIGNALR/SIGNALR_ISSUES.md` | `ACCORE-SIG-I-L5K3` | +| `SIG-I-3` | `AyCode.Services/docs/SIGNALR/SIGNALR_ISSUES.md` | `ACCORE-SIG-I-H8D6` | +| `SIG-I-4` | `AyCode.Services/docs/SIGNALR/SIGNALR_ISSUES.md` | `ACCORE-SIG-I-P1J4` | +| `SIG-I-5` | `AyCode.Services/docs/SIGNALR/SIGNALR_ISSUES.md` | `ACCORE-SIG-I-N3V8` | +| `SIG-I-6` | `AyCode.Services/docs/SIGNALR/SIGNALR_ISSUES.md` | `ACCORE-SIG-I-T7S2` | +| `SIG-I-7` | `AyCode.Services/docs/SIGNALR/SIGNALR_ISSUES.md` | `ACCORE-SIG-I-B5G9` | +| `SIG-I-8` | `AyCode.Services/docs/SIGNALR/SIGNALR_ISSUES.md` | `ACCORE-SIG-I-K6F1` | +| `SIG-I-9` | `AyCode.Services/docs/SIGNALR/SIGNALR_ISSUES.md` | `ACCORE-SIG-I-X4M7` | +| `SIG-T-1` | `AyCode.Services/docs/SIGNALR/SIGNALR_TODO.md` | `ACCORE-SIG-T-J2P5` | +| `SIG-T-2` | `AyCode.Services/docs/SIGNALR/SIGNALR_TODO.md` | `ACCORE-SIG-T-W8R3` | +| `SIG-T-3` | `AyCode.Services/docs/SIGNALR/SIGNALR_TODO.md` | `ACCORE-SIG-T-D7Q4` | +| `SIG-T-4` | `AyCode.Services/docs/SIGNALR/SIGNALR_TODO.md` | `ACCORE-SIG-T-V9H1` | +| `SIG-T-5` | `AyCode.Services/docs/SIGNALR/SIGNALR_TODO.md` | `ACCORE-SIG-T-M5L6` | +| `SIG-T-6` | `AyCode.Services/docs/SIGNALR/SIGNALR_TODO.md` | `ACCORE-SIG-T-S3N8` | + +### TOON (TOON) + +Canonical home: `AyCode.Core/docs/TOON/TOON_ISSUES.md`, `AyCode.Core/docs/TOON/TOON_TODO.md`. + +| OLD_ID | FILE (repo-relative) | NEW_ID | +|---|---|---| +| `TOON-I-1` | `AyCode.Core/docs/TOON/TOON_ISSUES.md` | `ACCORE-TOON-I-B7L4` | +| `TOON-I-2` | `AyCode.Core/docs/TOON/TOON_ISSUES.md` | `ACCORE-TOON-I-X3H2` | +| `TOON-I-3` | `AyCode.Core/docs/TOON/TOON_ISSUES.md` | `ACCORE-TOON-I-P6V5` | +| `TOON-I-4` | `AyCode.Core/docs/TOON/TOON_ISSUES.md` | `ACCORE-TOON-I-K4Z9` | +| `TOON-T-1` | `AyCode.Core/docs/TOON/TOON_TODO.md` | `ACCORE-TOON-T-D1R7` | +| `TOON-T-2` | `AyCode.Core/docs/TOON/TOON_TODO.md` | `ACCORE-TOON-T-G5M3` | +| `TOON-T-3` | `AyCode.Core/docs/TOON/TOON_TODO.md` | `ACCORE-TOON-T-J8N6` | +| `TOON-T-4` | `AyCode.Core/docs/TOON/TOON_TODO.md` | `ACCORE-TOON-T-V2T4` | +| `TOON-T-5` | `AyCode.Core/docs/TOON/TOON_TODO.md` | `ACCORE-TOON-T-S6B9` | +| `TOON-T-6` | `AyCode.Core/docs/TOON/TOON_TODO.md` | `ACCORE-TOON-T-F3X1` | +| `TOON-T-7` | `AyCode.Core/docs/TOON/TOON_TODO.md` | `ACCORE-TOON-T-M9Q2` | + +### XCUT (XCUT) + +Canonical home: `AyCode.Core/docs/XCUT/XCUT_ISSUES.md`. Cross-ref pointer entries with the same ID exist in `BINARY_ISSUES.md` (line 148) and `SIGNALR_ISSUES.md` (line 131) — they are renamed to the same NEW_ID in Phase 5 (cross-ref pointers, not duplicate entries). + +| OLD_ID | FILE (repo-relative) | NEW_ID | +|---|---|---| +| `XCUT-I-1` | `AyCode.Core/docs/XCUT/XCUT_ISSUES.md` (canonical) + cross-refs in `BINARY_ISSUES.md`, `AyCode.Services/docs/SIGNALR/SIGNALR_ISSUES.md` | `ACCORE-XCUT-I-X8Q1` | + +--- + +## ACBLAZOR — AyCode.Blazor + +### MGGRID (GRID) + +Canonical home: `AyCode.Blazor.Components/docs/MGGRID/MGGRID_TODO.md`. (No issues yet — `MGGRID_ISSUES.md` only contains a placeholder example line.) + +| OLD_ID | FILE (repo-relative) | NEW_ID | +|---|---|---| +| `GRID-T-1` | `AyCode.Blazor.Components/docs/MGGRID/MGGRID_TODO.md` | `ACBLAZOR-GRID-T-V4P7` | +| `GRID-T-2` | `AyCode.Blazor.Components/docs/MGGRID/MGGRID_TODO.md` | `ACBLAZOR-GRID-T-S2L9` | + +--- + +## Pending forward-references (NOT migrated — Phase 6 cleanup) + +These IDs are referenced in docs but not yet defined as `_ISSUES.md`/`_TODO.md` entries. They have no OLD_ID body to migrate. Phase 6 must decide per-case: (a) actually create the entry under the new format, or (b) rewrite/remove the reference. + +| Referenced ID | Mentioned in | Decision deferred to Phase 6 | +|---|---|---| +| `LOG-T-12` | `docs/AUTH/README.md`, `docs/adr/0001-user-bearer-token-flow.md` | Tentative TODO ("Never log secrets" framework guideline). Either define as `ACCORE-LOG-T-` and add to `LOGGING_TODO.md`, or rewrite reference. | +| `SBP-T-9` | `AyCode.Services/docs/adr/0001-acbinary-decorator-feature-stack-design.md` | Reserved for `AcHubProtocolDecoratorBase` impl + handshake; deferred until at least one leaf ADR (0002-0005) reaches `Status: Accepted`. Either define on demand or rewrite reference. | + +## Template/placeholder IDs (NOT migrated) + +These appear in template/example lines, not as real entries. They stay as-is (or get reformatted to the new placeholder syntax in Phase 5 alongside the topic rename). + +| Placeholder | File | Note | +|---|---|---| +| `GRID-I-1` | `AyCode.Blazor.Components/docs/MGGRID/MGGRID_ISSUES.md:7` | Example line: "Add the first `## GRID-I-1: ...` entry below..." — should become "`## ACBLAZOR-GRID-I-:`" example. | +| `AUTH-I-N` | `AyCode.Core/docs/AUTH/AUTH_ISSUES.md`, `AyCode.Core/docs/AUTH/README.md` | Generic placeholder — the `N` is literal "N", not a digit. Should become `ACCORE-AUTH-I-` example. | + +## Workspace-meta IDs (NOT migrated — bare exception) + +`LLMP-DEC-N` Decision Log entries do NOT receive a repo prefix per `REPO_PREFIXES.md` "LLMP exception" section. They stay bare. Highest entry as of 2026-04-26: `LLMP-DEC-55` (Phase 3 closure). + +--- + +## Within-triplet duplicate-check (sanity) + +| Triplet | Count | Suffixes (sorted) | Unique? | +|---|---:|---|---| +| `ACCORE-BIN-I-` | 15 | B4Y7, D2J5, F1W8, G7N3, H2C5, J4D2, K8R4, L7G3, M3K6, N6Q3, P3M6, R5V9, S1F8, T9X1, V5L2 | ✅ | +| `ACCORE-BIN-T-` | 4 | Q2N7, S8P4, T5J8, W9F1 | ✅ | +| `ACCORE-LOG-I-` | 10 | B2H5, K1Z7, K7M2, L4N8, M4C9, P5W3, R9P3, T8F2, V3J6, X7Q1 | ✅ | +| `ACCORE-LOG-T-` | 11 | B8K5, F4S6, H6Y4, J9G2, L3T8, M7P2, N2D8, Q6Z1, R7L3, W4H9, X1V4 | ✅ | +| `ACCORE-SBP-I-` | 2 | F6T2, G4B5 | ✅ | +| `ACCORE-SBP-T-` | 8 | B3K6, H7M5, J5W8, K3J7, L1V4, N9F3, P8X9, R6D2 | ✅ | +| `ACCORE-SIG-I-` | 9 | B5G9, H8D6, K6F1, L5K3, N3V8, P1J4, R4W7, T7S2, X4M7 | ✅ | +| `ACCORE-SIG-T-` | 6 | D7Q4, J2P5, M5L6, S3N8, V9H1, W8R3 | ✅ | +| `ACCORE-TOON-I-` | 4 | B7L4, K4Z9, P6V5, X3H2 | ✅ | +| `ACCORE-TOON-T-` | 7 | D1R7, F3X1, G5M3, J8N6, M9Q2, S6B9, V2T4 | ✅ | +| `ACCORE-XCUT-I-` | 1 | X8Q1 | ✅ (trivially) | +| `ACBLAZOR-GRID-T-` | 2 | S2L9, V4P7 | ✅ | + +All 12 triplets pass uniqueness within-triplet (the only collision domain that matters per `REPO_PREFIXES.md`'s suffix specification — collisions ACROSS triplets are non-issues since the full ID disambiguates). + +--- + +## Phase 5 readiness checklist + +For each topic-pair (`_ISSUES.md` + `_TODO.md`) Phase 5 will: +1. Rename headers (`## LOG-I-1: ...` → `## ACCORE-LOG-I-K7M2: ...`). +2. Rewrite intra-file cross-refs (e.g., body text "see LOG-I-3" → "see ACCORE-LOG-I-L4N8"). +3. Rewrite TOC/anchor references if present. +4. Verify with grep: zero remaining bare `--` matches in the file (post-rename), excluding example/placeholder lines. +5. One commit per topic (12 commits total: BIN, LOG, SBP, SIG, TOON, XCUT, GRID — but BIN/LOG/SIG/SBP/TOON each pair I+T → 5 commits; XCUT and GRID each 1 commit → 7 commits total). + +Inter-file cross-refs (e.g., `BINARY_ISSUES.md` mentioning `BIN-T-3`, `BINARY_TODO.md` mentioning `BIN-T-3` from another entry, ADRs mentioning `LOG-I-9` etc.) are handled in Phase 6. + +--- + +## Related + +- `REPO_PREFIXES.md` — repo prefix registry (canonical authority for the `` component). +- `skills/docs-check/references/TOPIC_CODES.md` — topic registry (canonical authority for the `` component). +- `LLM_PROTOCOL_DECISIONS.md` `LLMP-DEC-50` — migration design decision (7-phase plan). +- `LLM_PROTOCOL_DECISIONS.md` `LLMP-DEC-53`, `LLMP-DEC-54`, `LLMP-DEC-55` — Phases 1-3 closure entries. diff --git a/.github/REPO_PREFIXES.md b/.github/REPO_PREFIXES.md new file mode 100644 index 0000000..d4e8978 --- /dev/null +++ b/.github/REPO_PREFIXES.md @@ -0,0 +1,106 @@ +# Repo Prefixes — format spec for repo-level namespace in topic IDs + +Specification of the `` component in the workspace's 4-component ID format. **Each repo declares its own prefix in its own `copilot-instructions.md` `@repo` block** — there is no central prefix listing here, in line with the Framework-First Design Principle (a framework `.md` does not enumerate consumer repos). + +This file lives in `AyCode.Core/.github/` because the **format spec** is workspace-meta (used by every repo). It does NOT list non-framework prefixes. + +## Full ID format + +``` +--- +``` + +| Component | Source | Description | +|---|---|---| +| `` | Each repo's own `copilot-instructions.md` `@repo` block (`prefix = "..."` field) | Repo-level namespace | +| `` | `docs-check/references/TOPIC_CODES.md` | Topic code (e.g., `LOG`, `BIN`, `SIG`) | +| `` | `docs-check/references/TOPIC_CODES.md` | Entry type (`I` = issue, `T` = TODO, `B` = bug, `C` = critical severity override) | +| `` | Generated at creation | 4-character random alphanumeric suffix from `[A-Z0-9]` | + +**Format rules**: all uppercase, hyphen-separated, no underscores, no spaces. Hash anchors in markdown cross-refs use lowercase: `accore-log-i-k7m2`. + +**Examples** (using this repo's own prefix only — see Framework-First note above): +``` +ACCORE-LOG-I-K7M2 # AyCode.Core's logger issue, random suffix K7M2 +ACCORE-BIN-T-W9F1 # AyCode.Core's BINARY TODO, random suffix W9F1 +ACCORE-XCUT-I-X8Q1 # AyCode.Core's cross-cutting issue +LLMP-DEC-50 # workspace-meta Decision (no prefix — see "LLMP exception" below) +``` + +## Why per-repo prefixes + +Without prefixes, IDs like `LOG-I-5` are not globally unique across repos. Two peers may independently create logger-related issues with colliding IDs. More importantly: **framework docs cannot reference consumer-side issues** per the Framework-First Design Principle (a lower-layer framework cannot depend on a higher-layer consumer). Per-repo prefixes provide: + +1. **Globally unique IDs** — `ACCORE-LOG-I-K7M2` ≠ `-LOG-I-K7M2`, even when topic, type, and random suffix all match. +2. **Layer enforcement is visible** — a framework doc body referencing a higher-layer-prefixed ID becomes an immediate red flag in review (the prefix mismatch reveals the dependency-direction violation). +3. **Cross-repo search via wildcard** — `*-LOG-I-*` glob/regex finds all logger issues workspace-wide, with no central registry needed; the LLM filters by prefix after retrieval. +4. **Distributed parallel work** — combined with the random `` suffix, multiple developers can create entries in parallel branches without ID-collision at merge time. + +## ACCORE — this repo's own prefix + +This repo (`AyCode.Core`) uses prefix **`ACCORE`** (declared in this repo's own `copilot-instructions.md` `@repo` block, `prefix = "ACCORE"` field). + +## Per-repo prefix declaration convention + +Every repo participating in the workspace declares its own prefix in its `.github/copilot-instructions.md` `@repo` block: + +``` +@repo { + name = "" + prefix = "" # ← prefix declared here + type = "framework" | "product" | "consumer" | ... + layer = 0..N + own-dep-repos = [...] +} +``` + +To discover a peer's prefix at agent runtime: read that peer's `copilot-instructions.md` (already loaded if the peer is in `own-dep-repos`). For peers NOT in `own-dep-repos` (i.e., higher-layer consumers from a framework's perspective): cross-repo wildcard search (next section) avoids needing to know the prefix in advance. + +## Cross-repo ID search (no central registry needed) + +When searching for entries across the workspace (e.g., "all logger issues" — across framework AND any consumer repos), agents use the prefix-wildcard glob: + +``` +*-LOG-I-* # all logger issues, any prefix +*-BIN-T-* # all BINARY TODOs, any prefix +*-SIG-* # all SIGNALR entries (issues + TODOs + bugs) +``` + +The wildcard pattern is workspace-discovery-agnostic — no central prefix list required. Result enumeration finds all matches; the LLM filters by prefix per the user's intent. The `docs-discovery` skill includes the cross-repo wildcard convention in its discovery flow. + +## Random suffix spec + +The `` suffix is **4 characters from `[A-Z0-9]`** (36⁴ ≈ 1.7 million combinations per topic-type-prefix triple). + +**Generation rules**: + +1. Each new entry receives a fresh random suffix at creation time. +2. Before finalizing: the agent globs existing entries (active topic file + all year-bucketed archive files for that topic) and verifies the suffix is not yet used. +3. If collision detected (extremely rare — birthday-paradox 50% probability at ~1300 entries per topic-type-prefix triple): regenerate the suffix. +4. The suffix is **append-only** once assigned — never renumbered, never recycled, never reassigned to a different entry. + +**At archive time** (`docs-archive` skill): performs collision-check before moving entries to year-bucketed archive files. If collision detected with an existing archive entry: skill aborts, signals the user, awaits manual resolution — no silent corruption. + +## LLMP exception + +`LLMP-DEC-N` Decision Log entries **do NOT receive a repo prefix**. They are workspace-meta — there is exactly one `LLM_PROTOCOL_DECISIONS.md` file (in AyCode.Core), and decisions are workspace-wide, not repo-specific. Bare format: `LLMP-DEC-1`, `LLMP-DEC-2`, ... + +Sequential numbering for LLMP-DEC entries is **preserved** (legacy from before this registry existed; no random suffix). This is acceptable because the single Decision Log file enforces serialization — no parallel branches create concurrent LLMP-DEC entries that would collide. + +If a future scenario emerges where workspace-meta decisions span multiple Decision Logs (unlikely), this exception will be revisited. + +## Cross-references + +- **Topic codes registry**: `docs-check/references/TOPIC_CODES.md` — the `` component +- **Decision Log**: `LLM_PROTOCOL_DECISIONS.md` — registry of `LLMP-DEC-N` entries (workspace-meta, no prefix) +- **Per-repo prefix declarations**: each repo's own `.github/copilot-instructions.md` `@repo` block + +## Picking a prefix for a new repo + +When a new repo joins the workspace, it picks its own prefix (no central approval needed): + +1. Choose a prefix (4-12 chars, uppercase, alphanumeric, no hyphens / underscores). +2. Verify it does NOT collide with `Ac*` / `Mg*` C# class-name prefixes (prefix must be ≥ 4 chars to avoid 2-char visual collision in mixed code/markdown content). +3. Verify it is visually distinct from prefixes of repos this new repo will reference or interoperate with (workspace-discovery-time check, not centrally enforced). +4. Declare the prefix in the new repo's `.github/copilot-instructions.md` `@repo` block (`prefix = ""` field). +5. (Optional) Add an `LLMP-DEC-N` entry recording the new repo's join + prefix choice, if the new repo's existence is workspace-meta-significant. diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 37ed0e5..8ac6fbe 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -96,6 +96,7 @@ Before running any source-code `Grep` / `get_file` / `code_search` in response t @repo { name = "AyCode.Core" + prefix = "ACCORE" type = "framework" layer = 0 own-dep-repos = [] @@ -123,7 +124,13 @@ Before running any source-code `Grep` / `get_file` / `code_search` in response t Framework design = **"write the base first, derive the specific later"**. Plan framework placement first, then consumer-specific code. -**Exception for workspace meta-tooling:** Files under `.github/` (LLM-agent skills, `copilot-instructions.md`, `LLM_PROTOCOL_DECISIONS.md`, registry data like `REPOS.md` / `TOPIC_CODES.md`) are **workspace-configuration, not framework code**. They may reference any layer — topics, repos, or consumer products — because they describe *this specific workspace's* agent-tooling layout. The Framework-First rule applies to C# code, namespaces, types, and domain `.md` docs (under `docs/`), **NOT** to `.github/` tooling. If AyCode.Core is ever extracted as a standalone framework, the `.github/` folder is workspace-swapped; the framework code itself stays layer-clean. Do NOT "fix" apparent Framework-First violations inside `.github/` tooling — they are intentional. +**Exception for workspace-meta history (narrow):** Only **historical / transient** workspace-meta files may reference any layer: +- `LLM_PROTOCOL_DECISIONS.md` — append-only Decision Log; entries document workspace-wide events historically and may reference any layer (a decision affecting a specific consumer is recorded here for the audit trail). +- Transient migration artifacts (e.g., `MIGRATION_ID_MAPPING.md` during an active ID-format migration) — short-lived, scheduled for deletion review. + +**All OTHER `.github/` files** (skills, registries like `REPO_PREFIXES.md` / `REPOS.md` / `TOPIC_CODES.md`, `copilot-instructions.md` itself, etc.) follow the Framework-First Design Principle: a Layer N file may only reference Layer ≤ N. Cross-layer awareness in tooling uses **runtime discovery via `own-dep-repos` walking** (each repo declares its own info; the skill / agent walks the dep tree to gather what's needed), not centralized enumeration in a Layer 0 file. + +The Framework-First rule applies to C# code, namespaces, types, domain `.md` docs (under `docs/`), AND `.github/` tooling — except the narrow workspace-meta history above. If AyCode.Core is ever extracted as a standalone framework, the framework code AND its `.github/` tooling stay layer-clean. Full doctrine: `../docs/ARCHITECTURE.md#framework-vs-consumer-boundary` diff --git a/.github/skills/adr-author/SKILL.md b/.github/skills/adr-author/SKILL.md index 2148f39..b4d49c1 100644 --- a/.github/skills/adr-author/SKILL.md +++ b/.github/skills/adr-author/SKILL.md @@ -158,7 +158,7 @@ After the primary write: - **Pre-flight-closed-entry**: if an entry was closed BEFORE the ADR write (a pre-flight fix that this ADR formalizes architecturally), do NOT change its Status — it's already `Closed`. Instead, propose appending a soft cross-ref to the entry's `### Related` section: `**Reference:** ADR-NNNN — formal architectural decision; this entry's Resolution is the pre-flight fix referenced in the ADR's Consequences.` Do not apply either case without user consent. -4. **Follow-up TODOs** — if Step 6 surfaced follow-up work items, propose their addition to the relevant `{TOPIC}_TODO.md` as new `{TOPIC}-T-N` entries. Do not apply without user consent. +4. **Follow-up TODOs** — if Step 6 surfaced follow-up work items, propose their addition to the relevant `_TODO.md` as new `--T-` entries (per `docs-check/references/TOPIC_CODES.md` ID format rules and `REPO_PREFIXES.md`'s prefix scheme). Do not apply without user consent. ## Step 9 — Hand-off after write diff --git a/.github/skills/adr-author/references/ADR_TEMPLATE.md b/.github/skills/adr-author/references/ADR_TEMPLATE.md index 97253ce..5271b25 100644 --- a/.github/skills/adr-author/references/ADR_TEMPLATE.md +++ b/.github/skills/adr-author/references/ADR_TEMPLATE.md @@ -78,5 +78,5 @@ Proposed (YYYY-MM-DD) - Supersedes: - Superseded by: - Related ADRs: -- Related TODOs/Issues: +- Related TODOs/Issues: - External references: diff --git a/.github/skills/docs-archive/SKILL.md b/.github/skills/docs-archive/SKILL.md index 04af02a..b09a92e 100644 --- a/.github/skills/docs-archive/SKILL.md +++ b/.github/skills/docs-archive/SKILL.md @@ -37,7 +37,7 @@ User confirmation required. Never auto-invoke. Move entry X to archive IF `Status: Closed`. -Year derived from a date in the entry body (e.g., `Fixed 2026-04-25`, `Won't fix 2026-04-25`, `Superseded by LOG-I-X 2026-04-25`). If no parseable date in body, default to current year. +Year derived from a date in the entry body (e.g., `Status: Closed (2026-04-25)` or a `### Resolution` sub-section dated `2026-04-25`, or `Superseded by ACCORE-LOG-I-K7M2 (2026-04-25)`). If no parseable date in body, default to current year. Status vocabulary follows `TOPIC_CODES.md` Status field conventions: only `Closed` is archive-eligible; `Open` and `InProgress` stay active. **Stay in active file**: - `Status: Open` — including documented-current-behaviour entries (these stay Open with a body callout per `TOPIC_CODES.md`'s Status field conventions) diff --git a/.github/skills/docs-check/SKILL.md b/.github/skills/docs-check/SKILL.md index 8439c92..d2efc10 100644 --- a/.github/skills/docs-check/SKILL.md +++ b/.github/skills/docs-check/SKILL.md @@ -81,16 +81,17 @@ propose a draft entry. ### Draft entry format -- **Proposed ID**: `{TOPIC}-{TYPE}-{N}` per the workspace registry (`references/TOPIC_CODES.md` relative to this SKILL.md). Types: `I` (issue), `T` (TODO), `B` (bug — confirmed broken), `C` (critical — severity override). `N` = (highest existing seq in the loaded companion file) + 1. Marked `[tentative]` since parallel sessions may collide — the user verifies/adjusts at apply-time. +- **Proposed ID**: `---` per the workspace registries — `` from `AyCode.Core/.github/REPO_PREFIXES.md` (use the active repo's prefix), `` and `` from the active repo's `references/TOPIC_CODES.md` (consumer repos may host their own; otherwise fall back to AyCode.Core's canonical). Types: `I` (issue), `T` (TODO), `B` (bug — confirmed broken), `C` (critical — severity override). `` = 4-character random alphanumeric `[A-Z0-9]`; generate then verify uniqueness against the topic's active companion + year-bucketed archive files; regenerate on rare collision (~1.7M-combination space per `--` triple). Marked `[tentative]` since the user verifies prefix/topic choices at apply-time. - **Priority**: `P1` (high) / `P2` (important) / `P3` (nice-to-have). Note: `C` type already implies emergency; priority is still stated for precision. - **Rationale**: 1-2 sentences. What's wrong or what's planned. - **Affected**: file/class/method reference (with line number if known) -- **Sub-category** (optional): if the entry relates to a known sub-area (e.g., SignalR protocol, logger DI factory), state in body header: `## SIG-I-4 [PROTO]: ...`. Do NOT encode sub-category in the ID itself — ID stays flat. +- **Sub-category** (optional): if the entry relates to a known sub-area (e.g., SignalR protocol, logger DI factory), state in body header: `## ACCORE-SIG-I-K7M2 [PROTO]: ...`. Do NOT encode sub-category in the ID itself — ID stays flat. **Topic code selection**: -- Pick from the registry (`references/TOPIC_CODES.md`) — the registry is the authoritative list of topic codes and type codes; this skill does not hardcode them. -- If the observation spans ≥2 topics → use the `XCUT` topic code (see the XCUT row in `references/TOPIC_CODES.md` for its "Docs location" — the canonical home of cross-cutting entries), with short cross-refs from each affected topic's file. -- If a new topic is needed → surface a proposal ("suggest new topic code `NEWTOPIC` — reason: ...") in the output, do NOT auto-assign. User adds via Decision Log + registry update. +- Pick from the active repo's registry (`/.github/skills/docs-check/references/TOPIC_CODES.md` if the repo has one, otherwise fall back to AyCode.Core's canonical at `AyCode.Core/.github/skills/docs-check/references/TOPIC_CODES.md`) — the registry is the authoritative list of topic codes and type codes; this skill does not hardcode them. +- Topic codes need NOT be globally unique across repos — the `` component (per `REPO_PREFIXES.md`) disambiguates. The framework's `ACCORE-LOG` topic and any other repo's own `LOG` topic (scoped to that repo's prefix) can coexist as separate logger topics — the prefix differentiates. +- If the observation spans ≥2 topics within the same repo → use that repo's `XCUT` topic code (see the XCUT row in the relevant `TOPIC_CODES.md` for its "Docs location"), with short cross-refs from each affected topic's file. Cross-repo XCUT (spanning topics across multiple repos) is a separate case — currently not formalized; surface as a question if encountered. +- If a new topic is needed → surface a proposal ("suggest new topic code `NEWTOPIC` in ``'s TOPIC_CODES.md — reason: ...") in the output, do NOT auto-assign. User adds via Decision Log entry (`LLMP-DEC-N`) + registry update per `TOPIC_CODES.md` Registry maintenance workflow. ### Volume cap @@ -102,14 +103,14 @@ propose a draft entry. - "This might have a race condition if ..." — speculative, skip. - "Consider refactoring the whole class to use a strategy pattern" — vague, not actionable without clarification. -## Step 6 — Status update on fix +## Step 6 — Status update on close -If code changes in this response **fix** a concrete issue that IS listed in a loaded `_ISSUES.md`: -- Surface a suggestion to mark that issue `Status: FIXED` (with commit ref if applicable). +If code changes in this response **close** a concrete entry that IS listed in a loaded `_ISSUES.md` or `_TODO.md`: +- Surface a suggestion to mark that entry `Status: Closed (YYYY-MM-DD)` with a `### Resolution` sub-section (per `references/TOPIC_CODES.md` Status field conventions). Include commit / ADR / PR reference in the Resolution body. - Same prerequisites + cap apply. - Counts against the 3-item cap in Step 5. -Example surface: `LOGGING_ISSUES.md#log-i-1 → mark Status: FIXED (NopLogWriter ctor signature fixed in this response)`. +Example surface: `LOGGING_ISSUES.md#accore-log-i-k7m2 → mark Status: Closed (NopLogWriter ctor signature fixed in this response; add ### Resolution with commit ref)`. ## Step 7 — Emit the `[DOCUMENTATION CHECK]` section @@ -127,7 +128,7 @@ Collect findings from Steps 2-6. Emit at the end of the response (after the main - `` → needs `` **Issue / TODO draft entries** (capped at 3): -- `[tentative: TOPIC-TYPE-N]` [P1/P2/P3] [rationale] — [affected file:line] +- `[tentative: ---]` [P1/P2/P3] [rationale] — [affected file:line] **Status: FIXED suggestions** (if any): - `#` → mark FIXED (fix in ) diff --git a/.github/skills/docs-check/references/TOPIC_CODES.md b/.github/skills/docs-check/references/TOPIC_CODES.md index 79ae0b0..b17abeb 100644 --- a/.github/skills/docs-check/references/TOPIC_CODES.md +++ b/.github/skills/docs-check/references/TOPIC_CODES.md @@ -1,28 +1,27 @@ -# Topic Codes — registry for globally-unique issue/TODO/decision IDs +# Topic Codes — registry for AyCode.Core's own topics (`ACCORE`) -> **Scope note — workspace meta-tooling:** This registry is **workspace-configuration, not framework code**. It lists topics across any layer (framework, shared libraries, consumer products) because LLM agents operate across the full workspace and need one unified topic list. This is an intentional exception to the Framework-First Design Principle — see `AyCode.Core/.github/copilot-instructions.md` → Framework-First Design Principle → Exception for workspace meta-tooling. If AyCode.Core is extracted as a standalone framework, this registry is replaced with the new workspace's topic set (typically only LOG, BIN, TOON, XCUT, LLMP — the framework-layer topics). +Per the Framework-First Design Principle, this Layer 0 registry lists **only the framework's own (`ACCORE`) topics**. Each higher-layer repo hosts its own `TOPIC_CODES.md` for repo-specific topics — see `## Per-repo extension convention` below. A consumer's topic-search at runtime walks `own-dep-repos` to gather both its own and all inherited (lower-layer) topic registries. -Canonical registry of topic codes used in issue, TODO, bug, critical, and decision entry IDs across the workspace. ID format: `{TOPIC}-{TYPE}-{N}`. +Full ID format: `---` — see `AyCode.Core/.github/REPO_PREFIXES.md` for the `` and `` components. The `` and `` components are defined in this file (for the framework) and in each higher-layer repo's own equivalent (for consumer-side topics). ## Why this registry exists -To make IDs like `LOG-I-5`, `SIG-B-2`, `XCUT-I-1` **globally unique strings** — unambiguous when referenced from code comments, cross-file, commit messages, or a future DB migration. +To make IDs like `ACCORE-LOG-I-K7M2`, `ACCORE-SIG-B-3R9P`, `ACCORE-XCUT-I-A4B7` unambiguous within the framework. The `` component (registered here for ACCORE) combines with `` (per `REPO_PREFIXES.md`) and `` (4-character random alphanumeric suffix) to form the full ID. -## Topic codes +## Framework's own (ACCORE) topic codes -| Code | Topic | Scope | Docs location (primary) | -|---------|-----------------------------|-----------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------| -| `LOG` | LOGGING | Logger system: levels, writers, config-reading vs DI factory | `AyCode.Core/AyCode.Core/docs/LOGGING/` (+ variants in `AyCode.Core.Server`, `AyCode.Services`, `Mango.Nop.Services`) | -| `AUTH` | AUTH | User authentication: bearer tokens, JWT, login flow, hub authorization | `AyCode.Core/docs/AUTH/` | -| `SIG` | SIGNALR | SignalR transport: tags, client base, dispatch, session | `AyCode.Core/AyCode.Services/docs/SIGNALR/` (+ variant in `AyCode.Services.Server`) | -| `SBP` | SIGNALR_BINARY_PROTOCOL | Binary wire protocol over SignalR: framing, chunking, argument read | `AyCode.Core/AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/` | -| `BIN` | BINARY | AcBinary serializer: features, format, writers, source generator | `AyCode.Core/AyCode.Core/docs/BINARY/` | -| `TOON` | TOON | Toon serializer: LLM-optimized format with @meta/@types/@data sections | `AyCode.Core/AyCode.Core/docs/TOON/` | -| `GRID` | MGGRID (grid component) | MGGRID component family: layout, CRUD, columns, toolbar, rendering | `AyCode.Blazor/AyCode.Blazor.Components/docs/MGGRID/` | -| `XCUT` | cross-cutting | Issues / TODOs that span ≥2 topics — one canonical home, referenced from others | `AyCode.Core/AyCode.Core/docs/XCUT/` *(canonical; entry can be cross-ref'd from each affected topic file)* | -| `LLMP` | LLM-protocol meta | LLM protocol decisions (Decision Log entries only — uses `LLMP-DEC-N` form) | `AyCode.Core/.github/LLM_PROTOCOL_DECISIONS.md` | +| Code | Topic | Scope | Docs location | +|---------|-----------------------------|-----------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------| +| `LOG` | LOGGING | Logger system: levels, writers, config-reading vs DI factory | `AyCode.Core/AyCode.Core/docs/LOGGING/` (+ variants in `AyCode.Core.Server`, `AyCode.Services`) | +| `AUTH` | AUTH | User authentication: bearer tokens, JWT, login flow, hub authorization | `AyCode.Core/docs/AUTH/` | +| `SIG` | SIGNALR | SignalR transport: tags, client base, dispatch, session | `AyCode.Core/AyCode.Services/docs/SIGNALR/` (+ variant in `AyCode.Services.Server`) | +| `SBP` | SIGNALR_BINARY_PROTOCOL | Binary wire protocol over SignalR: framing, chunking, argument read | `AyCode.Core/AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/` | +| `BIN` | BINARY | AcBinary serializer: features, format, writers, source generator | `AyCode.Core/AyCode.Core/docs/BINARY/` | +| `TOON` | TOON | Toon serializer: LLM-optimized format with @meta/@types/@data sections | `AyCode.Core/AyCode.Core/docs/TOON/` | +| `XCUT` | cross-cutting | Issues / TODOs spanning ≥2 ACCORE topics — one canonical home, referenced from each affected topic | `AyCode.Core/AyCode.Core/docs/XCUT/` | +| `LLMP` | LLM-protocol meta | LLM protocol decisions (Decision Log entries only — uses `LLMP-DEC-N` form, no prefix) | `AyCode.Core/.github/LLM_PROTOCOL_DECISIONS.md` | -## Type codes +## Type codes (universal across all repos) | Code | Type | Used in file | Notes | |-------|----------------|----------------------------------------------|----------------------------------------------------------------------------------------------------| @@ -35,26 +34,44 @@ To make IDs like `LOG-I-5`, `SIG-B-2`, `XCUT-I-1` **globally unique strings** ### Distinctions - **I vs B**: Both tracked together in `_ISSUES.md`. Use `B` only when the behaviour is confirmed broken with a reproducer. `I` covers concerns, inconsistencies, doc drift, edge cases without an active bug. -- **C (Critical)**: A severity flag, not a category. `LOG-C-1` means "logger critical item 1" — body must state whether it's an underlying bug / issue / todo. Prefer `C` over `I`/`B`/`T` when severity is emergency. Do NOT double-classify (no `LOG-IB-1` or similar). +- **C (Critical)**: A severity flag, not a category. `ACCORE-LOG-C-K7M2` means "AyCode.Core's logger critical item with random suffix K7M2" — body must state whether it's an underlying bug / issue / todo. Prefer `C` over `I`/`B`/`T` when severity is emergency. Do NOT double-classify (no `ACCORE-LOG-IB-K7M2` or similar). - **DEC**: LLMP exception — long form because "LLMP-D-1" is unreadable. Decision Log entries only. +## Per-repo extension convention + +Each higher-layer repo MAY host its own `TOPIC_CODES.md` for repo-specific topics. Recommended location: + +``` +/.github/TOPIC_CODES.md +``` + +This per-repo file lists ONLY that repo's own topic codes. Lower-layer (inherited) topics are reachable through the dependency tree — at runtime, the `docs-check` skill walks `own-dep-repos` from the invocation point to gather both this repo's own topics AND all inherited topics from deps. + +Topic codes need NOT be globally unique across repos — the `` component disambiguates. Two repos may legitimately use the same topic code for repo-local concepts (e.g., one framework's `DAL` ≠ another framework's `DAL`). + +If a higher-layer repo has no repo-specific topics, the file is omitted (default = the repo uses only inherited topics from its deps). + +The framework (this file) does NOT enumerate higher-layer topics — that would violate Framework-First. To find all topics workspace-wide, agents walk the dep tree from a top-layer consumer (which transitively sees everything). + ## ID format rules -1. **Format**: `{TOPIC}-{TYPE}-{N}` — all uppercase, hyphen-separated. -2. **Sequential number**: starts at 1, no zero-padding (`LOG-I-1`, `LOG-I-10`, `LOG-I-123`). -3. **Counter scope**: per (topic, type) pair. `LOG-I-*` and `LOG-T-*` have independent counters. `LOG-B-*` has its own counter (separate from `LOG-I-*`). -4. **Append-only**: once assigned, IDs never change. If an entry is reversed or superseded, add a NEW entry that references the prior one — do not renumber. -5. **Hash anchor** (markdown cross-file refs): lowercase with hyphens preserved (`LOGGING_ISSUES.md#log-i-5` — GitHub auto-converts). -6. **No sub-category in ID**: legacy prefixes like `PROTO-`, `DISPATCH-`, `CONN-`, `DS-` are NOT allowed at ID level. Capture sub-category in the entry body header: `## SIG-I-4 [PROTO]: ...`. +1. **Format**: `---` — all uppercase, hyphen-separated. The `` component identifies the owning repo per `AyCode.Core/.github/REPO_PREFIXES.md` (and per each repo's own `@repo.prefix` field). **LLMP exception**: `LLMP-DEC-N` entries (workspace-meta Decision Log) skip the prefix and use sequential `N` instead of `` — single-file serialization avoids parallel-branch collision. +2. **Random suffix**: `` is a 4-character alphanumeric suffix from `[A-Z0-9]` (~1.7M combinations per `--` triple). Generated at entry creation; the agent globs existing entries (active topic file + all year-bucketed archive files) and verifies uniqueness; regenerate on rare collision. +3. **Append-only**: once assigned, IDs never change. If an entry is reversed or superseded, add a NEW entry that references the prior one — do not renumber, do not re-randomize. +4. **Hash anchor** (markdown cross-file refs): lowercase with hyphens preserved (`LOGGING_ISSUES.md#accore-log-i-k7m2` — GitHub auto-converts). Always use the full prefixed form; bare hash anchors without prefix are ambiguous across repos. +5. **No sub-category in ID**: legacy sub-prefixes like `PROTO-`, `DISPATCH-`, `CONN-`, `DS-` are NOT allowed at ID level. Capture sub-category in the entry body header: `## ACCORE-SIG-I-K7M2 [PROTO]: ...`. -## Registry maintenance +## Registry maintenance — adding a new ACCORE topic -To add a new topic code: -1. Propose the code (2-5 uppercase chars), short and mnemonic. -2. Check it doesn't collide with C# class-name prefixes (`Ac*` = AyCode.Core, `Mg*` = Mango-specific) — the code should be visually distinct from those prefixes. -3. Add a row to this registry. -4. Create the topic folder: `docs/{TOPIC_FOLDER_NAME}/` with `README.md`, optional `{TOPIC_FOLDER_NAME}_ISSUES.md`, `{TOPIC_FOLDER_NAME}_TODO.md`. -5. Add a Decision Log entry (`LLMP-DEC-N`) recording the new topic. +To add a new topic code **for AyCode.Core specifically**: +1. Propose the code (2-5 uppercase chars), short and mnemonic, scoped to ACCORE's domain (framework concerns only). +2. Check it doesn't collide with C# class-name prefixes (`Ac*` / `Mg*`) — the topic code should be visually distinct in mixed code/markdown content. +3. Check it doesn't collide with existing ACCORE topic codes in the table above. +4. Add a row to the "Framework's own (ACCORE) topic codes" table. +5. Create the topic folder: `AyCode.Core//docs/{TOPIC_FOLDER_NAME}/` with `README.md`, optional `{TOPIC_FOLDER_NAME}_ISSUES.md`, `{TOPIC_FOLDER_NAME}_TODO.md`. +6. Add a Decision Log entry (`LLMP-DEC-N`, in the workspace-level `LLM_PROTOCOL_DECISIONS.md`) recording the new framework topic. + +For higher-layer repos: each consumer registers its own topics in its own `TOPIC_CODES.md` per the per-repo extension convention. No framework-level approval is needed — the consumer is sovereign over its own domain. ## Collision avoidance with class-name prefixes @@ -62,29 +79,31 @@ C# code conventions in this workspace: - `Ac*` — AyCode.Core framework types (e.g., `AcLoggerBase`, `AcBinarySerializer`) - `Mg*` — Mango company types (e.g., `MgGrid`, `MgDbTableBase`, `MgEntityBase`) -Topic codes intentionally avoid these 2-char prefixes to prevent visual confusion in mixed content (e.g., `MgGrid.cs → GRID-I-1`, not `MG-I-1`). +Topic codes intentionally avoid these 2-char prefixes (`Ac`, `Mg`) to prevent visual confusion in mixed content. Topic codes are 2-5 chars and SHOULD NOT start with `Ac` or `Mg`. (Example principle: a hypothetical 2-char `MG` topic code would visually collide with `Mg*` class names; choose a more distinctive ≥3-char code.) -## Examples +## Examples (ACCORE only) ``` -LOG-I-5 # logger issue 5 -LOG-T-3 # logger TODO 3 -LOG-B-1 # logger bug 1 (confirmed broken) -LOG-C-1 # logger CRITICAL — body: underlying bug / issue / todo -SIG-I-4 # SignalR issue 4 (body may note: [PROTO] sub-category) -SBP-T-2 # SignalR Binary Protocol TODO 2 -BIN-B-1 # Binary serializer bug 1 -TOON-I-3 # Toon issue 3 -GRID-T-7 # MgGrid TODO 7 -XCUT-I-1 # cross-cutting issue 1 (affects ≥2 topics) -LLMP-DEC-4 # LLM-protocol decision 4 (Decision Log entry) +ACCORE-LOG-I-K7M2 # framework's logger issue (random suffix K7M2) +ACCORE-LOG-T-3R9P # framework's logger TODO +ACCORE-LOG-B-A4B7 # framework's logger bug (confirmed broken) +ACCORE-LOG-C-X9Q4 # framework's logger CRITICAL — body: underlying bug / issue / todo +ACCORE-SIG-I-M2K8 # framework's SignalR issue (body may note: [PROTO] sub-category) +ACCORE-SBP-T-7N3F # framework's SignalR Binary Protocol TODO +ACCORE-BIN-B-P5W2 # framework's Binary serializer bug +ACCORE-TOON-I-D8R6 # framework's Toon issue +ACCORE-XCUT-I-F4G1 # framework's cross-cutting issue (affects ≥2 ACCORE topics) +LLMP-DEC-50 # workspace-meta Decision Log entry (no prefix — bare exception) ``` +The `` suffixes shown above are illustrative. Real entries generate fresh random suffixes at creation time per `REPO_PREFIXES.md`'s "Random suffix spec". + ## Cross-references to other files -- **Reference format** (cross-file in markdown): `LOGGING_ISSUES.md#log-i-5` (filename + hash anchor). Bare ID (`LOG-I-5`) may be used when context is unambiguous (within the same topic). -- **Code comments**: `// See LOG-I-5` — bare ID acceptable since it's globally unique. -- **DB natural key** (future migration): `(topic, type, seq)` tuple; or the full string `LOG-I-5` as a single column. +- **Reference format** (cross-file in markdown): `LOGGING_ISSUES.md#accore-log-i-k7m2` (filename + lowercase hash anchor with full 4-component ID). Always use the full prefixed form — bare hash anchors without prefix are ambiguous across repos. +- **Code comments**: `// See ACCORE-LOG-I-K7M2` — full prefixed form, since the ID is globally unique only with prefix. +- **DB natural key** (future migration): `(prefix, topic, type, suffix)` tuple; or the full string `ACCORE-LOG-I-K7M2` as a single column. +- **Workspace registries**: `AyCode.Core/.github/REPO_PREFIXES.md` (framework prefix spec); this file (ACCORE topics + format spec); each higher-layer repo's own `.github/TOPIC_CODES.md` (consumer-side topics); `AyCode.Core/.github/LLM_PROTOCOL_DECISIONS.md` (LLMP-DEC entries, workspace-meta history). ## Status field conventions @@ -110,7 +129,7 @@ When marking `Closed`: 2. **Add a `### Resolution` sub-section** documenting the closure. **Strongly recommended** — without it, future readers (and the `docs-archive` skill on lookup) have no context for "what changed, why, where". Suggested fields: - **What:** one-line summary of the change. - **Where:** code reference (file/class/commit hash) or doc reference (ADR / PR). - - **Why:** the rationale (fix / "won't fix because X" / "superseded by LOG-I-Y" / "accepted as-is"). + - **Why:** the rationale (fix / "won't fix because X" / "superseded by ACCORE-LOG-I-XXXX" / "accepted as-is"). - Optional: scope, date if different from Status line, related entries. The body carries the **nuance**; the Status field only signals archive-eligibility. diff --git a/.github/skills/docs-discovery/SKILL.md b/.github/skills/docs-discovery/SKILL.md index 3d1c5bd..27eff59 100644 --- a/.github/skills/docs-discovery/SKILL.md +++ b/.github/skills/docs-discovery/SKILL.md @@ -135,7 +135,7 @@ The Step 2 glob patterns target **active** companions only — unsuffixed names. ### On-demand read (no user-confirm needed — read-only operation) Read an archive file when ANY of these signals appears: -- A loaded entry references an archived ID (e.g., `Superseded by LOG-I-X` where X resolves only to `_.md`) +- A loaded entry references an archived ID (e.g., `Superseded by ACCORE-LOG-I-K7M2` where the random-suffixed ID resolves only to a `_.md` archive) - A code comment or other doc references an ID resolving only to an archive file - The user's request describes a behaviour pattern matching an archived `Fixed` entry's Description (regression suspicion) - The investigation feels like "this was solved before" — read the topic's archive(s) before re-deriving @@ -157,6 +157,20 @@ On-demand archive lookup: - `**/docs/{TOKEN}/{TOKEN}_TODO_*.md` - `**/LLM_PROTOCOL_DECISIONS_*.md` +## Cross-repo ID search + +When a request asks about all entries of a topic across the workspace (e.g., "show me all logger issues" — potentially spanning multiple repos, each possibly having its own logger-related topic under its own prefix), use **prefix-wildcard globs** against the entry IDs: + +- `**/*-LOG-I-*` — all logger-issue IDs, any repo prefix +- `**/*-LOG-*` — broader: all logger entries (issues + TODOs + bugs across any prefix) +- `**/*-XCUT-I-*` — all cross-cutting issue IDs across any prefix + +The wildcard pattern is repo-agnostic — no central prefix list is consulted; the LLM filters by prefix after retrieval. + +Active topic files are scanned by default; archive files follow the on-demand rules above. Filter results by the `` dimension after retrieval to narrow to a specific repo scope. + +The skill maintains no cross-repo index — **globs do the work**. This complements topic-folder discovery (Step 2): folder-discovery loads files by token-to-folder mapping; cross-repo ID search resolves specific entries by `---` pattern. + ## Step 6 — Proceed to the user's task The response's `[LOADED_DOCS: N files (+K this turn: )]` prefix (per the active repo's Rule #1) already surfaces the newly-loaded filenames and the cumulative count. **No separate confirmation line is needed** — the prefix itself is the confirmation. Continue directly to the user's actual request. diff --git a/.github/skills/protocol-audit/SKILL.md b/.github/skills/protocol-audit/SKILL.md index 9dab05b..86dddc6 100644 --- a/.github/skills/protocol-audit/SKILL.md +++ b/.github/skills/protocol-audit/SKILL.md @@ -1,7 +1,7 @@ --- name: protocol-audit -description: Audit all `.github/copilot-instructions.md` files registered in `references/REPOS.md` for protocol consistency. Two file types are recognized per that registry — **primary** (full numbered AI AGENT CORE PROTOCOL) and **inherit** (reference-only: blockquote pointer to the canonical protocol, no duplicated numbered rules). The skill applies the appropriate invariant set per type. Use when the user asks to "audit protocol", "check instruction consistency", "verify repo rules", "check cross-repo drift", or after modifying the AI AGENT CORE PROTOCOL in any repo. Produces a per-file × invariant table with concrete patch suggestions; does NOT modify any file without explicit consent. -compatibility: Designed for Claude Code and GitHub Copilot (VS). Requires read access to the paths listed in `references/REPOS.md`. +description: Audit `.github/copilot-instructions.md` files for protocol consistency across the invocation-point repo and its dependency tree (discovered at runtime via `own-dep-repos` walking). Two file types are recognized by content — **primary** (full numbered AI AGENT CORE PROTOCOL) and **inherit** (reference-only: blockquote pointer to the canonical protocol, no duplicated numbered rules). The skill applies the appropriate invariant set per type. Use when the user asks to "audit protocol", "check instruction consistency", "verify repo rules", "check cross-repo drift", or after modifying the AI AGENT CORE PROTOCOL in any repo. Produces a per-file × invariant table with concrete patch suggestions; does NOT modify any file without explicit consent. +compatibility: Designed for Claude Code and GitHub Copilot (VS). Requires read access to the invocation-point repo + all its transitive `own-dep-repos`. metadata: author: Fullepi --- @@ -14,15 +14,26 @@ Verify that all `.github/copilot-instructions.md` files registered in `reference This skill READS files and REPORTS findings. It MUST NOT modify any file. Patch suggestions are surfaced as diffs for the user to review and approve. Follow Rule #5 (or equivalent) from the active repo's `copilot-instructions.md`. -## Step 1 — Load the repo list +## Step 1 — Discover the audit set (runtime walk) -Read `references/REPOS.md` (relative to this SKILL.md). Extract: -- **Primary files table** (with absolute paths and classification) -- **Inherit files table** (with absolute paths and classification) -- **Expected own-dep-repos** tables (one per file type) -- **Known issues** section (pre-flagged expected failures) +Determine the **invocation-point repo** from the active workspace context (the repo containing the user's currently-active session). -The registry file is the **single source of truth** for "which files belong to this workspace's protocol audit". The skill treats its contents as authoritative — it does not hardcode any repo/project names. +Walk the dependency tree: +1. Read the invocation-point repo's `.github/copilot-instructions.md` `@repo` block. +2. For each `own-dep-repos` entry, resolve the path relative to the repo root and read that dep's `@repo` block. +3. Continue transitively until no new deps are found. +4. Audit set = {invocation-point repo} ∪ {all walked deps}. + +Classify each file by content inspection (no central registry of files): +- **Primary** — contains the `🛑 AI AGENT CORE PROTOCOL (CRITICAL ENFORCEMENT)` header → full invariant set. +- **Inherit** — contains `follows the AI Agent Core Protocol defined in ` blockquote AND lacks the primary header → reduced invariant set. +- **Unknown** — matches neither → record as `UNKNOWN`, flag for manual review. + +Read `references/REPOS.md` for **framework-side metadata only**: canonical protocol host designation, the framework's own file table (typically a single row — AyCode.Core), and any known issues. Per the Framework-First Design Principle, that file lists only ACCORE; consumer participation in the audit is auto-discovered through the walk above. The skill does not hardcode any repo / project names. + +Effective audit scope per invocation: +- From `AyCode.Core` (Layer 0) → audits only `AyCode.Core`. +- From a higher-layer repo → audits invocation-point + full transitive dep tree below it. ## Step 2 — Read each instruction file @@ -36,14 +47,14 @@ Each invariant yields `PASS` / `FAIL` / `N/A` (not-applicable-to-this-type) and, ### 3A — Common invariants (applied to ALL 8 files) -**C1. `@repo` block has all 4 required fields** -Inside the `@repo { ... }` block, the keys `name`, `type`, `layer`, `own-dep-repos` must all be present. +**C1. `@repo` block has all 5 required fields** +Inside the `@repo { ... }` block, the keys `name`, `prefix`, `type`, `layer`, `own-dep-repos` must all be present. **C2. `own-dep-repos` paths resolve to existing directories** For each `": "` entry, resolve `/` and check the directory exists. -**C3. `own-dep-repos` matches REPOS.md expectations** -The dep set must equal the expected set in REPOS.md's relevant "Expected own-dep-repos" table. +**C3. `@repo.prefix` has valid format** +The `prefix` value must be uppercase, 4-12 chars, alphanumeric only (no hyphens / underscores / spaces / lowercase). It must NOT collide with `Ac*` / `Mg*` C# class-name prefixes (must be ≥ 4 chars, see `REPO_PREFIXES.md`). **C4. `## Session Setup` section present with all three skills** Header `## Session Setup` must appear. The section body must reference all three skills: `docs-discovery/SKILL.md`, `docs-check/SKILL.md`, and `protocol-audit/SKILL.md`. For inherit files, the section must additionally reference loading the canonical `copilot-instructions.md` (from the host repo — e.g., AyCode.Core). Expected first-response `[LOADED_DOCS]` counts: 4 for primary, 5 for inherit. diff --git a/.github/skills/protocol-audit/references/REPOS.md b/.github/skills/protocol-audit/references/REPOS.md index 736c20a..a4ff7cb 100644 --- a/.github/skills/protocol-audit/references/REPOS.md +++ b/.github/skills/protocol-audit/references/REPOS.md @@ -1,81 +1,75 @@ -# Repos under protocol-audit +# Repos under protocol-audit (framework-only registry) -> **Scope note — workspace meta-tooling:** This file is **workspace-configuration, not framework code**. It may list repos at any layer (including consumer products) because protocol-audit is a workspace-level cross-cutting tool. This is an intentional exception to the Framework-First Design Principle — see `AyCode.Core/.github/copilot-instructions.md` → Framework-First Design Principle → Exception for workspace meta-tooling. If AyCode.Core is extracted as a standalone framework, this file is replaced with the new workspace's layout. - -Each row is one `.github/copilot-instructions.md` file that participates in the shared AI AGENT CORE PROTOCOL — either as **Primary** (full numbered-rule protocol) or **Inherit** (references the canonical host's protocol, minimal own content). +Per the Framework-First Design Principle, this Layer 0 registry lists **only the framework's own files** participating in the AI AGENT CORE PROTOCOL. Consumer files (Layer 1+) are discovered at audit time via the invocation-point repo's `own-dep-repos` walk — see `## Cross-repo audit discovery (runtime)` below. ## Canonical protocol host -**`AyCode.Core`** — this repo hosts the shared agent skills (`.github/skills/`), the Decision Log (`.github/LLM_PROTOCOL_DECISIONS.md`), and these registry files. All inherit files reference AyCode.Core. Cross-cutting invariants (X1–X2) are skipped for the host itself (it does not cross-reference itself). +**`AyCode.Core`** — this repo hosts the shared agent skills (`.github/skills/`), the Decision Log (`.github/LLM_PROTOCOL_DECISIONS.md`), and these registry files. All inherit files reference AyCode.Core. Cross-cutting invariants (X1–X3) are skipped for the host itself (it does not cross-reference itself). If the host designation is ever moved to a different repo, update this section AND the inherit-file substring checked by invariant I1 in `SKILL.md`. -## Primary protocol files +## Framework's own primary protocol files -These files contain the full numbered AI AGENT CORE PROTOCOL (Rules #1-5), `@repo` block, and Conventions. All structural, rule-content, and cross-reference invariants apply. The first row (marked `★`) is the canonical protocol host. +| # | Name | Absolute path | Layer | Host | +|---|-------------|---------------------------------------------|---------------|------| +| 1 | AyCode.Core | `H:\Applications\Aycode\Source\AyCode.Core` | framework (0) | ★ | -| # | Name | Absolute path | Layer | Host | -|---|---------------------|----------------------------------------------------------------------------|------------------|------| -| 1 | AyCode.Core | `H:\Applications\Aycode\Source\AyCode.Core` | framework (0) | ★ | -| 2 | AyCode.Blazor | `H:\Applications\Aycode\Source\AyCode.Blazor` | framework (1) | | -| 3 | Mango.Nop Libraries | `H:\Applications\Mango\Source\NopCommerce.Common\4.70\Libraries` | shared libs (2) | | -| 4 | FruitBank | `H:\Applications\Mango\Source\FruitBank` | product (3) | | -| 5 | FruitBankHybridApp | `H:\Applications\Mango\Source\FruitBankHybridApp` | product (3) | | +The instruction file is at `\.github\copilot-instructions.md`. -## Inherit protocol files +## Cross-repo audit discovery (runtime) -These files reference AyCode.Core's protocol via blockquote and do NOT repeat the numbered rules. Only the reduced invariant set applies (see "Invariants by type" below). +When `protocol-audit` is invoked from a higher-layer repo (Layer 1+), the skill discovers participating files by walking the invocation-point repo's `own-dep-repos` recursively: -| # | Name | Absolute path | Layer | Role | -|---|----------------------------|------------------------------------------------------------------------------------------------|------------------|-------------------------------------------| -| 6 | Mango.Nop.Core | `H:\Applications\Mango\Source\NopCommerce.Common\4.70\Libraries\Mango.Nop.Core` | framework (2) | Domain framework for NopCommerce plugins | -| 7 | Nop.Plugin.Misc.AIPlugin | `H:\Applications\Mango\Source\NopCommerce.Common\4.70\Plugins\Nop.Plugin.Misc.AIPlugin` | consumer (3) | FruitBank plugin source code | +1. Read the invocation-point repo's `.github/copilot-instructions.md` `@repo` block. +2. For each `own-dep-repos` entry, resolve the path relative to the repo root and read that dep's `@repo` block. +3. Continue transitively until no new deps are found. +4. Audit set = {invocation-point repo} ∪ {all walked deps}. -The instruction file to audit for each is: `\.github\copilot-instructions.md`. +Effective audit scope per invocation: +- From `AyCode.Core` (Layer 0) → audits only `AyCode.Core` (this file's table). +- From `AyCode.Blazor` (Layer 1) → audits `AyCode.Core + AyCode.Blazor`. +- From a Layer 2/3 consumer → audits the full transitive dep tree below it (consumer + all its deps). -## Expected own-dep-repos (for @repo block path validation) +The framework cannot directly enumerate consumer files (Framework-First). Higher layers naturally see Layer ≤ N — that's what `own-dep-repos` already encodes. -### Primary +## File-type classification (by content, not by central registry) -| Repo | Expected deps (relative path from this repo's root) | -|--------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------| -| AyCode.Core | — (none) | -| AyCode.Blazor | `AyCode.Core: ../AyCode.Core` | -| Libraries | `AyCode.Core: ../../../../../Aycode/Source/AyCode.Core` | -| FruitBank | `AyCode.Core: ../../../Aycode/Source/AyCode.Core`, `Mango.Nop Libraries: ../NopCommerce.Common/4.70/Libraries` | -| FruitBankHybridApp | `AyCode.Core: ../../../Aycode/Source/AyCode.Core`, `AyCode.Blazor: ../../../Aycode/Source/AyCode.Blazor`, `Mango.Nop Libraries: ../NopCommerce.Common/4.70/Libraries` | +Each discovered file is classified per content inspection: -### Inherit +- **Primary** — contains the `🛑 AI AGENT CORE PROTOCOL (CRITICAL ENFORCEMENT)` header → full invariant set applies (Common + Primary + Cross-cutting). +- **Inherit** — contains the `follows the AI Agent Core Protocol defined in ` blockquote AND lacks the primary header → reduced invariant set applies (Common + Inherit + Cross-cutting). +- **Unknown** — matches neither pattern → flag as `UNKNOWN` for manual review (do not silently skip). -| Repo | Expected deps (relative path from this repo's root) | -|---------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------| -| Mango.Nop.Core | `AyCode.Core: ../../../../../../Aycode/Source/AyCode.Core` | -| Nop.Plugin.Misc.AIPlugin | `Mango.Nop.Core: ../../Libraries/Mango.Nop.Core`, `AyCode.Core: ../../../../../../Aycode/Source/AyCode.Core` | +See `SKILL.md` for the invariant sets. ## Invariants by type -**Primary files (1-5)** — full invariant set per `SKILL.md`: -- Rule numbering contiguous 1..N +**Primary files** — full invariant set per `SKILL.md`: +- `@repo` block has all 5 required fields (`name`, `prefix`, `type`, `layer`, `own-dep-repos`); paths resolve to existing directories; `prefix` has valid format +- Rule numbering contiguous 1..N; rule count ≥ 5 +- Rule #1 uses count+delta format - Rule #2 contains `CROSS-REPO HARD-GATE` and `PER-QUESTION DOC-FIRST` - Rule #3 is `STRICT NO-RE-READ POLICY (ANTI-LOOP)` and contains "in context" definition (`lossy compressions`) - Rule #4 contains auto-detection triggers - Rule #5 contains broad scope wording (`any file (code, documentation, configuration, memory, or otherwise)`) - `strictly maintain rule 3` reference exists -- `## Shared Agent Skills` section with both skills listed -- `## Protocol History` section referencing `AyCode.Core/.github/LLM_PROTOCOL_DECISIONS.md` -- `@repo` block has all 4 required fields, paths resolve to existing directories +- `## Shared Agent Skills` section with all three skills listed (X1) +- `## Protocol History` section referencing `AyCode.Core/.github/LLM_PROTOCOL_DECISIONS.md` (X2) +- Docs-sync rule references the `docs-check` skill (X3) -**Inherit files (6-8)** — reduced invariant set: -- References AyCode.Core's protocol via substring: `follows the AI Agent Core Protocol defined in AyCode.Core` -- Has `## Shared Agent Skills` section listing **both** skills (docs-discovery + protocol-audit) -- Has `## Protocol History` section referencing `AyCode.Core/.github/LLM_PROTOCOL_DECISIONS.md` -- `@repo` block (if present) has all 4 required fields, paths resolve to existing directories +**Inherit files** — reduced invariant set: +- `@repo` block (if present) has all 5 required fields; paths resolve; `prefix` has valid format +- References AyCode.Core's protocol via substring: `follows the AI Agent Core Protocol defined in AyCode.Core` (I1) +- Does NOT duplicate the numbered Rules #1-5 (I2) +- Has a link to the Decision Log (I3) +- Has `## Shared Agent Skills` section with all three skills listed (X1) +- Has `## Protocol History` section referencing the canonical Decision Log (X2) - Numbered rules are NOT required (they are inherited from AyCode.Core) ## Known issues -*(No open issues. Previously tracked — Mango.Nop.Core path off-by-one and Mango.FruitBank purpose TBD — are resolved; see `AyCode.Core/.github/LLM_PROTOCOL_DECISIONS.md` for the fix history.)* +*(No open issues.)* ## Maintenance note -When modifying the repo set (add, remove, or relocate), update this table. `SKILL.md` remains stable because it reads this file at runtime. +This file lists only the framework's own files. When the framework's own repo set changes (rare — currently a single fixed entry), update the table above. **Consumer participation is auto-discovered** at audit time via `own-dep-repos` walking — no central enumeration of consumer repos is needed here, in line with the Framework-First Design Principle. diff --git a/AyCode.Core/docs/BINARY/BINARY_IMPLEMENTATION.md b/AyCode.Core/docs/BINARY/BINARY_IMPLEMENTATION.md index da34b84..8ee2ef3 100644 --- a/AyCode.Core/docs/BINARY/BINARY_IMPLEMENTATION.md +++ b/AyCode.Core/docs/BINARY/BINARY_IMPLEMENTATION.md @@ -141,18 +141,18 @@ Two-phase: - `WriteObjectFullMarkerIId` / `WriteObjectFullMarkerAll`: `wrapper.Metadata` cached at entry, reused in ref-handling and non-ref branches - `GetWrapper(type, slot)` is O(1) array index after first call, but `value.GetType()` is a virtual call — avoid repeating it -## Metadata Lifecycle & Cold-Start (planned: BIN-T-3 / BIN-T-4) +## Metadata Lifecycle & Cold-Start (planned: ACCORE-BIN-T-W9F1 / ACCORE-BIN-T-T5J8) -Today `BinarySerializeTypeMetadata` and `BinaryDeserializeTypeMetadata` are built lazily in `GetWrapperSlow` via `GlobalMetadataCache.GetOrAdd(type, MetadataFactory)`. The factory runs reflection property enumeration, attribute scans, and `Expression.Compile` per property — the dominant first-call cost for SGen types (see `BINARY_ISSUES.md#bin-i-10`). +Today `BinarySerializeTypeMetadata` and `BinaryDeserializeTypeMetadata` are built lazily in `GetWrapperSlow` via `GlobalMetadataCache.GetOrAdd(type, MetadataFactory)`. The factory runs reflection property enumeration, attribute scans, and `Expression.Compile` per property — the dominant first-call cost for SGen types (see `BINARY_ISSUES.md#accore-bin-i-n6q3`). -**Planned evolution** (`BINARY_TODO.md#bin-t-3`): +**Planned evolution** (`BINARY_TODO.md#accore-bin-t-w9f1`): - **`GeneratedMetadataRegistry`**: `ModuleInit` registers pre-built metadata per `[AcBinarySerializable]` type alongside the existing `GeneratedWriterRegistry` / `GeneratedReaderRegistry` entries. Generator passes references to its static `s_typeNameHash` / `s_propertyHashes` fields — single source of truth, no duplicate computation, no hot-path indirection (generator keeps using its own static fields). - **Metadata ctor split**: a second ctor on `BinarySerializeTypeMetadata` / `BinaryDeserializeTypeMetadata` accepts pre-computed values (hashes, `MinWriteSize`, `ComplexPropertyCount`, `IsIId`, `IdAccessorType`, flags). No reflection in this ctor. - **Lazy `RuntimeInit`**: `TypeMetadataBase` gets `volatile bool _runtimeInitialized` + `internal void RuntimeInit()`. `GetWrapperSlow` calls it only when `wrapper.GeneratedWriter == null || !Options.UseGeneratedCode` — i.e. for runtime-only types and the `UseGeneratedCode=false` edge case. SGen types skip it. Thread-safe by idempotence + `volatile` (no lock). - **Hybrid safety**: SGen root path (`WriteObjectProperties` → `generatedWriter.WriteProperties`) never touches the SGen type's own property accessors; non-SGen child types come through the `MetadataFactory` path as today. -**Follow-up** (`BINARY_TODO.md#bin-t-4`): after BIN-T-3 removes reflection + `Expression.Compile` from the cold path, JIT of generated methods becomes dominant — mitigated via `[AggressiveOptimization]`, background `RuntimeHelpers.PrepareMethod`, and/or R2R (consumer publish config). +**Follow-up** (`BINARY_TODO.md#accore-bin-t-t5j8`): after ACCORE-BIN-T-W9F1 removes reflection + `Expression.Compile` from the cold path, JIT of generated methods becomes dominant — mitigated via `[AggressiveOptimization]`, background `RuntimeHelpers.PrepareMethod`, and/or R2R (consumer publish config). Wire format unchanged; `UseGeneratedCode=false` fallback continues to work identically (triggers `RuntimeInit` for SGen types on demand). diff --git a/AyCode.Core/docs/BINARY/BINARY_ISSUES.md b/AyCode.Core/docs/BINARY/BINARY_ISSUES.md index 753e208..8ce6033 100644 --- a/AyCode.Core/docs/BINARY/BINARY_ISSUES.md +++ b/AyCode.Core/docs/BINARY/BINARY_ISSUES.md @@ -2,7 +2,7 @@ ## Deserialization -### BIN-I-1: Non-array-backed memory — per-segment copy +### ACCORE-BIN-I-D2J5: Non-array-backed memory — per-segment copy **Status:** Open **Affects:** `SequenceBinaryInput` @@ -12,7 +12,7 @@ When `ReadOnlySequence` segments are backed by native memory (not managed **Impact:** Negligible. Non-array-backed `ReadOnlyMemory` is extremely rare (custom `MemoryManager` with native memory, memory-mapped files). All standard .NET pools (`ArrayPool`, `MemoryPool.Shared`, Kestrel pipe) are array-backed. -### BIN-I-2: Cross-boundary scratch buffer is not pooled across calls +### ACCORE-BIN-I-G7N3: Cross-boundary scratch buffer is not pooled across calls **Status:** Open **Affects:** `SequenceBinaryInput._scratchBuffer` @@ -23,14 +23,14 @@ The scratch buffer is `ArrayPool.Rent`-ed on first cross-boundary read and reuse **Possible optimization:** Store the scratch buffer on the pooled `BinaryDeserializationContext` and reuse across deserializations. Low priority — `ArrayPool` overhead is negligible. -### BIN-I-3: ReadBytes always copies +### ACCORE-BIN-I-S1F8: ReadBytes always copies **Status:** Open **Affects:** `BinaryDeserializationContext.ReadBytes(int length)` `ReadBytes` allocates a new `byte[]` and copies from the buffer. This is unavoidable because the caller owns the returned array, and the source buffer (pipe segment or serialized data) may be recycled. -### BIN-I-4: ReadStringUtf8 requires contiguous buffer +### ACCORE-BIN-I-V5L2: ReadStringUtf8 requires contiguous buffer **Status:** Open **Affects:** `BinaryDeserializationContext.ReadStringUtf8(int length)` @@ -41,14 +41,14 @@ The scratch buffer is `ArrayPool.Rent`-ed on first cross-boundary read and reuse ## Serialization -### BIN-I-5: BufferWriterBinaryOutput fallback path allocates per-chunk +### ACCORE-BIN-I-K8R4: BufferWriterBinaryOutput fallback path allocates per-chunk **Status:** Open **Affects:** `BufferWriterBinaryOutput.AcquireChunk` fallback -When `MemoryMarshal.TryGetArray` fails on `IBufferWriter.GetMemory()` (native memory-backed writer), a `byte[]` is rented from `ArrayPool` per chunk and copied to the writer on `Grow`/`Flush`. Same as BIN-I-1 — non-array-backed writers are extremely rare. +When `MemoryMarshal.TryGetArray` fails on `IBufferWriter.GetMemory()` (native memory-backed writer), a `byte[]` is rented from `ArrayPool` per chunk and copied to the writer on `Grow`/`Flush`. Same as ACCORE-BIN-I-D2J5 — non-array-backed writers are extremely rare. -### BIN-I-6: AsyncPipeWriterOutput uses sync GetResult() for backpressure +### ACCORE-BIN-I-P3M6: AsyncPipeWriterOutput uses sync GetResult() for backpressure **Status:** Open **Affects:** `AsyncPipeWriterOutput.Grow()` — `_lastFlush.GetAwaiter().GetResult()` @@ -59,37 +59,37 @@ When the previous `PipeWriter.FlushAsync()` hasn't completed by the next `Grow() **Possible optimization:** `AsyncSegment` mode (future) with a custom async `WriteMessageAsync` protocol interface, enabling `await` on flush instead of `GetResult()`. -### BIN-I-7: AsyncPipeWriterOutput fallback path — same as BIN-I-5 +### ACCORE-BIN-I-T9X1: AsyncPipeWriterOutput fallback path — same as ACCORE-BIN-I-K8R4 **Status:** Open **Affects:** `AsyncPipeWriterOutput.AcquireChunk` fallback -Same `TryGetArray` fallback as `BufferWriterBinaryOutput` (BIN-I-5). Kestrel `PipeWriter.GetMemory()` always returns array-backed memory — fallback is for non-standard `PipeWriter` implementations only. +Same `TryGetArray` fallback as `BufferWriterBinaryOutput` (ACCORE-BIN-I-K8R4). Kestrel `PipeWriter.GetMemory()` always returns array-backed memory — fallback is for non-standard `PipeWriter` implementations only. ## Deserialization (PipeReader) -### BIN-I-8: PipeReaderBinaryInput uses sync ReadAsync().GetResult() +### ACCORE-BIN-I-B4Y7: PipeReaderBinaryInput uses sync ReadAsync().GetResult() **Status:** Open **Affects:** `PipeReaderBinaryInput.Initialize()` and `TryAdvanceSegment()` -Same constraint as BIN-I-6 — `IBinaryInputBase` interface is synchronous. `ReadAsync().GetAwaiter().GetResult()` blocks when waiting for more data from the pipe. Currently not used in production (SignalR delivers complete messages via `TryParseMessage`). Reserved for future direct-pipe deserialization scenarios. +Same constraint as ACCORE-BIN-I-P3M6 — `IBinaryInputBase` interface is synchronous. `ReadAsync().GetAwaiter().GetResult()` blocks when waiting for more data from the pipe. Currently not used in production (SignalR delivers complete messages via `TryParseMessage`). Reserved for future direct-pipe deserialization scenarios. ## Source Generator (SGen) -### BIN-I-9: CS8625 warnings for non-nullable reference types +### ACCORE-BIN-I-H2C5: CS8625 warnings for non-nullable reference types **Status:** Open **Affects:** Generated reader code The source generator emits `null` assignments for non-nullable reference type properties during deserialization (before the value is read from the stream). This produces CS8625 warnings. Functionally harmless — the property is always assigned before use. -### BIN-I-10: First-run cold-start overhead +### ACCORE-BIN-I-N6Q3: First-run cold-start overhead **Status:** Open **Affects:** First `Serialize`/`Deserialize` per `[AcBinarySerializable]` type, per process -Cold-start cost chain on first use of an SGen type (before BIN-T-3 lands): +Cold-start cost chain on first use of an SGen type (before ACCORE-BIN-T-W9F1 lands): 1. `BinarySerializeTypeMetadata` ctor — reflection property enumeration + `GetCustomAttribute` scans 2. `Expression.Compile` per property accessor (dynamic getter + typed getters) — **dominant cost** @@ -100,43 +100,43 @@ Cold-start cost chain on first use of an SGen type (before BIN-T-3 lands): Subsequent calls hit cached metadata/wrappers → only Tier 0→1 JIT transition remains (background, async). -**Dominant cost today:** #1–#2 (reflection + `Expression.Compile`). After BIN-T-3, the dominant residual cost shifts to #4–#5 (JIT), addressed by BIN-T-4. +**Dominant cost today:** #1–#2 (reflection + `Expression.Compile`). After ACCORE-BIN-T-W9F1, the dominant residual cost shifts to #4–#5 (JIT), addressed by ACCORE-BIN-T-T5J8. **Impact:** Measurable first-call latency — larger for types with many properties or deep graphs. For SignalR workloads the first message per entity type pays this tax. -### BIN-I-11: Consumer entity with `new` Id shadowing — excluded from SGen +### ACCORE-BIN-I-F1W8: Consumer entity with `new` Id shadowing — excluded from SGen **Status:** Open **Affects:** Any consumer entity whose base class hides `BaseEntity.Id` with `readonly new int Id { get; }` pattern (e.g. `DiscountProductMapping` in Mango.Nop.Core) When the base class shadows `Id` with a setter-less `new int Id { get; }`, SGen can't emit a setter without CS0200. Runtime falls back to compiled-expression serialization for these types. Low priority — affects a small number of consumer entities. -**Related TODO:** `BINARY_TODO.md#bin-t-2` +**Related TODO:** `BINARY_TODO.md#accore-bin-t-q2n7` ## Buffer Writer (BWO) -### BIN-I-12: Struct copy semantics +### ACCORE-BIN-I-J4D2: Struct copy semantics **Status:** Open **Affects:** `BufferWriterBinaryOutput` value-type assignment Assigning a `BufferWriterBinaryOutput` value creates an independent copy. State changes (e.g. `_committedBytes` via `Grow`/`Flush`) are not reflected in the original. Copy back after use if needed. -### BIN-I-13: Initialize resets tracking +### ACCORE-BIN-I-R5V9: Initialize resets tracking **Status:** Open **Affects:** `BufferWriterBinaryOutput.Initialize` (context mode) `Initialize` sets `_committedBytes = 0`. Standalone bytes written before are lost if the BWO is then passed to a context. Call `FlushAndReset()` first, or track standalone bytes separately. -### BIN-I-14: Constructor acquires chunk +### ACCORE-BIN-I-L7G3: Constructor acquires chunk **Status:** Open **Affects:** `BufferWriterBinaryOutput` ctor `AcquireChunk` runs in ctor for standalone readiness. Redundant if only context mode is used (context `Initialize` acquires its own). Not a leak — consecutive `GetMemory` without `Advance` returns overlapping memory. -### BIN-I-15: No mode mixing +### ACCORE-BIN-I-M3K6: No mode mixing **Status:** Open **Affects:** `BufferWriterBinaryOutput` — context vs standalone mode @@ -145,8 +145,8 @@ A single instance must not use context + standalone modes simultaneously — buf ## Cross-cutting (canonical home: `../XCUT/`) -### XCUT-I-1: JSON-in-Binary request parameters — cross-ref +### ACCORE-XCUT-I-X8Q1: JSON-in-Binary request parameters — cross-ref **Status:** Closed (2026-04-26, see canonical entry). -Canonical entry: **`../XCUT/XCUT_ISSUES.md#xcut-i-1`**. Summary: client→server request parameters previously used JSON inside a Binary envelope (`SignalPostJsonDataMessage`); response path was already pure Binary. Migration landed in commits `cdd54d3` + `3b70070` via `SignalParams` (length-prefixed binary pack/unpack) — wire is now Binary in both directions. Migration plan tracked in `BINARY_TODO.md#bin-t-1` (also Closed). +Canonical entry: **`../XCUT/XCUT_ISSUES.md#accore-xcut-i-x8q1`**. Summary: client→server request parameters previously used JSON inside a Binary envelope (`SignalPostJsonDataMessage`); response path was already pure Binary. Migration landed in commits `cdd54d3` + `3b70070` via `SignalParams` (length-prefixed binary pack/unpack) — wire is now Binary in both directions. Migration plan tracked in `BINARY_TODO.md#accore-bin-t-s8p4` (also Closed). diff --git a/AyCode.Core/docs/BINARY/BINARY_SGEN.md b/AyCode.Core/docs/BINARY/BINARY_SGEN.md index 5ab34ad..714fd6b 100644 --- a/AyCode.Core/docs/BINARY/BINARY_SGEN.md +++ b/AyCode.Core/docs/BINARY/BINARY_SGEN.md @@ -169,9 +169,9 @@ void ScanObject(object value, BinarySerializationContext ctx, First use of an SGen type per process incurs reflection + `Expression.Compile` in the `BinarySerializeTypeMetadata` / `BinaryDeserializeTypeMetadata` constructors — dominant first-call cost today. Subsequent calls reuse cached metadata and wrappers. -See `BINARY_ISSUES.md#bin-i-10` for the full cost chain and `BINARY_TODO.md#bin-t-3` / `#todo-04` for planned work: +See `BINARY_ISSUES.md#accore-bin-i-n6q3` for the full cost chain and `BINARY_TODO.md#accore-bin-t-w9f1` / `#todo-04` for planned work: -- **BIN-T-3 — Compile-time metadata generation.** Source generator emits pre-built `BinarySerializeTypeMetadata` (and deserialize counterpart) with hashes, flags, and `MinWriteSize` baked in. Registered from `ModuleInit` into a `GeneratedMetadataRegistry`; `GetWrapperSlow` consults it before falling back to the reflection `MetadataFactory`. A lazy `TypeMetadataBase.RuntimeInit()` builds the `Expression.Compile` property accessors only when needed (runtime-only type, or `UseGeneratedCode=false`). SGen types never touch their own runtime accessors → `RuntimeInit` skipped. Hybrid mode is unaffected: non-SGen child types continue to run the reflection factory. -- **BIN-T-4 — JIT Tier 1 warmup.** After BIN-T-3, JIT of generated `WriteProperties` / `ScanObject` / `ScanForDuplicates` becomes the residual first-call cost. Candidates to evaluate (measure first): `[MethodImpl(MethodImplOptions.AggressiveOptimization)]` on generated methods, background `RuntimeHelpers.PrepareMethod` from `ModuleInit`, ReadyToRun (R2R) in consuming-project publish config, code chunking for oversized methods. +- **ACCORE-BIN-T-W9F1 — Compile-time metadata generation.** Source generator emits pre-built `BinarySerializeTypeMetadata` (and deserialize counterpart) with hashes, flags, and `MinWriteSize` baked in. Registered from `ModuleInit` into a `GeneratedMetadataRegistry`; `GetWrapperSlow` consults it before falling back to the reflection `MetadataFactory`. A lazy `TypeMetadataBase.RuntimeInit()` builds the `Expression.Compile` property accessors only when needed (runtime-only type, or `UseGeneratedCode=false`). SGen types never touch their own runtime accessors → `RuntimeInit` skipped. Hybrid mode is unaffected: non-SGen child types continue to run the reflection factory. +- **ACCORE-BIN-T-T5J8 — JIT Tier 1 warmup.** After ACCORE-BIN-T-W9F1, JIT of generated `WriteProperties` / `ScanObject` / `ScanForDuplicates` becomes the residual first-call cost. Candidates to evaluate (measure first): `[MethodImpl(MethodImplOptions.AggressiveOptimization)]` on generated methods, background `RuntimeHelpers.PrepareMethod` from `ModuleInit`, ReadyToRun (R2R) in consuming-project publish config, code chunking for oversized methods. Wire format is unchanged by both TODOs — this is dispatch / startup optimization only. diff --git a/AyCode.Core/docs/BINARY/BINARY_TODO.md b/AyCode.Core/docs/BINARY/BINARY_TODO.md index 387b00f..9bdba57 100644 --- a/AyCode.Core/docs/BINARY/BINARY_TODO.md +++ b/AyCode.Core/docs/BINARY/BINARY_TODO.md @@ -5,8 +5,8 @@ --- -## BIN-T-1: Replace JSON-in-Binary request parameters -**Priority:** P1 · **Type:** Refactor · **Status:** Closed (2026-04-26, landed in commits `cdd54d3` 2026-04-05 + `3b70070` 2026-04-06) · **Related:** `../XCUT/XCUT_ISSUES.md#xcut-i-1` (canonical), `AyCode.Services/docs/SIGNALR/SIGNALR_TODO.md` +## ACCORE-BIN-T-S8P4: Replace JSON-in-Binary request parameters +**Priority:** P1 · **Type:** Refactor · **Status:** Closed (2026-04-26, landed in commits `cdd54d3` 2026-04-05 + `3b70070` 2026-04-06) · **Related:** `../XCUT/XCUT_ISSUES.md#accore-xcut-i-x8q1` (canonical), `AyCode.Services/docs/SIGNALR/SIGNALR_TODO.md` Migrate client→server request parameters from JSON-in-Binary envelope to direct Binary serialization (matching response path). Coordinated change across client, server, and all consuming projects. Do NOT attempt as side-effect of unrelated work. @@ -17,15 +17,15 @@ Migrate client→server request parameters from JSON-in-Binary envelope to direc - **Where:** `AyCode.Services/SignalRs/AcSignalRClientBase.cs`, `AcWebSignalRHubBase.cs`, `ISignalParams.cs` (server + client dispatch); `IAcSignalRHubClient.cs` (legacy wrappers). - **Equivalent (not literal `SignalPostBinaryDataMessage`):** `SignalParams` was chosen over a 1:1 binary wrapper class — fewer indirections on the hot path, type-safe pack/unpack, and `DataSerializerType` field on `SignalReceiveParams` for response format indication. - **Wire impact:** No JSON round-trip on the wire for request params; this is a **breaking change** vs. previous JSON-in-Binary clients/servers (see commit message). -- **Legacy types:** `SignalPostJsonMessage`, `SignalPostJsonDataMessage`, `SignalPostMessage`, `ISignalPostMessage` all marked `[Obsolete]` in `IAcSignalRHubClient.cs`; deletion tracked separately in `AyCode.Services/docs/SIGNALR/SIGNALR_TODO.md#sig-t-6` (gated on consumer migration). +- **Legacy types:** `SignalPostJsonMessage`, `SignalPostJsonDataMessage`, `SignalPostMessage`, `ISignalPostMessage` all marked `[Obsolete]` in `IAcSignalRHubClient.cs`; deletion tracked separately in `AyCode.Services/docs/SIGNALR/SIGNALR_TODO.md#accore-sig-t-s3n8` (gated on consumer migration). -## BIN-T-2: Re-evaluate DiscountProductMapping SGen exclusion -**Priority:** P3 · **Type:** Investigation · **Related:** `BINARY_ISSUES.md#bin-i-11` +## ACCORE-BIN-T-Q2N7: Re-evaluate DiscountProductMapping SGen exclusion +**Priority:** P3 · **Type:** Investigation · **Related:** `BINARY_ISSUES.md#accore-bin-i-f1w8` Investigate whether the `new int Id` shadowing pattern can be handled by SGen (via base-class introspection, property-setter lookup on the base) to eliminate the runtime compiled-expression fallback for this entity class. -## BIN-T-3: Generate `BinarySerializeTypeMetadata` / `BinaryDeserializeTypeMetadata` at compile time -**Priority:** P1 · **Type:** Performance · **Related:** `BINARY_ISSUES.md#bin-i-10` +## ACCORE-BIN-T-W9F1: Generate `BinarySerializeTypeMetadata` / `BinaryDeserializeTypeMetadata` at compile time +**Priority:** P1 · **Type:** Performance · **Related:** `BINARY_ISSUES.md#accore-bin-i-n6q3` Eliminate the dominant first-call cost (reflection + `Expression.Compile` in metadata ctor) for SGen types by emitting pre-built metadata from the source generator. @@ -48,10 +48,10 @@ Eliminate the dominant first-call cost (reflection + `Expression.Compile` in met - Deserialize side has parity (same approach for `BinaryDeserializeTypeMetadata`). - Existing tests pass; wire format unchanged. -## BIN-T-4: JIT Tier 1 warmup for generated hot methods -**Priority:** P2 · **Type:** Performance · **Related:** `BINARY_ISSUES.md#bin-i-10` +## ACCORE-BIN-T-T5J8: JIT Tier 1 warmup for generated hot methods +**Priority:** P2 · **Type:** Performance · **Related:** `BINARY_ISSUES.md#accore-bin-i-n6q3` -After BIN-T-3 lands, JIT of generated `WriteProperties` / `ScanObject` / `ScanForDuplicates` becomes the dominant residual first-call cost for SGen types. Options to evaluate (benchmark before committing): +After ACCORE-BIN-T-W9F1 lands, JIT of generated `WriteProperties` / `ScanObject` / `ScanForDuplicates` becomes the dominant residual first-call cost for SGen types. Options to evaluate (benchmark before committing): - **`[MethodImpl(MethodImplOptions.AggressiveOptimization)]`** on the generated hot methods — skips Tier 0, compiles directly at Tier 1. Simple generator change. Trade-off: larger one-time JIT cost in exchange for eliminating the Tier 0→1 recompile step. - **Background prewarm from `ModuleInit`**: `Task.Run(() => RuntimeHelpers.PrepareMethod(handle))` for each registered writer/reader method. Parallelizes JIT with app startup. Keep it opt-in (option flag) to avoid surprising consumers with extra startup threads. @@ -60,5 +60,5 @@ After BIN-T-3 lands, JIT of generated `WriteProperties` / `ScanObject` / `ScanFo - **Native AOT** — out of scope for this TODO; separate architectural decision with deployment-model implications. **Acceptance:** -- Benchmark a realistic entity graph (≥ 3 referenced child types) and show first-call time within ~10% of steady-state after BIN-T-3 + chosen mitigation(s). +- Benchmark a realistic entity graph (≥ 3 referenced child types) and show first-call time within ~10% of steady-state after ACCORE-BIN-T-W9F1 + chosen mitigation(s). - Document which combination is recommended for SignalR hot-path workloads vs. batch serialization. diff --git a/AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md b/AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md index ba535ea..60b9cfa 100644 --- a/AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md +++ b/AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md @@ -2,7 +2,7 @@ For planned/actionable work see `LOGGING_TODO.md`. -## LOG-I-1: NopLogWriter ctor signature mismatch (consumer-specific but framework-exposed) +## ACCORE-LOG-I-K7M2: NopLogWriter ctor signature mismatch (consumer-specific but framework-exposed) **Severity:** Minor (caught, non-blocking, but noisy) · **Status:** Open · **Area:** Writer-instantiation contract (`AcLoggerBase(string)` config-reading ctor) @@ -20,9 +20,9 @@ Two logger-construction paradigms coexist: Console.Error noise tolerated. Alternatively, consumer uses DI-based `AddAcLoggerFactory` (see LOGGING.md) instead of the config-reading ctor — this path doesn't touch `LogWriters[]`. ### Related TODO -`LOGGING_TODO.md#log-t-1` +`LOGGING_TODO.md#accore-log-t-h6y4` -## LOG-I-2: AcEnv.AppConfiguration is filesystem-bound, MAUI/WASM-unsafe +## ACCORE-LOG-I-R9P3: AcEnv.AppConfiguration is filesystem-bound, MAUI/WASM-unsafe **Severity:** Minor · **Status:** Open · **Area:** `AyCode.Core.Consts.AcEnv` @@ -36,9 +36,9 @@ Design predates `IOptions`/DI pattern. Consumer avoids the config-reading `AcLoggerBase(string)` ctor on these platforms. DI-based `AddAcLoggerFactory` + `services.Configure(...)` is the replacement (see LOGGING.md). ### Related TODO -`LOGGING_TODO.md#log-t-2` +`LOGGING_TODO.md#accore-log-t-n2d8` -## LOG-I-3: Two parallel logger-setup patterns +## ACCORE-LOG-I-L4N8: Two parallel logger-setup patterns **Severity:** Minor (confusion, not functional) · **Status:** Open · **Area:** LOGGING.md / consumer code @@ -47,17 +47,17 @@ Two ways to construct a logger coexist: 1. **Config-reading:** `new Logger(categoryName)` → `AcLoggerBase` reads `AyCode:Logger` section via `AcEnv.AppConfiguration`, instantiates writers via `Activator.CreateInstance` 2. **DI factory:** `services.Configure(...)` + `services.AddAcLoggerFactory()` → `Func` resolved from DI, writers pulled from DI -Consumer picks per scenario; no automatic bridge. Risk: mixing patterns causes subtle failures (e.g. `MissingMethodException` — see LOG-I-1). +Consumer picks per scenario; no automatic bridge. Risk: mixing patterns causes subtle failures (e.g. `MissingMethodException` — see ACCORE-LOG-I-K7M2). ### Related TODO -`LOGGING_TODO.md#log-t-3` +`LOGGING_TODO.md#accore-log-t-r7l3` -## LOG-I-4: Default LogLevel diverges across the two setup paths +## ACCORE-LOG-I-B2H5: Default LogLevel diverges across the two setup paths **Severity:** Minor (surprise, not broken) · **Status:** Open · **Area:** `AcLoggerBase` field initializer vs `AcLoggerOptions` ### Description -The two logger-setup paths (see LOG-I-3) ship with **different default LogLevels**: +The two logger-setup paths (see ACCORE-LOG-I-L4N8) ship with **different default LogLevels**: - `AcLoggerBase.cs:18` — field initializer: `LogLevel = Error` - `AcLoggerOptions.cs:27` — DI options default: `LogLevel = Info` @@ -71,9 +71,9 @@ Same consumer code, same "no configuration" state, two different log volumes dep Historical: field initializer predates the Options class; Options was added as part of the DI-factory refactor with a developer-friendly `Info` default. ### Related TODO -`LOGGING_TODO.md#log-t-5` +`LOGGING_TODO.md#accore-log-t-j9g2` -## LOG-I-5: `AcConsoleLogWriter.Initialize()` runs twice on parameterless ctor +## ACCORE-LOG-I-X7Q1: `AcConsoleLogWriter.Initialize()` runs twice on parameterless ctor **Severity:** Minor (wasted work, not broken) · **Status:** Open · **Area:** `AcConsoleLogWriter` ctor chain @@ -97,9 +97,9 @@ Chain `: this(null)` invokes the `(string?)` ctor, which calls `Initialize()`. C Remove the second `Initialize()` call in the parameterless ctor body (the chain already covered it). ### Related TODO -`LOGGING_TODO.md#log-t-6` +`LOGGING_TODO.md#accore-log-t-b8k5` -## LOG-I-6: `ILogger.IsEnabled(MsLogLevel.None)` incorrectly reports enabled +## ACCORE-LOG-I-V3J6: `ILogger.IsEnabled(MsLogLevel.None)` incorrectly reports enabled **Severity:** Low (semantic bug, rare path) · **Status:** Open · **Area:** `AcLoggerBase.IsEnabled` + `MapFromMsLogLevel` @@ -125,9 +125,9 @@ Either: - **(b)** Change the comparison to strict `<` with `Disabled` as sentinel (larger refactor — affects semantic of `Disabled` elsewhere) ### Related TODO -`LOGGING_TODO.md#log-t-7` +`LOGGING_TODO.md#accore-log-t-x1v4` -## LOG-I-7: Misleading inline comment in `AcLoggerBase.Log` +## ACCORE-LOG-I-T8F2: Misleading inline comment in `AcLoggerBase.Log` **Severity:** Trivial (doc-only) · **Status:** Open · **Area:** `AcLoggerBase.cs:210-211` @@ -143,11 +143,11 @@ Comment says fallback is `null` (empty display), the code assigns `"Log"`. Contr Update comment to match code: `// Use eventId.Name:eventId.Id if Name is set, otherwise fallback to "Log" per LOGGING.md convention`. ### Related TODO -Folded into `LOGGING_TODO.md#log-t-8` (cleanup batch). +Folded into `LOGGING_TODO.md#accore-log-t-m7p2` (cleanup batch). -## LOG-I-8: Server-side NopCommerce plugin still uses legacy config-reading Logger ctor +## ACCORE-LOG-I-M4C9: Server-side NopCommerce plugin still uses legacy config-reading Logger ctor -**Severity:** Minor (works, but inconsistent with modern pattern + triggers LOG-I-1 noise) · **Status:** Open · **Area:** Consumer adoption gap in `Nop.Plugin.Misc.AIPlugin/Infrastructure/PluginNopStartup.cs` +**Severity:** Minor (works, but inconsistent with modern pattern + triggers ACCORE-LOG-I-K7M2 noise) · **Status:** Open · **Area:** Consumer adoption gap in `Nop.Plugin.Misc.AIPlugin/Infrastructure/PluginNopStartup.cs` ### Description Client side (`FruitBankHybridApp.*` — Web, Web.Client, MAUI) was migrated to the DI-factory pattern: `services.Configure(...)` + `services.AddAcLoggerFactory()`. The server-side plugin was NOT migrated — it still: @@ -158,21 +158,21 @@ Client side (`FruitBankHybridApp.*` — Web, Web.Client, MAUI) was migrated to t 4. Writer registration exists (`services.AddScoped()` + `NopLogWriter`) but those DI-registered singletons are NOT the instances the `new Logger(...)` ctor sees — the legacy ctor creates a parallel set via `Activator.CreateInstance`. The legacy config-reading ctor DOES find the appsettings `AyCode:Logger` section via `AcEnv.AppConfiguration` (filesystem-backed, works on server) — so logging functions. But every `new Logger(...)` call: -- Triggers LOG-I-1 (NopLogWriter ctor mismatch → Console.Error noise) +- Triggers ACCORE-LOG-I-K7M2 (NopLogWriter ctor mismatch → Console.Error noise) - Reconstructs writer instances via `Activator` (not singleton-shared with DI-registered writers) - Is inconsistent with the client-side pattern → two mental models for the same framework ### Fix direction -See `LOGGING_TODO.md#log-t-11`. +See `LOGGING_TODO.md#accore-log-t-w4h9`. ### Related -- `LOG-I-1` (trigger — NopLogWriter ctor mismatch, currently causing Console.Error noise) -- `LOG-I-3` (root cause — two coexisting setup patterns) -- `LOG-I-4` (consequence — different defaults between paths; server legacy path silently ships with `Error` default unless `AyCode:Logger:LogLevel` is set) -- Sibling gap: `../SIGNALR/SIGNALR_ISSUES.md#sig-i-7` (same server-side plugin, protocol-options adoption gap) +- `ACCORE-LOG-I-K7M2` (trigger — NopLogWriter ctor mismatch, currently causing Console.Error noise) +- `ACCORE-LOG-I-L4N8` (root cause — two coexisting setup patterns) +- `ACCORE-LOG-I-B2H5` (consequence — different defaults between paths; server legacy path silently ships with `Error` default unless `AyCode:Logger:LogLevel` is set) +- Sibling gap: `../SIGNALR/SIGNALR_ISSUES.md#accore-sig-i-b5g9` (same server-side plugin, protocol-options adoption gap) - Plugin doc drift: `Nop.Plugin.Misc.AIPlugin/docs/SIGNALR/README.md:22` still documents the pre-migration `new AcBinaryHubProtocol()` registration (actual code uses `.AddAcBinaryProtocol(opts => {...})`). Update needed. -## LOG-I-9: JWT signing key written to log (CRITICAL security) +## ACCORE-LOG-I-P5W3: JWT signing key written to log (CRITICAL security) **Severity:** 🛑 **Critical (security)** · **Status:** Closed (2026-04-25) · **Area:** `AyCode.Services.Server/Logins/AcLoginServiceServer.cs:192` @@ -206,11 +206,11 @@ Remove the `GlobalLogger.Detail($"Key: ...")` line entirely. The signing key mus ### Related - **Reference:** ADR [`0001-user-bearer-token-flow.md`](../../../docs/adr/0001-user-bearer-token-flow.md) — formal architectural decision; this entry's Resolution is the pre-flight fix referenced in the ADR's Consequences. -- `LOG-I-10` (sibling — access token also leaked, same file, same code path) +- `ACCORE-LOG-I-K1Z7` (sibling — access token also leaked, same file, same code path) - `LOGGING/README.md` may need a new "Never log secrets" guideline section (separate `_TODO.md` candidate) -- **Discovery context**: this issue and `LOG-I-10` emerged during the user-bearer-token ADR context-gathering phase (2026-04-25 Copilot session, while reading `AcLoginServiceServer.cs`). If a dedicated AUTH topic-folder is created later (likely as part of the bearer token ADR follow-ups), these two entries are candidates for relocation to `AUTH_ISSUES.md` with `Status: SUPERSEDED by AUTH-I-N` cross-references. +- **Discovery context**: this issue and `ACCORE-LOG-I-K1Z7` emerged during the user-bearer-token ADR context-gathering phase (2026-04-25 Copilot session, while reading `AcLoginServiceServer.cs`). If a dedicated AUTH topic-folder is created later (likely as part of the bearer token ADR follow-ups), these two entries are candidates for relocation to `AUTH_ISSUES.md` with `Status: SUPERSEDED by AUTH-I-N` cross-references. -## LOG-I-10: JWT access token written to log (CRITICAL security) +## ACCORE-LOG-I-K1Z7: JWT access token written to log (CRITICAL security) **Severity:** 🛑 **Critical (security)** · **Status:** Closed (2026-04-25) · **Area:** `AyCode.Services.Server/Logins/AcLoginServiceServer.cs:212` @@ -223,7 +223,7 @@ GlobalLogger.Detail($"AccesToken: {writtenToken}"); (Side note: `AccesToken` is a typo for `AccessToken` — fix while at the line.) -Access tokens are bearer credentials — anyone holding the token can authenticate as the user until token expiry (currently 6h per `GenerateAccessToken` config). Logged tokens leak via the same channels as `LOG-I-9` (live streams, retention archives, screenshots, shared logs during ops). +Access tokens are bearer credentials — anyone holding the token can authenticate as the user until token expiry (currently 6h per `GenerateAccessToken` config). Logged tokens leak via the same channels as `ACCORE-LOG-I-P5W3` (live streams, retention archives, screenshots, shared logs during ops). ### Fix direction Remove the `GlobalLogger.Detail($"AccesToken: ...")` line entirely. If issuance verification is needed, log only **metadata** — user ID, expiry timestamp, issuer — never the token itself. @@ -236,15 +236,15 @@ Remove the `GlobalLogger.Detail($"AccesToken: ...")` line entirely. If issuance **Where:** `AyCode.Services.Server/Logins/AcLoginServiceServer.cs:212` (line numbers shifted slightly due to the inserted comment). -**Why:** Same as `LOG-I-9` — user opted for DEBUG-gating over deletion (2026-04-25, bearer-token ADR session). Typo fix is opportunistic since the line was being touched. +**Why:** Same as `ACCORE-LOG-I-P5W3` — user opted for DEBUG-gating over deletion (2026-04-25, bearer-token ADR session). Typo fix is opportunistic since the line was being touched. -**Caveat:** Same DEBUG-build leak constraint as `LOG-I-9`. CI/CD must build with `-c Release` for production. +**Caveat:** Same DEBUG-build leak constraint as `ACCORE-LOG-I-P5W3`. CI/CD must build with `-c Release` for production. ### Related - **Reference:** ADR [`0001-user-bearer-token-flow.md`](../../../docs/adr/0001-user-bearer-token-flow.md) — formal architectural decision; this entry's Resolution is the pre-flight fix referenced in the ADR's Consequences. -- `LOG-I-9` (sibling — JWT signing key also leaked, same file) -- Same `LOGGING/README.md` "Never log secrets" guideline gap as LOG-I-9 -- Same discovery-context note as LOG-I-9 (bearer token ADR session, candidate for AUTH topic relocation if/when that emerges) +- `ACCORE-LOG-I-P5W3` (sibling — JWT signing key also leaked, same file) +- Same `LOGGING/README.md` "Never log secrets" guideline gap as ACCORE-LOG-I-P5W3 +- Same discovery-context note as ACCORE-LOG-I-P5W3 (bearer token ADR session, candidate for AUTH topic relocation if/when that emerges) ## Evaluated review findings — NOT bugs (by-design) diff --git a/AyCode.Core/docs/LOGGING/LOGGING_TODO.md b/AyCode.Core/docs/LOGGING/LOGGING_TODO.md index a28cb3d..c588283 100644 --- a/AyCode.Core/docs/LOGGING/LOGGING_TODO.md +++ b/AyCode.Core/docs/LOGGING/LOGGING_TODO.md @@ -5,8 +5,8 @@ --- -## LOG-T-1: Fix the writer-ctor mismatch for DI-injected writers -**Priority:** P2 · **Type:** Bug fix · **Related:** `LOGGING_ISSUES.md#log-i-1` +## ACCORE-LOG-T-H6Y4: Fix the writer-ctor mismatch for DI-injected writers +**Priority:** P2 · **Type:** Bug fix · **Related:** `LOGGING_ISSUES.md#accore-log-i-k7m2` Options: - **A)** Provide a fallback `(AppType, LogLevel, string?)` ctor on consumer writers that have DI-heavy primary ctors, with DI resolution via service-locator @@ -15,20 +15,20 @@ Options: Eliminate the per-startup Console.Error noise regardless. -## LOG-T-2: Expose `AcEnv.AppConfiguration` setter for consumer init -**Priority:** P2 · **Type:** Feature · **Related:** `LOGGING_ISSUES.md#log-i-2` +## ACCORE-LOG-T-N2D8: Expose `AcEnv.AppConfiguration` setter for consumer init +**Priority:** P2 · **Type:** Feature · **Related:** `LOGGING_ISSUES.md#accore-log-i-r9p3` Allow `AcEnv.SetConfiguration(IConfiguration)` so consumer `Program.cs` can do `AcEnv.SetConfiguration(builder.Configuration)` at startup. Enables config-reading pattern on MAUI/WASM without filesystem assumptions. Backward-compat: fall back to filesystem if no explicit set. -## LOG-T-3: Unify or clearly separate config-reading and DI-based patterns -**Priority:** P2 · **Type:** Docs / Refactor · **Related:** `LOGGING_ISSUES.md#log-i-3` +## ACCORE-LOG-T-R7L3: Unify or clearly separate config-reading and DI-based patterns +**Priority:** P2 · **Type:** Docs / Refactor · **Related:** `LOGGING_ISSUES.md#accore-log-i-l4n8` Decide the canonical direction: - **(a)** Deprecate config-reading pattern → all consumers migrate to DI factory - **(b)** Keep both, with compile-time guidance (analyzer / XML doc `[Obsolete]` hints / decision tree in LOGGING.md) - **(c)** Merge: DI-factory internally falls back to config-reading when `TLogger` doesn't match the `Activator` ctor shape -## LOG-T-4: Per-writer LogLevel via appsettings +## ACCORE-LOG-T-F4S6: Per-writer LogLevel via appsettings **Priority:** P2 · **Type:** Feature Extend `AcLoggerOptions` with per-writer LogLevel overrides. Example shape: @@ -42,25 +42,25 @@ Extend `AcLoggerOptions` with per-writer LogLevel overrides. Example shape: ``` Factory applies overrides when constructing writers. Currently writer-LogLevel is hardcoded in writer ctors. -## LOG-T-5: Unify default LogLevel across setup paths -**Priority:** P1 · **Type:** Behaviour decision + cleanup · **Related:** `LOGGING_ISSUES.md#log-i-4` +## ACCORE-LOG-T-J9G2: Unify default LogLevel across setup paths +**Priority:** P1 · **Type:** Behaviour decision + cleanup · **Related:** `LOGGING_ISSUES.md#accore-log-i-b2h5` Decide which default wins (`AcLoggerBase.cs:18` = `Error` vs `AcLoggerOptions.cs:27` = `Info`) and make both paths consistent. Recommendation: **`Info`** — matches the DI/Options path already in use for modern consumers (MAUI, WASM, ASP.NET Core) and is the common developer expectation. Change: drop the field initializer in `AcLoggerBase` (or set it to `Info`). Update LOGGING.md with a single "Default LogLevel = Info" line so this can't drift again. -## LOG-T-6: Fix `AcConsoleLogWriter.Initialize()` double-run -**Priority:** P3 · **Type:** Bug fix · **Related:** `LOGGING_ISSUES.md#log-i-5` +## ACCORE-LOG-T-B8K5: Fix `AcConsoleLogWriter.Initialize()` double-run +**Priority:** P3 · **Type:** Bug fix · **Related:** `LOGGING_ISSUES.md#accore-log-i-x7q1` Remove the redundant `Initialize()` call from the parameterless ctor body — the `: this(null)` chain already invokes it. No behaviour change; removes wasted `Console.ForegroundColor` assignment. -## LOG-T-7: Fix `ILogger.IsEnabled(MsLogLevel.None)` wrongly reporting enabled -**Priority:** P2 · **Type:** Bug fix · **Related:** `LOGGING_ISSUES.md#log-i-6` +## ACCORE-LOG-T-X1V4: Fix `ILogger.IsEnabled(MsLogLevel.None)` wrongly reporting enabled +**Priority:** P2 · **Type:** Bug fix · **Related:** `LOGGING_ISSUES.md#accore-log-i-v3j6` Add `if (logLevel == MsLogLevel.None) return false;` at the top of `AcLoggerBase.IsEnabled`. One-line fix. Optionally add a unit test covering all six MS LogLevel values → expected bool. -## LOG-T-8: Cleanup batch (low-risk micro-refactor, one commit) -**Priority:** P3 · **Type:** Cleanup · **Related:** `LOGGING_ISSUES.md#log-i-7` +## ACCORE-LOG-T-M7P2: Cleanup batch (low-risk micro-refactor, one commit) +**Priority:** P3 · **Type:** Cleanup · **Related:** `LOGGING_ISSUES.md#accore-log-i-t8f2` Single commit covering: - Remove unused usings in `AcLoggerBase.cs` (`System.Security.AccessControl`, `System.Net.Mime.MediaTypeNames`) @@ -68,14 +68,14 @@ Single commit covering: - Fix misleading comment at `AcLoggerBase.cs:210` — current comment says "fallback null" but code assigns `"Log"`. Make comment match code. - Decide on the commented-out batch block in `AcLogItemWriterBase.cs:90-119`: either delete (git history preserves) or convert to a single `// TODO: see LOGGING_TODO.md#todo-XX` marker with a new TODO entry for the batch work. -## LOG-T-9: Fail-fast ctor validation in `AddAcLoggerFactory` +## ACCORE-LOG-T-L3T8: Fail-fast ctor validation in `AddAcLoggerFactory` **Priority:** P2 · **Type:** Feature `AcLoggerServiceExtensions.AddAcLoggerFactory` uses `Activator.CreateInstance(typeof(TLogger), AppType, LogLevel, categoryName, writers)` only on first logger resolution. Ctor-mismatch therefore surfaces only at first log call, not at `services.BuildServiceProvider()` time. Add a one-time reflection check at registration: `typeof(TLogger).GetConstructor([typeof(AppType), typeof(LogLevel), typeof(string), typeof(IAcLogWriterBase[])])` — if null, throw `InvalidOperationException` with the expected signature in the message. Cost: one reflection call per registration. Benefit: app fails to start (loud) instead of logging being silently broken (quiet). -## LOG-T-10: Writer exception isolation +## ACCORE-LOG-T-Q6Z1: Writer exception isolation **Priority:** P2 · **Type:** Resilience Currently `AcLoggerBase.Info(...)` and friends do `LogWriters.ForEach(x => x.Info(...))`. A throwing writer (e.g. `SignaRClientLogItemWriter` during network blip, `AcDbLogItemWriter` during a DB outage) takes down the fan-out → subsequent writers in the list never see the message. @@ -84,8 +84,8 @@ Wrap each writer invocation in `try { ... } catch (Exception ex) { Console.Error Must NOT log to `AcLoggerBase` itself inside the catch (reentrancy / infinite loop risk). -## LOG-T-11: Migrate server-side NopCommerce plugin logger setup to DI-factory -**Priority:** P2 · **Type:** Consumer refactor · **Related:** `LOGGING_ISSUES.md#log-i-8`, `../../../AyCode.Services/docs/SIGNALR/SIGNALR_TODO.md#log-t-5` +## ACCORE-LOG-T-W4H9: Migrate server-side NopCommerce plugin logger setup to DI-factory +**Priority:** P2 · **Type:** Consumer refactor · **Related:** `LOGGING_ISSUES.md#accore-log-i-m4c9`, `../../../AyCode.Services/docs/SIGNALR/SIGNALR_TODO.md#accore-sig-t-m5l6` Align the server-side plugin (`Nop.Plugin.Misc.AIPlugin/Infrastructure/PluginNopStartup.cs`) with the client-side setup pattern already used by MAUI / Web / Web.Client consumers. @@ -114,10 +114,10 @@ services.AddAcLoggerFactory(); ### Consequences / checklist - [ ] Consumers of `new Logger(...)` elsewhere in the plugin code must switch to injecting `Func` (DI factory). -- [ ] LOG-I-1 Console.Error noise disappears once the config-reading path is no longer invoked. +- [ ] ACCORE-LOG-I-K7M2 Console.Error noise disappears once the config-reading path is no longer invoked. - [ ] Legacy `AyCode:Logger:LogWriters[]` array in `appsettings.json` becomes unused — decide: **(a)** remove (breaking if any other consumer still reads it), **(b)** keep for back-compat with a comment "superseded by DI, see LOGGING.md". - [ ] Update `Nop.Plugin.Misc.AIPlugin/docs/SIGNALR/README.md:22` — current text still describes `services.AddSingleton(new AcBinaryHubProtocol())` which has NOT been the actual registration for months. - [ ] Verify server startup log — `AcLoggerOptions` must bind cleanly (no "missing section" warnings from `IOptionsMonitor`). -### Why this is a separate TODO from LOG-T-3 -LOG-T-3 is about the **framework-level decision** (keep both patterns vs deprecate legacy). LOG-T-11 is the **consumer-level execution** of that decision for the server plugin — independent of whether LOG-T-3 ultimately deprecates the legacy path or keeps it alive. Migrating the server plugin removes LOG-I-1 noise regardless of LOG-T-3's outcome. +### Why this is a separate TODO from ACCORE-LOG-T-R7L3 +ACCORE-LOG-T-R7L3 is about the **framework-level decision** (keep both patterns vs deprecate legacy). ACCORE-LOG-T-W4H9 is the **consumer-level execution** of that decision for the server plugin — independent of whether ACCORE-LOG-T-R7L3 ultimately deprecates the legacy path or keeps it alive. Migrating the server plugin removes ACCORE-LOG-I-K7M2 noise regardless of ACCORE-LOG-T-R7L3's outcome. diff --git a/AyCode.Core/docs/LOGGING/README.md b/AyCode.Core/docs/LOGGING/README.md index 3810a13..1f164e8 100644 --- a/AyCode.Core/docs/LOGGING/README.md +++ b/AyCode.Core/docs/LOGGING/README.md @@ -120,7 +120,7 @@ Each writer's constructor signature must accept `(AppType, LogLevel, string?)`. ## DI-Based Factory Pattern -Modern, framework-first alternative to the config-reading `AcLoggerBase(string)` ctor. No runtime reflection over writer config; concrete writer types resolved from DI. Recommended for all modern projects (MAUI, WASM, ASP.NET Core) — the config-reading path is filesystem-bound and unsuitable for MAUI/WASM (see `LOGGING_ISSUES.md#log-i-2`). +Modern, framework-first alternative to the config-reading `AcLoggerBase(string)` ctor. No runtime reflection over writer config; concrete writer types resolved from DI. Recommended for all modern projects (MAUI, WASM, ASP.NET Core) — the config-reading path is filesystem-bound and unsuitable for MAUI/WASM (see `LOGGING_ISSUES.md#accore-log-i-r9p3`). ### Consumer setup in Program.cs @@ -199,7 +199,7 @@ For SignalR client setup that wires the same `AcLoggerBase` instance into Micros | Typical use | Legacy / server-side config-driven | Modern DI: MAUI, WASM, ASP.NET Core | | MAUI/WASM-safe | ❌ (filesystem-bound `AcEnv.AppConfiguration`) | ✅ | -Both patterns can coexist — consumer picks per scenario. Related issues: `LOGGING_ISSUES.md`. Planned unification: `LOGGING_TODO.md#log-t-3`. +Both patterns can coexist — consumer picks per scenario. Related issues: `LOGGING_ISSUES.md`. Planned unification: `LOGGING_TODO.md#accore-log-t-r7l3`. ## Core Components diff --git a/AyCode.Core/docs/TOON/README.md b/AyCode.Core/docs/TOON/README.md index 66ca573..c375eb7 100644 --- a/AyCode.Core/docs/TOON/README.md +++ b/AyCode.Core/docs/TOON/README.md @@ -1,6 +1,6 @@ # TOON — Token-Oriented Object Notation -LLM-optimized serializer. Primary goal: **maximize LLM accuracy** via explicit schema/data separation, rich metadata, and unambiguous structure boundaries. Serialize-only (no deserializer — see `TOON_TODO.md#toon-t-6`). +LLM-optimized serializer. Primary goal: **maximize LLM accuracy** via explicit schema/data separation, rich metadata, and unambiguous structure boundaries. Serialize-only (no deserializer — see `TOON_TODO.md#accore-toon-t-f3x1`). Source: `Serializers/Toons/` in this project. diff --git a/AyCode.Core/docs/TOON/TOON_IMPLEMENTATION.md b/AyCode.Core/docs/TOON/TOON_IMPLEMENTATION.md index 00a78b0..4a4e5ef 100644 --- a/AyCode.Core/docs/TOON/TOON_IMPLEMENTATION.md +++ b/AyCode.Core/docs/TOON/TOON_IMPLEMENTATION.md @@ -124,4 +124,4 @@ The context's `StringBuilder` is shared with write helpers: - **Cached per-type metadata** — reflection runs once per type, then hot cache. - **Parallel code paths for `UseIndentation`** — compact mode avoids space emission on `=` and skips blank lines at write time (not a post-process strip). - **Fast-path for primitive values** — `Serialize(value)` with a primitive returns without pool access or reflection. -- **No deserialization** — Toon is intentionally one-way. See `TOON_TODO.md#toon-t-6`. +- **No deserialization** — Toon is intentionally one-way. See `TOON_TODO.md#accore-toon-t-f3x1`. diff --git a/AyCode.Core/docs/TOON/TOON_INFERENCE.md b/AyCode.Core/docs/TOON/TOON_INFERENCE.md index 0eef282..38b3e51 100644 --- a/AyCode.Core/docs/TOON/TOON_INFERENCE.md +++ b/AyCode.Core/docs/TOON/TOON_INFERENCE.md @@ -82,7 +82,7 @@ Useful extra info because LLMs can misjudge narrow integer type sizes: | read-only property (no public setter) | `readonly` | | enum backing field detected (see below) | `enum-type: {EnumName}` | -> ⚠️ **`Age` pattern false positives** — the rule uses `string.Contains("Age", OrdinalIgnoreCase)`, which is not word-boundary-aware. Hits `LanguageId`, `Package*`, `Image*`, `Page*`, `Message*`, `Storage*` and similar. See `TOON_ISSUES.md#toon-i-2` for detected cases and fix options. Lesser risk applies to the `Email`, `Phone`, `Address`, `Url`, `Date`, `Version`, `CreatedAt`, `UpdatedAt`, `DeletedAt` patterns too. +> ⚠️ **`Age` pattern false positives** — the rule uses `string.Contains("Age", OrdinalIgnoreCase)`, which is not word-boundary-aware. Hits `LanguageId`, `Package*`, `Image*`, `Page*`, `Message*`, `Storage*` and similar. See `TOON_ISSUES.md#accore-toon-i-x3h2` for detected cases and fix options. Lesser risk applies to the `Email`, `Phone`, `Address`, `Url`, `Date`, `Version`, `CreatedAt`, `UpdatedAt`, `DeletedAt` patterns too. ## Enum backing field detection diff --git a/AyCode.Core/docs/TOON/TOON_ISSUES.md b/AyCode.Core/docs/TOON/TOON_ISSUES.md index 11097f8..cfb3c4d 100644 --- a/AyCode.Core/docs/TOON/TOON_ISSUES.md +++ b/AyCode.Core/docs/TOON/TOON_ISSUES.md @@ -2,7 +2,7 @@ For planned/actionable work see `TOON_TODO.md`. -## TOON-I-1: `Compact` preset XML doc contradicts code behaviour +## ACCORE-TOON-I-B7L4: `Compact` preset XML doc contradicts code behaviour **Severity:** Trivial (doc-only, no runtime effect) · **Status:** Open (direction not decided) · **Area:** `Serializers/Toons/AcToonSerializerOptions.cs` @@ -48,7 +48,7 @@ var trulyCompact = new AcToonSerializerOptions { ### Related TODO None yet — fix direction not decided. -## TOON-I-2: `Age` inference substring false positive +## ACCORE-TOON-I-X3H2: `Age` inference substring false positive **Severity:** Minor (constraint-only, no runtime effect) · **Status:** Open · **Area:** `Serializers/Toons/AcToonSerializer.Descriptions.cs` → `GetPropertyConstraints` / `GetInferredConstraints` @@ -83,7 +83,7 @@ Explicit `[ToonDescription(Constraints = "...")]` on the affected property (repl ### Related TODO None yet. -## TOON-I-3: Property override duplicated on inheritance in `@types` +## ACCORE-TOON-I-P6V5: Property override duplicated on inheritance in `@types` **Severity:** Minor (schema correctness; LLM may misinterpret) · **Status:** Open · **Area:** Property enumeration — likely `AcToonSerializer.ToonSerializeTypeMetadata.cs` or the shared base in `Serializers/` root. @@ -118,7 +118,7 @@ None — the schema is wrong as-is. Downstream consumers must tolerate the dupli ### Related TODO None yet. -## TOON-I-4: Property order in `@types` is not pure alphabetical +## ACCORE-TOON-I-K4Z9: Property order in `@types` is not pure alphabetical **Severity:** Minor (readability / predictability) · **Status:** Open · **Area:** Property ordering — likely `AcToonSerializer.ToonSerializeTypeMetadata.cs`, inherited from the shared base in `Serializers/` root. diff --git a/AyCode.Core/docs/TOON/TOON_TODO.md b/AyCode.Core/docs/TOON/TOON_TODO.md index 14b0d91..06db0f0 100644 --- a/AyCode.Core/docs/TOON/TOON_TODO.md +++ b/AyCode.Core/docs/TOON/TOON_TODO.md @@ -5,7 +5,7 @@ --- -## TOON-T-1: Tabular array mode (CSV-style headered lists) +## ACCORE-TOON-T-D1R7: Tabular array mode (CSV-style headered lists) **Priority:** P2 · **Type:** Feature (opt-in) · **Origin:** 2026-04-24 LLM-accuracy proposal Emit arrays of homogeneous flat objects with a single column header instead of repeating property names on every element: @@ -27,7 +27,7 @@ When any condition fails → fall back to the current named syntax. Rationale: the CSV pattern is heavily represented in LLM training data; a single header avoids per-row key repetition. Estimated 30-50% token savings on arrays with 50+ rows. Must remain OFF in `Verbose` preset for debug clarity. -## TOON-T-2: Schema-derived type elision in `@data` +## ACCORE-TOON-T-G5M3: Schema-derived type elision in `@data` **Priority:** P2 · **Type:** Feature · **Origin:** 2026-04-24 LLM-accuracy proposal Omit type names on `@data` list elements when: @@ -47,9 +47,9 @@ GenericAttributes = [ ] ``` -Must stay explicit in `Verbose` mode and in polymorphic collections (type name is the discriminator). The main design tension: this slightly erodes the "explicit is better" principle — schema drift in a long conversation could cause silent misinterpretation. Pair with TOON-T-5 to mitigate. +Must stay explicit in `Verbose` mode and in polymorphic collections (type name is the discriminator). The main design tension: this slightly erodes the "explicit is better" principle — schema drift in a long conversation could cause silent misinterpretation. Pair with ACCORE-TOON-T-S6B9 to mitigate. -## TOON-T-3: Schema-declared default values +## ACCORE-TOON-T-J8N6: Schema-declared default values **Priority:** P2 · **Type:** Feature · **Origin:** 2026-04-24 LLM-accuracy proposal Currently `OmitDefaultValues = true` removes fields equal to `default(T)`, but the LLM must guess what the default is. Extend `@types` with explicit per-property defaults so absence becomes unambiguous: @@ -66,9 +66,9 @@ Currently `OmitDefaultValues = true` removes fields equal to `default(T)`, but t Implementation: during `@types` emission, detect the property's `default(T)` value and emit `default-value: ...` when `OmitDefaultValues = true`. `@data` omission then carries documented semantics ("use the schema default"), not implicit guessing. -Deserializer impact: N/A — no deserializer yet (see TOON-T-6). +Deserializer impact: N/A — no deserializer yet (see ACCORE-TOON-T-F3X1). -## TOON-T-4: Reference-handling preset audit +## ACCORE-TOON-T-V2T4: Reference-handling preset audit **Priority:** P3 · **Type:** Configuration review · **Origin:** 2026-04-24 LLM-accuracy proposal The `@N` / `@ref:N` syntax exists and works (see `TOON_FORMAT.md#reference-syntax`). Audit whether the presets activate it aggressively enough: @@ -79,10 +79,10 @@ The `@N` / `@ref:N` syntax exists and works (see `TOON_FORMAT.md#reference-synta Deliverable: a "When to choose which ReferenceHandling mode" section in `TOON_OPTIONS.md` with concrete examples. -## TOON-T-5: Schema hash in `@meta` -**Priority:** P3 · **Type:** Feature (defense-in-depth for TOON-T-2, TOON-T-3) · **Origin:** 2026-04-24 +## ACCORE-TOON-T-S6B9: Schema hash in `@meta` +**Priority:** P3 · **Type:** Feature (defense-in-depth for ACCORE-TOON-T-G5M3, ACCORE-TOON-T-J8N6) · **Origin:** 2026-04-24 -After TOON-T-2 and TOON-T-3 ship, `@data` payloads rely more heavily on a specific `@types` schema. In multi-turn conversations, the LLM's cached schema may drift out of sync with the sender's. +After ACCORE-TOON-T-G5M3 and ACCORE-TOON-T-J8N6 ship, `@data` payloads rely more heavily on a specific `@types` schema. In multi-turn conversations, the LLM's cached schema may drift out of sync with the sender's. Emit a compact schema fingerprint in `@meta`: @@ -96,7 +96,7 @@ Emit a compact schema fingerprint in `@meta`: The prompt template instructs the LLM: *"only use cached schema when the `schema-hash` matches; otherwise request the full schema again."* Cost: ~20-30 tokens per payload. Benefit: silent schema drift becomes detectable. -## TOON-T-6: Deserialization support +## ACCORE-TOON-T-F3X1: Deserialization support **Priority:** P3 · **Type:** Feature (major) · **Origin:** 2026-04-24 during docs migration Toon is currently **serialize-only** — there is no `AcToonDeserializer`. An LLM can produce Toon-formatted responses, but the framework cannot parse them back into C# objects. @@ -105,9 +105,9 @@ Decision needed before implementation: - Is Toon deserialization in-scope? (Primary goal is LLM accuracy — deserialization is mostly useful for LLM-generated outputs.) - Or is `AcBinary`/`AcJson` the intended deserialization path, with Toon strictly a presentation format for LLM inputs? -If in-scope, the parser must handle: `@meta`/`@types`/`@data` sections, reference resolution (`@N` / `@ref:N`), multi-line strings, numeric enum values (requires `@types` for name mapping), tabular arrays (if TOON-T-1 lands), polymorphic collections. +If in-scope, the parser must handle: `@meta`/`@types`/`@data` sections, reference resolution (`@N` / `@ref:N`), multi-line strings, numeric enum values (requires `@types` for name mapping), tabular arrays (if ACCORE-TOON-T-D1R7 lands), polymorphic collections. -## TOON-T-7: Validate benchmark claims before re-adding to docs +## ACCORE-TOON-T-M9Q2: Validate benchmark claims before re-adding to docs **Priority:** P3 · **Type:** Doc correctness · **Origin:** 2026-04-24 during `ToonExtendedInfo.txt` removal The original `ToonExtendedInfo.txt` (deleted during migration) claimed: diff --git a/AyCode.Core/docs/XCUT/README.md b/AyCode.Core/docs/XCUT/README.md index df7ae56..d58b2c5 100644 --- a/AyCode.Core/docs/XCUT/README.md +++ b/AyCode.Core/docs/XCUT/README.md @@ -4,14 +4,14 @@ Canonical home for issues, TODOs, bugs, and critical items that span **two or mo ## When to use `XCUT-*-N` vs a topic-specific ID -- **Single topic** (concern, bug, or planned work inside one domain) → `{TOPIC}-{TYPE}-{N}` in that topic's `{TOPIC}_ISSUES.md` / `{TOPIC}_TODO.md` (e.g., `LOG-I-5` in `LOGGING_ISSUES.md`). -- **Two or more topics** (coordinated change needed across domains, or the issue's root cause spans multiple subsystems) → `XCUT-{TYPE}-{N}` here, with cross-references from each affected topic's file. +- **Single topic** (concern, bug, or planned work inside one domain) → `ACCORE-{TOPIC}-{TYPE}-{XXXX}` in that topic's `{TOPIC}_ISSUES.md` / `{TOPIC}_TODO.md` (e.g., `ACCORE-LOG-I-X7Q1` in `LOGGING_ISSUES.md`). +- **Two or more ACCORE topics** (coordinated change needed across domains, or the issue's root cause spans multiple subsystems) → `ACCORE-XCUT-{TYPE}-{XXXX}` here, with cross-references from each affected topic's file. ## Examples of cross-cutting items -- **`XCUT-I-1: JSON-in-Binary request parameters`** — affects both the BINARY serializer (wire format) and SIGNALR transport (envelope). Neither side can fix it alone; it needs a coordinated client+server+consumer migration. -- *(hypothetical)* `XCUT-T-N` for a shared infrastructure refactor that touches Logger, SignalR, and SourceGenerator simultaneously. -- *(hypothetical)* `XCUT-B-N` for a bug where the symptom appears in one topic but the root cause lives in another. +- **`ACCORE-XCUT-I-X8Q1: JSON-in-Binary request parameters`** — affects both the BINARY serializer (wire format) and SIGNALR transport (envelope). Neither side can fix it alone; it needs a coordinated client+server+consumer migration. +- *(hypothetical)* `ACCORE-XCUT-T-XXXX` for a shared infrastructure refactor that touches Logger, SignalR, and SourceGenerator simultaneously. +- *(hypothetical)* `ACCORE-XCUT-B-XXXX` for a bug where the symptom appears in one topic but the root cause lives in another. ## Files in this folder @@ -21,16 +21,15 @@ Canonical home for issues, TODOs, bugs, and critical items that span **two or mo ## Cross-reference convention 1. **Canonical entry** lives here. Full body: status, affects (list of topics), rationale, migration plan. -2. **Each affected topic** adds a short `### XCUT-{TYPE}-{N}: — cross-ref` section in its own `_ISSUES.md` / `_TODO.md`, pointing back to this canonical entry. -3. The **topic-specific cross-ref** body is one sentence: "See canonical entry at `../XCUT/XCUT_ISSUES.md#xcut-{type}-{n}`" + a 1-2 line summary of what this topic contributes. +2. **Each affected topic** adds a short `### ACCORE-XCUT-{TYPE}-{XXXX}: <title> — cross-ref` section in its own `_ISSUES.md` / `_TODO.md`, pointing back to this canonical entry (with the SAME 4-char suffix as the canonical, since cross-ref pointers are pointers — not duplicate IDs). +3. The **topic-specific cross-ref** body is one sentence: "See canonical entry at `../XCUT/XCUT_ISSUES.md#accore-xcut-{type}-{xxxx}`" + a 1-2 line summary of what this topic contributes. -## How `XCUT-*-N` IDs are numbered +## How `ACCORE-XCUT-*` IDs are formed -Per the `TOPIC_CODES.md` registry: -- Counter is `XCUT` + type (`I` / `T` / `B` / `C`). -- `XCUT-I-1`, `XCUT-I-2`, ... share one counter across all cross-cutting issues regardless of which topics they span. -- `XCUT-T-1`, `XCUT-T-2`, ... share another counter for cross-cutting TODOs. -- Append-only — once assigned, IDs never change. +Per the `REPO_PREFIXES.md` and `TOPIC_CODES.md` registries: +- Format: `ACCORE-XCUT-<TYPE>-<RAND>` where `<TYPE>` is `I` (issue), `T` (TODO), `B` (bug), or `C` (critical), and `<RAND>` is a random 4-character `[A-Z0-9]` suffix. +- All ACCORE cross-cutting issues live in the `ACCORE-XCUT-I-*` namespace, regardless of which topics they span. Same for TODOs (`ACCORE-XCUT-T-*`), bugs (`ACCORE-XCUT-B-*`), critical-severity (`ACCORE-XCUT-C-*`). +- Append-only — once assigned, IDs never change. The random suffix avoids collisions across parallel branches; uniqueness is verified at creation per `REPO_PREFIXES.md` "Random suffix spec". ## Historical note diff --git a/AyCode.Core/docs/XCUT/XCUT_ISSUES.md b/AyCode.Core/docs/XCUT/XCUT_ISSUES.md index 790a65f..152ef89 100644 --- a/AyCode.Core/docs/XCUT/XCUT_ISSUES.md +++ b/AyCode.Core/docs/XCUT/XCUT_ISSUES.md @@ -6,7 +6,7 @@ For planned cross-cutting work, see `XCUT_TODO.md`. --- -## XCUT-I-1: JSON-in-Binary request parameters +## ACCORE-XCUT-I-X8Q1: JSON-in-Binary request parameters **Status:** Closed (2026-04-26, landed in commits `cdd54d3` 2026-04-05 + `3b70070` 2026-04-06) **Affects:** BINARY serializer (wire format) ↔ SIGNALR transport (envelope) ↔ all consuming projects (caller code) @@ -31,10 +31,10 @@ Client→server request parameters previously travelled as JSON inside a Binary - **Wire impact:** No JSON round-trip on the wire for request params. **Breaking change** vs. previous JSON-in-Binary clients/servers — version bump required. - **Equivalent, not literal:** `SignalParams` (object[]-style packed payload) replaced `SignalPostJsonDataMessage<T>` instead of introducing a parallel `SignalPostBinaryDataMessage<T>`. Single unified envelope, fewer hot-path indirections. - **Coordinated change:** client + server + consumer projects updated together in the two commits (BREAKING). All five steps from the original "Do NOT attempt as a side-effect" list completed. -- **Legacy cleanup outstanding (not blocking closure):** `[Obsolete]` wrappers can be deleted once external consumer projects stop referencing them — tracked in `../../../AyCode.Services/docs/SIGNALR/SIGNALR_TODO.md#sig-t-6` (separate from this canonical issue). +- **Legacy cleanup outstanding (not blocking closure):** `[Obsolete]` wrappers can be deleted once external consumer projects stop referencing them — tracked in `../../../AyCode.Services/docs/SIGNALR/SIGNALR_TODO.md#accore-sig-t-s3n8` (separate from this canonical issue). ### Cross-references -- **BINARY_ISSUES.md** (`../BINARY/BINARY_ISSUES.md#xcut-i-1`): cross-ref pointing here -- **SIGNALR_ISSUES.md** (`../../../AyCode.Services/docs/SIGNALR/SIGNALR_ISSUES.md#xcut-i-1`): cross-ref pointing here -- **BINARY_TODO.md#bin-t-1**: migration plan (also marked Closed) +- **BINARY_ISSUES.md** (`../BINARY/BINARY_ISSUES.md#accore-xcut-i-x8q1`): cross-ref pointing here +- **SIGNALR_ISSUES.md** (`../../../AyCode.Services/docs/SIGNALR/SIGNALR_ISSUES.md#accore-xcut-i-x8q1`): cross-ref pointing here +- **BINARY_TODO.md#accore-bin-t-s8p4**: migration plan (also marked Closed) diff --git a/AyCode.Services/docs/SIGNALR/README.md b/AyCode.Services/docs/SIGNALR/README.md index 25e069d..e1979b7 100644 --- a/AyCode.Services/docs/SIGNALR/README.md +++ b/AyCode.Services/docs/SIGNALR/README.md @@ -152,7 +152,7 @@ GetParameterValues(ParameterInfo[]): Type-guided deserialization — each parameter is individually serialized/deserialized with its concrete type, avoiding the `object[]` → dictionary problem of untyped binary deserialization. -> Known concerns and limitations on parameter serialization (per-parameter overhead, AcBinary-only) are tracked in `SIGNALR_ISSUES.md` under `SIG-I-2` and `SIG-I-3`. +> Known concerns and limitations on parameter serialization (per-parameter overhead, AcBinary-only) are tracked in `SIGNALR_ISSUES.md` under `ACCORE-SIG-I-L5K3` and `ACCORE-SIG-I-H8D6`. ## Response Patterns diff --git a/AyCode.Services/docs/SIGNALR/SIGNALR_ISSUES.md b/AyCode.Services/docs/SIGNALR/SIGNALR_ISSUES.md index ee9d1f2..6deaa5d 100644 --- a/AyCode.Services/docs/SIGNALR/SIGNALR_ISSUES.md +++ b/AyCode.Services/docs/SIGNALR/SIGNALR_ISSUES.md @@ -2,7 +2,7 @@ ## Protocol -### SIG-I-1: Server-side IsRawBytesData pre-serialize +### ACCORE-SIG-I-R4W7: Server-side IsRawBytesData pre-serialize **Status:** Open **Affects:** `AcWebSignalRHubBase.SendMessageToClient` @@ -11,7 +11,7 @@ The server forwards the client's `IsRawBytesData` flag in the response `SignalPa **Plan:** Remove `IsRawBytesData` forwarding from server response path. The client should use `SignalDataType` for typed deserialization and explicit `byte[]` type for raw data. -### SIG-I-2: Parameter serialization is per-parameter +### ACCORE-SIG-I-L5K3: Parameter serialization is per-parameter **Status:** Open **Affects:** `SignalParams.SetParameterValues` / `GetParameterValues` @@ -20,7 +20,7 @@ Each parameter is individually serialized via `ToBinary()` / `BinaryTo(Type)` **Possible optimization:** Batch fast-path — single serialization context for all parameters. Benchmark first. -### SIG-I-3: Parameter serialization is AcBinary only +### ACCORE-SIG-I-H8D6: Parameter serialization is AcBinary only **Status:** Open **Affects:** `SignalParams.SetParameterValues` / `GetParameterValues` @@ -29,7 +29,7 @@ Uses `ToBinary()` / `BinaryTo()` exclusively. JSON parameter support would requi ## Transport -### SIG-I-4: BufferWriterChunkSize defaults to 64KB for SignalR +### ACCORE-SIG-I-P1J4: BufferWriterChunkSize defaults to 64KB for SignalR **Status:** Closed (2026-04-25, retroactive — was `Status: DONE` pre-LLMP-DEC-44 vocabulary normalization) **Affects:** `AcBinaryHubProtocol` constructor, write path @@ -43,7 +43,7 @@ The framework's `BufferWriterChunkSize` default was 64KB, suboptimal for SignalR - **Scope:** Override is SignalR-specific. Non-SignalR paths keep the 64KB default — this is intentional and stable behaviour now. - **Date:** Code change predates this status update; the entry was already `Status: DONE` before the LLMP-DEC-44 vocabulary normalization. The current update only formalizes it as `Closed` per the new 3-value convention. -### SIG-I-5: WebSocket buffer sizes are hardcoded +### ACCORE-SIG-I-N3V8: WebSocket buffer sizes are hardcoded **Status:** Open **Affects:** `AcSignalRClientBase` connection setup @@ -52,7 +52,7 @@ Transport max message size (30MB) and application buffer (30MB) are hardcoded. S ## DataSource -### SIG-I-6: GetAll returns raw byte[] for populate/merge +### ACCORE-SIG-I-T7S2: GetAll returns raw byte[] for populate/merge **Status:** Open **Affects:** `AcSignalRDataSource.LoadDataSourceAsync` @@ -63,7 +63,7 @@ The `GetAll` path uses `IsRawBytesData = true` to receive raw `byte[]` from the ## Server-side Setup & DI -### SIG-I-7: Server-side NopCommerce plugin AcBinaryHubProtocolOptions not bound from appsettings +### ACCORE-SIG-I-B5G9: Server-side NopCommerce plugin AcBinaryHubProtocolOptions not bound from appsettings **Status:** Open · **Severity:** Minor (works, but hardcoded + bypasses DI logger) · **Area:** Consumer adoption gap in `Nop.Plugin.Misc.AIPlugin/Infrastructure/PluginNopStartup.cs` @@ -81,19 +81,19 @@ Current `PluginNopStartup.ConfigureServices`: What's missing: - No `services.Configure<AcBinaryHubProtocolOptions>(configuration.GetSection("AyCode:SignalR:Protocol"))` → `ProtocolMode`, `BufferSize`, `WaitForFlush`, `FlushTimeout` are all hardcoded / default. - The `appsettings.json` has no `AyCode:SignalR` (or equivalent) section at all — so per-deploy tuning (e.g. increasing `FlushTimeout` for a satellite link, switching `ProtocolMode` for diagnostics) requires a code change + redeploy. -- Manual `new Logger(...)` sidesteps the DI `ILogger<AcBinaryHubProtocol>` auto-resolution that `BuildProtocol` provides → creates a parallel logger instance (see `../../../AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md#log-i-8`). +- Manual `new Logger(...)` sidesteps the DI `ILogger<AcBinaryHubProtocol>` auto-resolution that `BuildProtocol` provides → creates a parallel logger instance (see `../../../AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md#accore-log-i-m4c9`). ### Fix direction -See `SIGNALR_TODO.md#sig-t-5`. +See `SIGNALR_TODO.md#accore-sig-t-m5l6`. ### Related -- `../../../AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md#log-i-8` (sibling gap — same plugin, logger setup) -- `SIG-I-8` (client-side equivalent — `HubConnectionBuilder.Services` inner DI isolation forces a different workaround) +- `../../../AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md#accore-log-i-m4c9` (sibling gap — same plugin, logger setup) +- `ACCORE-SIG-I-K6F1` (client-side equivalent — `HubConnectionBuilder.Services` inner DI isolation forces a different workaround) - Plugin doc drift: `Nop.Plugin.Misc.AIPlugin/docs/SIGNALR/README.md:22` documents `services.AddSingleton<IHubProtocol>(new AcBinaryHubProtocol())` — the actual code uses `.AddAcBinaryProtocol(opts => {...})`. Doc needs a rewrite. ## Client-side Setup & DI -### SIG-I-8: HubConnectionBuilder inner DI isolation +### ACCORE-SIG-I-K6F1: HubConnectionBuilder inner DI isolation **Status:** Open **Affects:** Consumer client setup in `Program.cs` (MAUI, WASM, ASP.NET Core server prerender) @@ -108,7 +108,7 @@ hubBuilder.AddAcBinaryProtocol(protocolOpts); ## Dispatch -### SIG-I-9: First-call null response (observed) +### ACCORE-SIG-I-X4M7: First-call null response (observed) **Status:** Open **Affects:** `PostDataAsync<T>` awaiter / OnReceiveMessage → pending-request correlation @@ -124,12 +124,12 @@ Log timeline: Hypothesis (unverified): `PostDataAsync<T>` awaiter's null-mapping path misroutes the parsed result, or `requestId → Task<T>` correlation has a race on the first response of a fresh connection. Client auto-retry hides the user-visible impact. -**Related TODO:** `SIGNALR_TODO.md#sig-t-1` +**Related TODO:** `SIGNALR_TODO.md#accore-sig-t-j2p5` ## Cross-cutting (canonical home: `AyCode.Core` repo's `docs/XCUT/`) -### XCUT-I-1: JSON-in-Binary request parameters — cross-ref +### ACCORE-XCUT-I-X8Q1: JSON-in-Binary request parameters — cross-ref **Status:** Closed (2026-04-26, see canonical entry). -Canonical entry: **`../../../AyCode.Core/docs/XCUT/XCUT_ISSUES.md#xcut-i-1`**. Summary: SignalR transport previously carried `SignalPostJsonDataMessage<T>` (JSON inside a Binary envelope) for request params, while response path was pure Binary. Replacement landed in commits `cdd54d3` + `3b70070`: `SignalParams` (length-prefixed binary pack/unpack) replaces the JSON envelope, coordinated across BINARY serializer + SIGNALR transport + consumer projects. **Breaking change** for older clients. +Canonical entry: **`../../../AyCode.Core/docs/XCUT/XCUT_ISSUES.md#accore-xcut-i-x8q1`**. Summary: SignalR transport previously carried `SignalPostJsonDataMessage<T>` (JSON inside a Binary envelope) for request params, while response path was pure Binary. Replacement landed in commits `cdd54d3` + `3b70070`: `SignalParams` (length-prefixed binary pack/unpack) replaces the JSON envelope, coordinated across BINARY serializer + SIGNALR transport + consumer projects. **Breaking change** for older clients. diff --git a/AyCode.Services/docs/SIGNALR/SIGNALR_TODO.md b/AyCode.Services/docs/SIGNALR/SIGNALR_TODO.md index ccf4026..c436ab7 100644 --- a/AyCode.Services/docs/SIGNALR/SIGNALR_TODO.md +++ b/AyCode.Services/docs/SIGNALR/SIGNALR_TODO.md @@ -5,12 +5,12 @@ --- -## SIG-T-1: Diagnose first-call null in PostDataAsync<T> -**Priority:** P2 · **Type:** Investigation · **Related:** `SIGNALR_ISSUES.md#issue-02` +## ACCORE-SIG-T-J2P5: Diagnose first-call null in PostDataAsync<T> +**Priority:** P2 · **Type:** Investigation · **Related:** `SIGNALR_ISSUES.md#accore-sig-i-l5k3` Reproduce the `GetProductDtos_80`-style first-call null. Add trace logs to `PostDataAsync<T>` awaiter path and `OnReceiveMessage → pending request` dictionary lookup. Verify `requestId → Task<T>` correlation on the very first chunked response of a fresh connection. -## SIG-T-2: Document asymmetric send/receive capability +## ACCORE-SIG-T-W8R3: Document asymmetric send/receive capability **Priority:** P1 · **Type:** Docs Current behaviour: sender selects `BinaryProtocolMode` independently; receiver detects the wire format from the first byte (`CHUNK_START=200` → chunked path; else non-chunked). This means client and server can run DIFFERENT `ProtocolMode` settings independently — a core feature amplifying interoperability. @@ -20,20 +20,20 @@ Document in `../SIGNALR_BINARY_PROTOCOL/README.md` as a dedicated "Asymmetric se - Third-party client on NuGet can pick any mode → server doesn't care - Gradual mode rollouts possible (no synchronized deploy) -## SIG-T-3: Code-level guard for FlushTimeout < ClientTimeoutInterval +## ACCORE-SIG-T-D7Q4: Code-level guard for FlushTimeout < ClientTimeoutInterval **Priority:** P2 · **Type:** Feature `AcBinaryHubProtocolOptions.Validate()` currently documents (in XML doc) that `FlushTimeout` should be less than the SignalR `HubOptions.ClientTimeoutInterval`, but there is no code-level check. Add validation at protocol registration time — if both options are resolvable from the DI scope, verify the constraint and emit a startup warning (or throw, pending decision). -## SIG-T-4: `BinaryProtocolMode.Auto` — adaptive send-mode -**Priority:** P3 · **Type:** Feature · **Related:** `../SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_TODO.md#sbp-t-3` +## ACCORE-SIG-T-V9H1: `BinaryProtocolMode.Auto` — adaptive send-mode +**Priority:** P3 · **Type:** Feature · **Related:** `../SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_TODO.md#accore-sbp-t-l1v4` Design: on first received message, inspect first byte to determine peer's send format. On subsequent sends, match it (subject to local-platform constraints, e.g. WASM never actually sends AsyncSegment). Per-`HubConnection` state. Optional upfront handshake-extension negotiation as an alternative — see wire-level TODO. -## SIG-T-5: Server-side NopCommerce plugin — expose `AcBinaryHubProtocolOptions` via appsettings -**Priority:** P2 · **Type:** Consumer refactor · **Related:** `SIGNALR_ISSUES.md#sig-i-7`, `../../../AyCode.Core/docs/LOGGING/LOGGING_TODO.md#log-t-11` +## ACCORE-SIG-T-M5L6: Server-side NopCommerce plugin — expose `AcBinaryHubProtocolOptions` via appsettings +**Priority:** P2 · **Type:** Consumer refactor · **Related:** `SIGNALR_ISSUES.md#accore-sig-i-b5g9`, `../../../AyCode.Core/docs/LOGGING/LOGGING_TODO.md#accore-log-t-w4h9` -Bind `AcBinaryHubProtocolOptions` from `appsettings.json` instead of hardcoding `ProtocolMode` and constructing a manual `Logger` instance in `PluginNopStartup.cs`. This sibling task is paired with LOGGING_TODO.md#log-t-11 (same plugin, logger-setup migration) — best landed in one commit. +Bind `AcBinaryHubProtocolOptions` from `appsettings.json` instead of hardcoding `ProtocolMode` and constructing a manual `Logger` instance in `PluginNopStartup.cs`. This sibling task is paired with LOGGING_TODO.md#accore-log-t-w4h9 (same plugin, logger-setup migration) — best landed in one commit. ### Target diff ```csharp @@ -65,7 +65,7 @@ services.AddSignalR(hubOptions => { /* unchanged */ }) ``` ### Consequences / checklist -- [ ] `new Logger(...)` line removed from SignalR registration → server-side logger now goes through the DI factory (see LOGGING_TODO.md#log-t-11). +- [ ] `new Logger(...)` line removed from SignalR registration → server-side logger now goes through the DI factory (see LOGGING_TODO.md#accore-log-t-w4h9). - [ ] Per-deploy tuning possible without recompile: switching `ProtocolMode` for diagnostics, extending `FlushTimeout` for slow links, adjusting `BufferSize` for different Kestrel slab sizes. - [ ] `Name` stays at `"acbinary"` default — changing it would break wire-level compat with existing clients. - [ ] `AcBinaryHubProtocolOptions.Validate()` still runs — invalid config (e.g. `ProtocolMode=AsyncSegment` on a WASM server, which is impossible here but hypothetically) throws at startup. @@ -74,10 +74,10 @@ services.AddSignalR(hubOptions => { /* unchanged */ }) ### Why this belongs in AyCode.Services (framework layer) docs The gap is consumer-level, but the canonical "server-side registration recipe" is a FRAMEWORK responsibility — LOGGING.md already shows it for the logger side. Adding a matching recipe to `../SIGNALR_BINARY_PROTOCOL/README.md#Registration in Program.cs → Server` would prevent the next consumer from making the same mistake. That doc update is part of this TODO's acceptance criteria. -## SIG-T-6: Delete legacy `[Obsolete]` JSON-in-Binary wrappers -**Priority:** P3 · **Type:** Cleanup · **Related:** `../../../AyCode.Core/docs/XCUT/XCUT_ISSUES.md#xcut-i-1` (closed canonical), `../../../AyCode.Core/docs/BINARY/BINARY_TODO.md#bin-t-1` (closed) +## ACCORE-SIG-T-S3N8: Delete legacy `[Obsolete]` JSON-in-Binary wrappers +**Priority:** P3 · **Type:** Cleanup · **Related:** `../../../AyCode.Core/docs/XCUT/XCUT_ISSUES.md#accore-xcut-i-x8q1` (closed canonical), `../../../AyCode.Core/docs/BINARY/BINARY_TODO.md#accore-bin-t-s8p4` (closed) -Now that XCUT-I-1 / BIN-T-1 have landed and the wire format no longer uses JSON-in-Binary, the `[Obsolete]` wrapper types in `IAcSignalRHubClient.cs:60-111` can be deleted: +Now that ACCORE-XCUT-I-X8Q1 / ACCORE-BIN-T-S8P4 have landed and the wire format no longer uses JSON-in-Binary, the `[Obsolete]` wrapper types in `IAcSignalRHubClient.cs:60-111` can be deleted: - `SignalPostJsonMessage` - `SignalPostJsonDataMessage<T>` - `SignalPostMessage<T>` diff --git a/AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_ISSUES.md b/AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_ISSUES.md index ec295ab..045ce16 100644 --- a/AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_ISSUES.md +++ b/AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_ISSUES.md @@ -3,7 +3,7 @@ For planned/actionable work see `SIGNALR_BINARY_PROTOCOL_TODO.md`. For higher-level SignalR abstractions see `../SIGNALR/SIGNALR_ISSUES.md`. -## SBP-I-1: AsyncSegment send-path unsupported on WebAssembly +## ACCORE-SBP-I-F6T2: AsyncSegment send-path unsupported on WebAssembly **Severity:** Major (on WASM) · **Status:** Open · **Area:** `AsyncPipeWriterOutput` / WASM runtime @@ -18,7 +18,7 @@ For higher-level SignalR abstractions see `../SIGNALR/SIGNALR_ISSUES.md`. ### Related TODO None — architectural constraint of browser WASM threading model. -## SBP-I-2: StaticWebAssets SDK "Illegal characters" noise (consumer build) +## ACCORE-SBP-I-G4B5: StaticWebAssets SDK "Illegal characters" noise (consumer build) **Severity:** Cosmetic (non-blocking) · **Status:** Open · **Area:** SDK, not our code diff --git a/AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_TODO.md b/AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_TODO.md index a55678e..8a712ea 100644 --- a/AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_TODO.md +++ b/AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_TODO.md @@ -5,7 +5,7 @@ --- -## SBP-T-1: SegmentBufferReader isolated unit tests +## ACCORE-SBP-T-P8X9: SegmentBufferReader isolated unit tests **Priority:** P1 · **Type:** Test coverage Original `vast-brewing-moonbeam` refactor plan (chunked receive-path) listed these tests in its verification section; they were never written. Needed: @@ -14,7 +14,7 @@ Original `vast-brewing-moonbeam` refactor plan (chunked receive-path) listed the - Missed-signal double-check pattern under `ManualResetEventSlim` reset - `Dispose` lifecycle (buffer pool return, old-buffer cleanup) -## SBP-T-2: Chunked protocol integration test +## ACCORE-SBP-T-K3J7: Chunked protocol integration test **Priority:** P1 · **Type:** Test coverage End-to-end round-trip: @@ -27,8 +27,8 @@ Cover asymmetric cases: - Bytes sender, AsyncSegment receiver - WASM-downgraded sender (Segment), server AsyncSegment receiver -## SBP-T-3: `BinaryProtocolMode.Auto` wire-detection implementation -**Priority:** P3 · **Type:** Feature · **Related:** `../SIGNALR/SIGNALR_TODO.md#sig-t-4` +## ACCORE-SBP-T-L1V4: `BinaryProtocolMode.Auto` wire-detection implementation +**Priority:** P3 · **Type:** Feature · **Related:** `../SIGNALR/SIGNALR_TODO.md#accore-sig-t-v9h1` Client-side adaptive mode: on first received message, inspect first payload byte: - `CHUNK_START (200)` → peer uses AsyncSegment → match it on subsequent sends (subject to local-platform constraint — WASM safety-net overrides to Segment) @@ -36,8 +36,8 @@ Client-side adaptive mode: on first received message, inspect first payload byte Per-`HubConnection` state. Requires changes to `BinaryProtocolMode` enum + detection wiring in `TryParseMessage`. -## SBP-T-4: SignalR handshake-extension for upfront mode negotiation -**Priority:** P3 · **Type:** Feature · **Related:** SBP-T-3 +## ACCORE-SBP-T-R6D2: SignalR handshake-extension for upfront mode negotiation +**Priority:** P3 · **Type:** Feature · **Related:** ACCORE-SBP-T-L1V4 Alternative to wire-detection: use SignalR handshake message's `extensions` JSON field to carry protocol-capability info — e.g. ```json @@ -57,7 +57,7 @@ Zero first-message overhead, fully explicit. Both sides advertise their send-mod These ideas were captured because the **wider binary-protocol market is currently silent** on these features (no major .NET binary serializer ships built-in encryption / compression / tracing). Real differentiation potential, but only if executed correctly. -## SBP-T-5: Optional payload encryption (`AcEncryptionOptions`) +## ACCORE-SBP-T-H7M5: Optional payload encryption (`AcEncryptionOptions`) **Priority:** P3 — IDEA · **Type:** Feature (NuGet competitiveness) · **Status:** Open ### Niches where TLS alone is insufficient @@ -83,7 +83,7 @@ These ideas were captured because the **wider binary-protocol market is currentl - Benchmark plan: zero-copy loss percentage, AsyncSegment chunk overhead. - Decorator API sketch reviewed. -## SBP-T-6: Optional message compression with `MinSize` threshold +## ACCORE-SBP-T-N9F3: Optional message compression with `MinSize` threshold **Priority:** P3 — IDEA · **Type:** Feature (NuGet competitiveness) · **Status:** Open ### Niches @@ -134,7 +134,7 @@ In `AsyncSegment` mode the total message size is unknown until `CHUNK_END`, so a **Default decision: (C)** — `AlwaysCompressInAsyncSegment = true`. Override possible per-options. Document the trade-off explicitly so users picking `AsyncSegment + compression + small messages` know what they're choosing. ### Other design constraints -- **Decorator pattern**, same as SBP-T-5. +- **Decorator pattern**, same as ACCORE-SBP-T-H7M5. - **Algorithm-pluggable** — at minimum LZ4 (fastest), Brotli (best ratio for text), Zstd (modern balanced). Default **none**. - **Order with encryption matters**: compress FIRST, encrypt AFTER (compressing ciphertext is futile). - **Wire marker byte** — 1-byte algorithm ID prefix so decoder knows what to expand. `0x00` = uncompressed (the small-message path), other values = algorithm IDs. @@ -147,7 +147,7 @@ In `AsyncSegment` mode the total message size is unknown until `CHUNK_END`, so a - AsyncSegment interaction documented — the (C) default with override path; sample log output showing `MinSize`-skipped vs. compressed messages for diagnostics. - Fallback / negotiation strategy: what happens if peer can't decompress? (Suggested: wire-marker `0x00` always works since it means "uncompressed" — sender can downgrade per-message if peer signals incompatibility, similar to HTTP `Accept-Encoding` semantics.) -## SBP-T-7: OpenTelemetry tracing integration +## ACCORE-SBP-T-J5W8: OpenTelemetry tracing integration **Priority:** P3 — IDEA · **Type:** Feature (NuGet competitiveness) · **Status:** Open ### Niches @@ -165,7 +165,7 @@ In `AsyncSegment` mode the total message size is unknown until `CHUNK_END`, so a - API sketch with sample exporter wiring (Jaeger / OTel Collector). - Hot-path branch verification — when `ActivitySource == null`, JIT must eliminate the tracing code completely. -## SBP-T-8: Optional HMAC signing (without encryption) +## ACCORE-SBP-T-B3K6: Optional HMAC signing (without encryption) **Priority:** P3 — IDEA · **Type:** Feature (NuGet competitiveness) · **Status:** Open ### Niches diff --git a/AyCode.Services/docs/adr/0001-acbinary-decorator-feature-stack-design.md b/AyCode.Services/docs/adr/0001-acbinary-decorator-feature-stack-design.md index 577674a..430b356 100644 --- a/AyCode.Services/docs/adr/0001-acbinary-decorator-feature-stack-design.md +++ b/AyCode.Services/docs/adr/0001-acbinary-decorator-feature-stack-design.md @@ -8,7 +8,7 @@ Proposed (2026-04-25) `AcBinaryHubProtocol` (`AyCode.Services/SignalRs/AcBinaryHubProtocol.cs`) is the AyCode binary `IHubProtocol` implementation for SignalR — the canonical wire format for binary hub messaging. The base implementation handles AcBinary serialization, three protocol modes (`Bytes` / `Segment` / `AsyncSegment`), chunked AsyncSegment streaming, and the base layer of features every consumer needs. -A class of optional features is planned for NuGet competitiveness (currently P3 idea status, see `../SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_TODO.md` SBP-T-5..8): **encryption**, **compression with MinSize**, **OpenTelemetry tracing**, **HMAC signing-only**. These features: +A class of optional features is planned for NuGet competitiveness (currently P3 idea status, see `../SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_TODO.md` ACCORE-SBP-T-H7M5..8): **encryption**, **compression with MinSize**, **OpenTelemetry tracing**, **HMAC signing-only**. These features: - Are NOT current-priority — speculative additions for public NuGet positioning. - Must be **opt-in** (default-off, zero overhead when not used). @@ -24,7 +24,7 @@ Adopt the **decorator-chain pattern** for composing optional features onto `AcBi ### `AcHubProtocolDecoratorBase` abstract base -A new abstract class in `AyCode.Services/SignalRs/` (concrete API spec is impl-level, tracked as `SBP-T-9` in `SIGNALR_BINARY_PROTOCOL_TODO.md`): +A new abstract class in `AyCode.Services/SignalRs/` (concrete API spec is impl-level, tracked as a forthcoming TODO in `SIGNALR_BINARY_PROTOCOL_TODO.md`, no ID assigned yet): - Delegates passthrough `IHubProtocol` members (`Name`, `Version`, `TransferFormat`, `IsVersionSupported`, `GetMessageBytes`) to the wrapped inner protocol. - Exposes `protected IHubProtocol Inner { get; }` to derived classes. @@ -72,7 +72,7 @@ At connection setup (1 application-level handshake roundtrip after SignalR's pro **Mismatch handling**: asymmetric registration (one side has decorator, other doesn't) → handshake fails fast with a logged reason at `Error` level. Per-message asymmetry (handshake-skip artefacts) is handled by the decorator-failure unified protocol below. -The app-level handshake mechanism's concrete shape (Option A: a special `__ac_handshake` HubMessage as first message; Option B: wire-level `WriteHandshake` virtual on `AcHubProtocolDecoratorBase`) is **deferred to a follow-up** — the umbrella commits to "handshake-based" but does not pick the mechanism. Tracked as part of `SBP-T-9`. +The app-level handshake mechanism's concrete shape (Option A: a special `__ac_handshake` HubMessage as first message; Option B: wire-level `WriteHandshake` virtual on `AcHubProtocolDecoratorBase`) is **deferred to a follow-up** — the umbrella commits to "handshake-based" but does not pick the mechanism. Tracked as part of the forthcoming TODO. ### Per-message `IsCompressed` flag — semantic (A): standalone byte @@ -186,9 +186,9 @@ A v1 client (no decorators registered) connecting to a v2 server (decorators in ### Follow-ups required -1. **`AcHubProtocolDecoratorBase` implementation** — abstract class added to `AyCode.Services/SignalRs/`; tracked as new TODO entry `SBP-T-9` in `SIGNALR_BINARY_PROTOCOL_TODO.md`. Implementation deferred until at least one leaf ADR (0002-0005) reaches `Status: Accepted`. -2. **Stacking-order validation in DI** — `AddAcEncryption` / `AddAcSigning` / `AddAcCompression` extension methods should warn or throw if registered in a non-canonical order (concrete impl part of `SBP-T-9`). -3. **App-level handshake mechanism design** — Option A (`__ac_handshake` HubMessage as first message) vs Option B (`WriteHandshake` virtual on `AcHubProtocolDecoratorBase`). Tracked as part of `SBP-T-9`. +1. **`AcHubProtocolDecoratorBase` implementation** — abstract class added to `AyCode.Services/SignalRs/`; tracked as a new forthcoming TODO entry in `SIGNALR_BINARY_PROTOCOL_TODO.md` (no ID assigned yet). Implementation deferred until at least one leaf ADR (0002-0005) reaches `Status: Accepted`. +2. **Stacking-order validation in DI** — `AddAcEncryption` / `AddAcSigning` / `AddAcCompression` extension methods should warn or throw if registered in a non-canonical order (concrete impl part of the forthcoming TODO). +3. **App-level handshake mechanism design** — Option A (`__ac_handshake` HubMessage as first message) vs Option B (`WriteHandshake` virtual on `AcHubProtocolDecoratorBase`). Tracked as part of the forthcoming TODO. 4. **Benchmark scaffolding** — message-granularity vtable cost measurement for the "negligible" claim. Each leaf ADR's acceptance criteria includes verifying this in their feature's context. 5. **Cross-references** — Step 8 of the `adr-author` skill: this ADR links to the 4 forthcoming leaf ADRs (0002-0005); `../SIGNALR_BINARY_PROTOCOL/README.md` gets a new `## Related ADRs` section pointing back to `0001-acbinary-decorator-feature-stack-design.md`. @@ -210,6 +210,6 @@ A v1 client (no decorators registered) connecting to a v2 server (decorators in ## Related -- Related TODOs: `../SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_TODO.md` SBP-T-5 (encryption), SBP-T-6 (compression+MinSize), SBP-T-7 (tracing), SBP-T-8 (signing); SBP-T-9 (`AcHubProtocolDecoratorBase` impl + handshake mechanism — to be added in Step 8 cross-reference round). +- Related TODOs: `../SIGNALR_BINARY_PROTOCOL/SIGNALR_BINARY_PROTOCOL_TODO.md` ACCORE-SBP-T-H7M5 (encryption), ACCORE-SBP-T-N9F3 (compression+MinSize), ACCORE-SBP-T-J5W8 (tracing), ACCORE-SBP-T-B3K6 (signing); the forthcoming `AcHubProtocolDecoratorBase` impl + handshake-mechanism TODO (to be added in Step 8 cross-reference round). - Forthcoming ADRs: 0002 (payload encryption), 0003 (message compression with MinSize), 0004 (OpenTelemetry tracing), 0005 (HMAC signing-only) — all will declare `Depends on: ADR-0001`. - Topic-folder cross-ref: `../SIGNALR_BINARY_PROTOCOL/README.md` to add `## Related ADRs` section in Step 8. diff --git a/docs/AUTH/AUTH_ISSUES.md b/docs/AUTH/AUTH_ISSUES.md index d389fb3..504f3bf 100644 --- a/docs/AUTH/AUTH_ISSUES.md +++ b/docs/AUTH/AUTH_ISSUES.md @@ -7,7 +7,7 @@ For the architectural decision that scoped this topic, see [`../adr/0001-user-be ## Active entries -*(No `AUTH-I-N` entries yet — topic just created. Currently-relevant security entries live as `LOG-I-9` and `LOG-I-10` in [`LOGGING_ISSUES.md`](../../AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md), pre-migration. ADR 0001's "Status migration on AUTH topic creation" follow-up is the planned home transfer — separate user-approved task.)* +*(No `AUTH-I-N` entries yet — topic just created. Currently-relevant security entries live as `ACCORE-LOG-I-P5W3` and `ACCORE-LOG-I-K1Z7` in [`LOGGING_ISSUES.md`](../../AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md), pre-migration. ADR 0001's "Status migration on AUTH topic creation" follow-up is the planned home transfer — separate user-approved task.)* ## Entry format diff --git a/docs/AUTH/README.md b/docs/AUTH/README.md index 568e53b..55971eb 100644 --- a/docs/AUTH/README.md +++ b/docs/AUTH/README.md @@ -45,10 +45,10 @@ Sections to come (mirrors ADR 0001 Follow-up "Implementation" + "Consumer wiring JWT signing keys, access tokens, refresh tokens, password hashes, and OAuth client secrets MUST NEVER appear in log output. Logged secrets leak via the same channels as the logs themselves (file system, retention archives, screenshots, bug reports). For diagnostics, log only metadata (user ID, expiry, issuer) or hash prefixes — never the raw value. -This guideline emerged from `LOG-I-9` and `LOG-I-10` (both `Closed (2026-04-25)` via `#if DEBUG` gating per ADR 0001 pre-flight). Pending `LOG-T-12` proposes adding a generalized framework-level guideline section to [`LOGGING/README.md`](../../AyCode.Core/docs/LOGGING/README.md); when that lands, it becomes the canonical home and this section trims to a cross-ref. +This guideline emerged from `ACCORE-LOG-I-P5W3` and `ACCORE-LOG-I-K1Z7` (both `Closed (2026-04-25)` via `#if DEBUG` gating per ADR 0001 pre-flight). A pending TODO (forthcoming entry in `LOGGING_TODO.md`, no ID assigned yet) proposes adding a generalized framework-level guideline section to [`LOGGING/README.md`](../../AyCode.Core/docs/LOGGING/README.md); when that lands, it becomes the canonical home and this section trims to a cross-ref. ## Cross-references - **ADR**: [`../adr/0001-user-bearer-token-flow.md`](../adr/0001-user-bearer-token-flow.md) — architectural decision. - **Topic registry**: `AUTH` row in [`TOPIC_CODES.md`](../../.github/skills/docs-check/references/TOPIC_CODES.md) (added in `LLMP-DEC-49`). -- **Sibling pre-migration**: `LOG-I-9` / `LOG-I-10` in [`LOGGING_ISSUES.md`](../../AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md) — currently homed in LOGGING; ADR 0001 Follow-up "Status migration on AUTH topic creation" lists these as candidates for relocation here as `AUTH-I-N` with `Superseded by` cross-refs in LOGGING. Migration NOT yet performed — separate user-approved follow-up. +- **Sibling pre-migration**: `ACCORE-LOG-I-P5W3` / `ACCORE-LOG-I-K1Z7` in [`LOGGING_ISSUES.md`](../../AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md) — currently homed in LOGGING; ADR 0001 Follow-up "Status migration on AUTH topic creation" lists these as candidates for relocation here as `AUTH-I-N` with `Superseded by` cross-refs in LOGGING. Migration NOT yet performed — separate user-approved follow-up. diff --git a/docs/CONVENTIONS.md b/docs/CONVENTIONS.md index 3480373..c5b8dea 100644 --- a/docs/CONVENTIONS.md +++ b/docs/CONVENTIONS.md @@ -33,7 +33,7 @@ See `AyCode.Services/docs/SIGNALR/README.md` for full architecture documentation ### ⚠️ Temporary: JSON-in-Binary Request Parameters -Client→server request parameters currently use a JSON-inside-Binary envelope — a cross-cutting tech debt planned for migration to pure Binary. Canonical entry: `AyCode.Core/AyCode.Core/docs/XCUT/XCUT_ISSUES.md#xcut-i-1`. Cross-refs: `BINARY_ISSUES.md#xcut-i-1` (serializer side) and `SIGNALR_ISSUES.md#xcut-i-1` (transport side). Migration is tracked in `BINARY_TODO.md#bin-t-1`. Do NOT attempt as a side-effect of unrelated work — requires coordinated client+server+consuming-project changes. +Client→server request parameters currently use a JSON-inside-Binary envelope — a cross-cutting tech debt planned for migration to pure Binary. Canonical entry: `AyCode.Core/AyCode.Core/docs/XCUT/XCUT_ISSUES.md#accore-xcut-i-x8q1`. Cross-refs: `BINARY_ISSUES.md#accore-xcut-i-x8q1` (serializer side) and `SIGNALR_ISSUES.md#accore-xcut-i-x8q1` (transport side). Migration is tracked in `BINARY_TODO.md#accore-bin-t-s8p4`. Do NOT attempt as a side-effect of unrelated work — requires coordinated client+server+consuming-project changes. ## Testing diff --git a/docs/adr/0001-user-bearer-token-flow.md b/docs/adr/0001-user-bearer-token-flow.md index 242b11c..3370085 100644 --- a/docs/adr/0001-user-bearer-token-flow.md +++ b/docs/adr/0001-user-bearer-token-flow.md @@ -13,7 +13,7 @@ The framework has partial JWT infrastructure on the server side (`AcLoginService - SignalR transport has no access-token provider wired into the hub-connection builder. - Server has no `AddJwtBearer` registration, no `[Authorize]` plumbing, and no per-tag authorization for the single-method `OnReceiveMessage(int tag, ...)` SignalR dispatch. -Two security defects in `AcLoginServiceServer.GenerateAccessToken` (JWT signing key + issued access token written to logger) were addressed pre-flight as `LOG-I-9` and `LOG-I-10` `Closed`. Their existence is the proximate trigger for this ADR — they exposed the absence of an end-to-end auth contract. +Two security defects in `AcLoginServiceServer.GenerateAccessToken` (JWT signing key + issued access token written to logger) were addressed pre-flight as `ACCORE-LOG-I-P5W3` and `ACCORE-LOG-I-K1Z7` `Closed`. Their existence is the proximate trigger for this ADR — they exposed the absence of an end-to-end auth contract. Consumer apps (MAUI + WASM) cannot adopt the framework safely until this ADR's decisions are implemented. @@ -52,7 +52,7 @@ Adopt a layered bearer-token authentication architecture across all client and s **Positive:** - Consumers get bearer-auth via three DI calls (one for JWT bundle, one for HTTP-handler registration, one for hub-builder extension) — minimum-boilerplate target met. - Per-tag authorization scales with the existing tag registry — no parallel registry to maintain. -- Two confirmed-critical security leaks (`LOG-I-9`, `LOG-I-10`) are closed; future similar mistakes prevented by the framework guideline doc (`docs/AUTH/README.md`'s "Never log secrets" section). +- Two confirmed-critical security leaks (`ACCORE-LOG-I-P5W3`, `ACCORE-LOG-I-K1Z7`) are closed; future similar mistakes prevented by the framework guideline doc (`docs/AUTH/README.md`'s "Never log secrets" section). - WASM and MAUI use one shared token-store abstraction; consumer code is platform-aware only at registration time. - Framework-first preserved: all architectural pieces live in AyCode.Services / AyCode.Services.Server / AyCode.Interfaces; consumers supply only platform-storage and config values. @@ -64,8 +64,8 @@ Adopt a layered bearer-token authentication architecture across all client and s **Follow-ups required:** *Pre-flight (already landed in this commit series):* -- ✅ `LOG-I-9` closed: JWT signing key log-write DEBUG-gated. -- ✅ `LOG-I-10` closed: access token log-write DEBUG-gated; `AccesToken` typo fixed at the same line. +- ✅ `ACCORE-LOG-I-P5W3` closed: JWT signing key log-write DEBUG-gated. +- ✅ `ACCORE-LOG-I-K1Z7` closed: access token log-write DEBUG-gated; `AccesToken` typo fixed at the same line. *Infrastructure (one-time, before implementation):* - Create `docs/AUTH/` topic folder with `README.md` (consumer recipe: class names, method signatures, wire formats, diagrams, code examples), `AUTH_ISSUES.md`, `AUTH_TODO.md`. @@ -86,7 +86,7 @@ Adopt a layered bearer-token authentication architecture across all client and s - Per-consumer hub: tag allowlist for login + ping (at minimum). *Status migration on AUTH topic creation:* -- Move `LOG-I-9` and `LOG-I-10` to `AUTH_ISSUES.md` per their existing "Discovery context" notes; in `LOGGING_ISSUES.md` replace bodies with cross-ref `Superseded by AUTH-I-N`. +- Move `ACCORE-LOG-I-P5W3` and `ACCORE-LOG-I-K1Z7` to `AUTH_ISSUES.md` per their existing "Discovery context" notes; in `LOGGING_ISSUES.md` replace bodies with cross-ref `Superseded by AUTH-I-N`. *Future ADRs:* - `0002` — Refresh-token flow + sliding-vs-fixed lifetime decision. @@ -104,7 +104,7 @@ Adopt a layered bearer-token authentication architecture across all client and s ## Related -- Pre-flight fix entries: [`LOGGING_ISSUES.md#log-i-9`](../../AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md), [`LOGGING_ISSUES.md#log-i-10`](../../AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md) (both `Closed (2026-04-25)`). -- Tentative TODO surfaced post-fix: `LOG-T-12` ("Never log secrets" guideline section in `LOGGING/README.md`). +- Pre-flight fix entries: [`LOGGING_ISSUES.md#accore-log-i-p5w3`](../../AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md), [`LOGGING_ISSUES.md#accore-log-i-k1z7`](../../AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md) (both `Closed (2026-04-25)`). +- Tentative TODO surfaced post-fix: a "Never log secrets" framework-guideline section in `LOGGING/README.md` — forthcoming entry in `LOGGING_TODO.md` (no ID assigned yet). - External: RFC 6750 (Bearer Token Usage), RFC 7519 (JWT), Microsoft.AspNetCore.SignalR auth docs (query-string token pattern). - Future: ADR `0002` (refresh-flow design).