diff --git a/.ai/ROOT.md b/.ai/ROOT.md
index 9c4c29b..c01585a 100644
--- a/.ai/ROOT.md
+++ b/.ai/ROOT.md
@@ -1,7 +1,7 @@
# [DEF:Project_Knowledge_Map:Root]
# @TIER: CRITICAL
# @PURPOSE: Global navigation map for AI-Agent (GRACE Knowledge Graph).
-# @LAST_UPDATE: 2026-02-19
+# @LAST_UPDATE: 2026-02-20
## 1. SYSTEM STANDARDS (Rules of the Game)
Strict policies and formatting rules.
@@ -26,6 +26,8 @@ Use these for code generation (Style Transfer).
* Ref: `.ai/shots/frontend_component.svelte` -> `[DEF:Shot:Svelte_Component]`
* **Plugin Module:** Reference implementation of a task plugin.
* Ref: `.ai/shots/plugin_example.py` -> `[DEF:Shot:Plugin_Example]`
+* **Critical Module:** Core banking transaction processor with ACID guarantees.
+ * Ref: `.ai/shots/critical_module.py` -> `[DEF:Shot:Critical_Module]`
## 3. DOMAIN MAP (Modules)
* **Project Map:** `.ai/PROJECT_MAP.md` -> `[DEF:Project_Map]`
diff --git a/.ai/shots/backend_route.py b/.ai/shots/backend_route.py
index 76d829d..b5239e7 100644
--- a/.ai/shots/backend_route.py
+++ b/.ai/shots/backend_route.py
@@ -1,14 +1,18 @@
-# [DEF:Shot:FastAPI_Route:Example]
+# [DEF:BackendRouteShot:Module]
+# @TIER: STANDARD
+# @SEMANTICS: Route, Task, API, Async
# @PURPOSE: Reference implementation of a task-based route using GRACE-Poly.
+# @LAYER: Interface (API)
# @RELATION: IMPLEMENTS -> [DEF:Std:API_FastAPI]
+# @INVARIANT: TaskManager must be available in dependency graph.
-from typing import List, Dict, Any, Optional
+from typing import Dict, Any
from fastapi import APIRouter, Depends, HTTPException, status
from pydantic import BaseModel
from ...core.logger import belief_scope
from ...core.task_manager import TaskManager, Task
from ...core.config_manager import ConfigManager
-from ...dependencies import get_task_manager, get_config_manager, has_permission, get_current_user
+from ...dependencies import get_task_manager, get_config_manager, get_current_user
router = APIRouter()
@@ -21,37 +25,41 @@ class CreateTaskRequest(BaseModel):
# @PURPOSE: Create and start a new task using TaskManager. Non-blocking.
# @PARAM: request (CreateTaskRequest) - Plugin and params.
# @PARAM: task_manager (TaskManager) - Async task executor.
-# @PARAM: config (ConfigManager) - Centralized configuration.
-# @PRE: plugin_id must exist; config must be initialized.
+# @PRE: plugin_id must match a registered plugin.
# @POST: A new task is spawned; Task ID returned immediately.
+# @SIDE_EFFECT: Writes to DB, Trigger background worker.
async def create_task(
request: CreateTaskRequest,
task_manager: TaskManager = Depends(get_task_manager),
config: ConfigManager = Depends(get_config_manager),
current_user = Depends(get_current_user)
):
- # RBAC: Dynamic permission check
- has_permission(f"plugin:{request.plugin_id}", "EXECUTE")(current_user)
-
+ # Context Logging
with belief_scope("create_task"):
try:
- # 1. Action: Resolve setting using ConfigManager (Example)
+ # 1. Action: Configuration Resolution
timeout = config.get("TASKS_DEFAULT_TIMEOUT", 3600)
- # 2. Action: Spawn async task via TaskManager
+ # 2. Action: Spawn async task
# @RELATION: CALLS -> task_manager.create_task
task = await task_manager.create_task(
plugin_id=request.plugin_id,
params={**request.params, "timeout": timeout}
)
return task
+
+ except ValueError as e:
+ # 3. Recovery: Domain logic error mapping
+ raise HTTPException(
+ status_code=status.HTTP_400_BAD_REQUEST,
+ detail=str(e)
+ )
except Exception as e:
- # Evaluation: Proper error mapping and logging
- # @UX_STATE: Error feedback to frontend
+ # @UX_STATE: Error feedback -> 500 Internal Error
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
- detail=f"Task creation failed: {str(e)}"
+ detail="Internal Task Spawning Error"
)
# [/DEF:create_task:Function]
-# [/DEF:Shot:FastAPI_Route]
+# [/DEF:BackendRouteShot:Module]
\ No newline at end of file
diff --git a/.ai/shots/critical_module.py b/.ai/shots/critical_module.py
new file mode 100644
index 0000000..309f03e
--- /dev/null
+++ b/.ai/shots/critical_module.py
@@ -0,0 +1,79 @@
+# [DEF:TransactionCore:Module]
+# @TIER: CRITICAL
+# @SEMANTICS: Finance, ACID, Transfer, Ledger
+# @PURPOSE: Core banking transaction processor with ACID guarantees.
+# @LAYER: Domain (Core)
+# @RELATION: DEPENDS_ON -> [DEF:Infra:PostgresDB]
+# @RELATION: DEPENDS_ON -> [DEF:Infra:AuditLog]
+# @INVARIANT: Total system balance must remain constant (Double-Entry Bookkeeping).
+# @INVARIANT: Negative transfers are strictly forbidden.
+
+# @TEST_DATA: sufficient_funds -> {"from": "acc_A", "to": "acc_B", "amt": 100.00}
+# @TEST_DATA: insufficient_funds -> {"from": "acc_empty", "to": "acc_B", "amt": 1000.00}
+# @TEST_DATA: concurrency_lock -> {./fixtures/transactions.json#race_condition}
+
+from decimal import Decimal
+from typing import NamedTuple
+from ...core.logger import belief_scope
+from ...core.db import atomic_transaction, get_balance, update_balance
+from ...core.exceptions import BusinessRuleViolation
+
+class TransferResult(NamedTuple):
+ tx_id: str
+ status: str
+ new_balance: Decimal
+
+# [DEF:execute_transfer:Function]
+# @PURPOSE: Atomically move funds between accounts with audit trails.
+# @PARAM: sender_id (str) - Source account.
+# @PARAM: receiver_id (str) - Destination account.
+# @PARAM: amount (Decimal) - Positive amount to transfer.
+# @PRE: amount > 0; sender != receiver; sender_balance >= amount.
+# @POST: sender_balance -= amount; receiver_balance += amount; Audit Record Created.
+# @SIDE_EFFECT: Database mutation (Rows locked), Audit IO.
+#
+# @UX_STATE: Success -> Returns 200 OK + Transaction Receipt.
+# @UX_STATE: Error(LowBalance) -> 422 Unprocessable -> UI shows "Top-up needed" modal.
+# @UX_STATE: Error(System) -> 500 Internal -> UI shows "Retry later" toast.
+def execute_transfer(sender_id: str, receiver_id: str, amount: Decimal) -> TransferResult:
+ # Guard: Input Validation
+ if amount <= Decimal("0.00"):
+ raise BusinessRuleViolation("Transfer amount must be positive.")
+ if sender_id == receiver_id:
+ raise BusinessRuleViolation("Cannot transfer to self.")
+
+ with belief_scope("execute_transfer") as context:
+ context.logger.info("Initiating transfer", data={"from": sender_id, "to": receiver_id})
+
+ try:
+ # 1. Action: Atomic DB Transaction
+ # @RELATION: CALLS -> atomic_transaction
+ with atomic_transaction():
+ # Guard: State Validation (Strict)
+ current_balance = get_balance(sender_id, for_update=True)
+
+ if current_balance < amount:
+ # @UX_FEEDBACK: Triggers specific UI flow for insufficient funds
+ context.logger.warn("Insufficient funds", data={"balance": current_balance})
+ raise BusinessRuleViolation("INSUFFICIENT_FUNDS")
+
+ # 2. Action: Mutation
+ new_src_bal = update_balance(sender_id, -amount)
+ new_dst_bal = update_balance(receiver_id, +amount)
+
+ # 3. Action: Audit
+ tx_id = context.audit.log_transfer(sender_id, receiver_id, amount)
+
+ context.logger.info("Transfer committed", data={"tx_id": tx_id})
+ return TransferResult(tx_id, "COMPLETED", new_src_bal)
+
+ except BusinessRuleViolation as e:
+ # Logic: Explicit re-raise for UI mapping
+ raise e
+ except Exception as e:
+ # Logic: Catch-all safety net
+ context.logger.error("Critical Transfer Failure", error=e)
+ raise RuntimeError("TRANSACTION_ABORTED") from e
+# [/DEF:execute_transfer:Function]
+
+# [/DEF:TransactionCore:Module]
\ No newline at end of file
diff --git a/.ai/shots/frontend_component.svelte b/.ai/shots/frontend_component.svelte
index 05bd165..5309939 100644
--- a/.ai/shots/frontend_component.svelte
+++ b/.ai/shots/frontend_component.svelte
@@ -1,19 +1,23 @@
-
-# @PURPOSE: Reference implementation of a task-spawning component using Constitution rules.
-# @RELATION: IMPLEMENTS -> [DEF:Std:UI_Svelte]
-
+
-
-
-
-
+
\ No newline at end of file
diff --git a/.ai/shots/plugin_example.py b/.ai/shots/plugin_example.py
index 8c10d8e..28d169a 100644
--- a/.ai/shots/plugin_example.py
+++ b/.ai/shots/plugin_example.py
@@ -1,6 +1,10 @@
-# [DEF:Shot:Plugin_Example:Example]
+# [DEF:PluginExampleShot:Module]
+# @TIER: STANDARD
+# @SEMANTICS: Plugin, Core, Extension
# @PURPOSE: Reference implementation of a plugin following GRACE standards.
-# @RELATION: IMPLEMENTS -> [DEF:Std:Plugin]
+# @LAYER: Domain (Business Logic)
+# @RELATION: INHERITS -> PluginBase
+# @INVARIANT: get_schema must return valid JSON Schema.
from typing import Dict, Any, Optional
from ..core.plugin_base import PluginBase
@@ -11,28 +15,15 @@ class ExamplePlugin(PluginBase):
def id(self) -> str:
return "example-plugin"
- @property
- def name(self) -> str:
- return "Example Plugin"
-
- @property
- def description(self) -> str:
- return "A simple plugin that demonstrates structured logging and progress tracking."
-
- @property
- def version(self) -> str:
- return "1.0.0"
-
# [DEF:get_schema:Function]
# @PURPOSE: Defines input validation schema.
+ # @POST: Returns dict compliant with JSON Schema draft 7.
def get_schema(self) -> Dict[str, Any]:
return {
"type": "object",
"properties": {
"message": {
"type": "string",
- "title": "Message",
- "description": "A message to log.",
"default": "Hello, GRACE!",
}
},
@@ -41,27 +32,33 @@ class ExamplePlugin(PluginBase):
# [/DEF:get_schema:Function]
# [DEF:execute:Function]
- # @PURPOSE: Core plugin logic with structured logging and progress reporting.
+ # @PURPOSE: Core plugin logic with structured logging and scope isolation.
# @PARAM: params (Dict) - Validated input parameters.
- # @PARAM: context (TaskContext) - Execution context with logging and progress tools.
- async def execute(self, params: Dict[str, Any], context: Optional[TaskContext] = None):
- message = params["message"]
+ # @PARAM: context (TaskContext) - Execution tools (log, progress).
+ # @SIDE_EFFECT: Emits logs to centralized system.
+ async def execute(self, params: Dict, context: Optional = None):
+ message = params
- # 1. Action: Structured Logging with Source Attribution
- if context:
- log = context.logger.with_source("example_plugin")
- log.info(f"Starting execution with message: {message}")
-
- # 2. Action: Progress Reporting
- log.progress("Processing step 1...", percent=25)
- # Simulating some async work...
- # await some_async_op()
-
- log.progress("Processing step 2...", percent=75)
- log.info("Execution completed successfully.")
- else:
- # Fallback for manual/standalone execution
- print(f"Standalone execution: {message}")
+ # 1. Action: System-level tracing (Rule VI)
+ with belief_scope("example_plugin_exec") as b_scope:
+ if context:
+ # Task Logs: ΠΠΈΡΠ΅ΠΌ Π² ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΈΠΉ ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ Π·Π°Π΄Π°ΡΠΈ
+ # @RELATION: BINDS_TO -> context.logger
+ log = context.logger.with_source("example_plugin")
+
+ b_scope.logger.info("Using provided TaskContext") # System log
+ log.info("Starting execution", data={"msg": message}) # Task log
+
+ # 2. Action: Progress Reporting
+ log.progress("Processing...", percent=50)
+
+ # 3. Action: Finalize
+ log.info("Execution completed.")
+ else:
+ # Standalone Fallback: ΠΠ°ΠΌΡΠΊΠ°Π΅ΠΌΡΡ Π½Π° ΡΠΈΡΡΠ΅ΠΌΠ½ΡΠΉ scope
+ b_scope.logger.warning("No TaskContext provided. Running standalone.")
+ b_scope.logger.info("Standalone execution", data={"msg": message})
+ print(f"Standalone: {message}")
# [/DEF:execute:Function]
-# [/DEF:Shot:Plugin_Example]
+# [/DEF:PluginExampleShot:Module]
\ No newline at end of file