Coverage for node / src / stigmem_node / routes / instruction.py: 79%

350 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-05-25 01:49 +0000

1"""Lazy instruction discovery — spec §21 (Phase 10). 

2 

3Routes: 

4 GET /v1/agents/{agent_id}/boot-stub §21.8.1 MUST 

5 GET /v1/agents/{agent_id}/instruction-manifest §21.8.2 MUST 

6 PUT /v1/agents/{agent_id}/instruction-manifest §21.8.3 MUST 

7 POST /v1/agents/{agent_id}/recall-instruction §21.8.4 MUST 

8 POST /v1/instruction/audit §21.8.5 SHOULD 

9 GET /v1/agents/{agent_id}/instruction-manifest/coverage §21.8.6 SHOULD 

10""" 

11 

12from __future__ import annotations 

13 

14import json 

15import logging 

16import re 

17import secrets 

18import time 

19import uuid 

20from datetime import UTC, datetime 

21from typing import Annotated, Any 

22 

23import yaml 

24from fastapi import APIRouter, Depends, HTTPException, Response, status 

25from fastapi.responses import PlainTextResponse 

26 

27from ..auth import Identity, resolve_identity 

28from ..db import db 

29from ..models.instruction import ( 

30 AuditSubmitRequest, 

31 ManifestEntry, 

32 PublishManifestRequest, 

33 RecallInstructionRequest, 

34) 

35 

36logger = logging.getLogger("stigmem.instruction") 

37 

38router = APIRouter(tags=["instruction"]) 

39 

40# --------------------------------------------------------------------------- 

41# Constants 

42# --------------------------------------------------------------------------- 

43 

44_MANIFEST_TOKEN_LIMIT = 1000 

45_BOOT_STUB_TOKEN_LIMIT = 500 

46_GUARANTEE_LOAD_CAP = 5 

47_AUDIT_TOKEN_PREFIX = "audi_" # nosec B105 — audit token prefix, not a password 

48_AUDEVENT_PREFIX = "audevent_" 

49_AUDIT_TOKEN_TTL_S = 86_400 # 24 hours 

50 

51# Registered wake-reason enum values used for task_type validation. 

52# Extend this set when new wake reasons are added to the platform. 

53_KNOWN_WAKE_REASONS: frozenset[str] = frozenset( 

54 { 

55 "issue_assigned", 

56 "issue_commented", 

57 "issue_blockers_resolved", 

58 "issue_children_completed", 

59 "issue_comment_mentioned", 

60 "routine_fired", 

61 "approval_resolved", 

62 "manual", 

63 } 

64) 

65 

66_ADAPTER_PROFILES = {"paperclip-claude-code", "openai-assistants", "generic"} 

67 

68 

69# --------------------------------------------------------------------------- 

70# Helpers 

71# --------------------------------------------------------------------------- 

72 

73 

74def _approx_tokens(text: str) -> int: 

75 """Approximate cl100k token count (4 chars ≈ 1 token).""" 

76 try: 

77 import tiktoken 

78 

79 enc = tiktoken.get_encoding("cl100k_base") 

80 return len(enc.encode(text)) 

81 except Exception: 

82 return max(1, len(text) // 4) 

83 

84 

85def _now_ms() -> int: 

86 return int(time.time() * 1000) 

87 

88 

89def _is_admin(identity: Identity) -> bool: 

90 return identity.is_admin() 

91 

92 

93def _check_agent_access(identity: Identity, agent_id: str) -> None: 

94 """Raise 403 unless caller is the named agent or an admin.""" 

95 if _is_admin(identity): 95 ↛ 98line 95 didn't jump to line 98 because the condition on line 95 was always true

96 return 

97 # Agent key entity_uri must contain the agent_id (UUID or role slug) 

98 if agent_id in identity.entity_uri: 

99 return 

100 raise HTTPException( 

101 status_code=status.HTTP_403_FORBIDDEN, 

102 detail="instruction_scope_denied", 

103 ) 

104 

105 

106def _get_current_manifest(conn: Any, agent_id: str) -> dict[str, Any] | None: 

107 row = conn.execute( 

108 "SELECT * FROM instruction_manifests WHERE agent_id = ? AND superseded_at IS NULL" 

109 " ORDER BY created_at DESC LIMIT 1", 

110 (agent_id,), 

111 ).fetchone() 

112 if row is None: 

113 return None 

114 return dict(row) 

115 

116 

117def _build_boot_stub( 

118 agent_id: str, 

119 agent_role: str, 

120 manifest_uri: str, 

121 manifest_version: str, 

122 adapter_profile: str, 

123 deployment: str = "default", 

124) -> str: 

125 frontmatter = { 

126 "agent_id": agent_id, 

127 "agent_role": agent_role, 

128 "heartbeat_contract": f"instruction:{deployment}/shared/heartbeat-contract/v1", 

129 "manifest_uri": manifest_uri, 

130 "stub_version": 1, 

131 "generated_at": datetime.now(UTC).isoformat(), 

132 "adapter_profile": adapter_profile, 

133 "migration_mode": "stigmem", 

134 } 

135 recall_schema = { 

136 "name": "recall_instruction", 

137 "description": "Retrieve relevant instruction units from the agent manifest.", 

138 "parameters": { 

139 "type": "object", 

140 "properties": { 

141 "intent": {"type": "string", "description": "What you are about to do"}, 

142 "max_chunks": {"type": "integer", "default": 3}, 

143 "token_budget": {"type": "integer", "default": _BOOT_STUB_TOKEN_LIMIT}, 

144 "manifest_hint": { 

145 "type": "array", 

146 "items": {"type": "string"}, 

147 "description": "Explicit unit names to prioritize", 

148 }, 

149 }, 

150 "required": ["intent"], 

151 }, 

152 } 

153 yaml_str = yaml.dump( 

154 {**frontmatter, "recall_tool_schema": recall_schema}, 

155 default_flow_style=False, 

156 allow_unicode=True, 

157 sort_keys=False, 

158 ) 

159 body = ( 

160 f"# Agent Boot Stub\n\n" 

161 f"You are **{agent_role}** (id: `{agent_id}`).\n\n" 

162 f"Your heartbeat procedure is at `{frontmatter['heartbeat_contract']}`.\n" 

163 f"Your instruction manifest is at `{manifest_uri}`.\n\n" 

164 f"Call `recall_instruction(intent)` to load relevant instruction sections before\n" 

165 f"performing any non-trivial task. The manifest lists available sections and their\n" 

166 f"triggers to help you decide when to load.\n" 

167 ) 

168 return f"---\n{yaml_str}---\n\n{body}" 

169 

170 

171def _validate_manifest_entries(entries: list[ManifestEntry]) -> None: 

172 seen_names: set[str] = set() 

173 guarantee_count = 0 

174 

175 for entry in entries: 

176 # Exactly one of fact_uri / path must be present 

177 has_fact = bool(entry.fact_uri) 

178 has_path = bool(entry.path) 

179 if not has_fact and not has_path: 

180 raise HTTPException( 

181 400, 

182 detail=(f"manifest_entry_invalid: '{entry.name}' has neither fact_uri nor path"), 

183 ) 

184 if has_fact and has_path: 

185 raise HTTPException( 

186 400, 

187 detail=(f"manifest_entry_invalid: '{entry.name}' has both fact_uri and path"), 

188 ) 

189 

190 # Unique names 

191 if entry.name in seen_names: 191 ↛ 192line 191 didn't jump to line 192 because the condition on line 191 was never true

192 raise HTTPException( 

193 400, 

194 detail=f"manifest_entry_invalid: duplicate name '{entry.name}'", 

195 ) 

196 seen_names.add(entry.name) 

197 

198 # Validate required_by_task_types 

199 for tt in entry.required_by_task_types: 

200 if tt not in _KNOWN_WAKE_REASONS: 

201 raise HTTPException( 

202 400, 

203 detail=f"task_type_unknown: '{tt}' is not a registered wake-reason", 

204 ) 

205 if len(entry.required_by_task_types) > 2: 

206 raise HTTPException( 

207 400, 

208 detail=( 

209 "task_types_approval_required: entry declares > 2 " 

210 "required_by_task_types; admin approval required" 

211 ), 

212 ) 

213 

214 if entry.guarantee_load: 

215 guarantee_count += 1 

216 

217 if guarantee_count > _GUARANTEE_LOAD_CAP: 

218 raise HTTPException( 

219 400, 

220 detail=( 

221 f"guarantee_cap_exceeded: at most {_GUARANTEE_LOAD_CAP} entries " 

222 "may have guarantee_load=true per agent" 

223 ), 

224 ) 

225 

226 

227def _score_intent_against_entry(intent: str, entry: ManifestEntry) -> float: 

228 """Simple BM25-style keyword overlap score for ranking manifest entries.""" 

229 intent_words = set(re.findall(r"\w+", intent.lower())) 

230 if not intent_words: 230 ↛ 231line 230 didn't jump to line 231 because the condition on line 230 was never true

231 return 0.0 

232 score = 0.0 

233 # Check description overlap 

234 desc_words = set(re.findall(r"\w+", entry.description.lower())) 

235 score += len(intent_words & desc_words) / max(len(intent_words), 1) * 0.4 

236 # Check trigger intents 

237 for trigger_intent in entry.load_triggers.intents: 

238 trigger_words = set(re.findall(r"\w+", trigger_intent.lower())) 

239 score += len(intent_words & trigger_words) / max(len(intent_words), 1) * 0.3 

240 # Check keywords 

241 for kw in entry.load_triggers.keywords: 

242 if kw.lower() in intent.lower(): 

243 score += 0.2 

244 return min(score, 1.0) 

245 

246 

247def _fetch_instruction_content(entry: ManifestEntry) -> tuple[str, str]: 

248 """Return (content, source) for a manifest entry. Raises on failure.""" 

249 if entry.fact_uri: 249 ↛ 258line 249 didn't jump to line 258 because the condition on line 249 was always true

250 with db() as conn: 

251 row = conn.execute( 

252 "SELECT value_v, valid_until FROM facts" 

253 " WHERE entity = ? ORDER BY timestamp DESC LIMIT 1", 

254 (entry.fact_uri,), 

255 ).fetchone() 

256 if row: 256 ↛ 258line 256 didn't jump to line 258

257 return str(row["value_v"]), "stigmem" 

258 if entry.path: 

259 try: 

260 with open(entry.path) as f: 

261 return f.read(), "fallback_path" 

262 except OSError as exc: 

263 raise LookupError( 

264 f"instruction fallback path '{entry.path}' could not be read" 

265 ) from exc 

266 raise LookupError(f"instruction content not found for entry '{entry.name}'") 

267 

268 

269def _get_fact_valid_until(fact_uri: str) -> str | None: 

270 with db() as conn: 

271 row = conn.execute( 

272 "SELECT valid_until FROM facts WHERE entity = ? ORDER BY timestamp DESC LIMIT 1", 

273 (fact_uri,), 

274 ).fetchone() 

275 if row: 275 ↛ 278line 275 didn't jump to line 278 because the condition on line 275 was always true

276 valid_until: str | None = row["valid_until"] 

277 return valid_until 

278 return None 

279 

280 

281# --------------------------------------------------------------------------- 

282# 21.8.1 Get Boot Stub 

283# --------------------------------------------------------------------------- 

284 

285 

286@router.get("/v1/agents/{agent_id}/boot-stub", response_class=PlainTextResponse) 

287def get_boot_stub( 

288 agent_id: str, 

289 identity: Annotated[Identity, Depends(resolve_identity)], 

290 profile: str = "generic", 

291) -> PlainTextResponse: 

292 _check_agent_access(identity, agent_id) 

293 

294 if profile not in _ADAPTER_PROFILES: 

295 profile = "generic" 

296 

297 with db() as conn: 

298 stub_row = conn.execute( 

299 "SELECT body, token_count, manifest_version FROM boot_stubs" 

300 " WHERE agent_id = ? AND adapter_profile = ?", 

301 (agent_id, profile), 

302 ).fetchone() 

303 

304 if stub_row is None: 304 ↛ 342line 304 didn't jump to line 342 because the condition on line 304 was always true

305 manifest_row = _get_current_manifest(conn, agent_id) 

306 if manifest_row is None: 306 ↛ 307line 306 didn't jump to line 307 because the condition on line 306 was never true

307 raise HTTPException( 

308 status_code=status.HTTP_404_NOT_FOUND, 

309 detail="boot_stub_not_found", 

310 ) 

311 # Generate on the fly from manifest 

312 agent_role = _derive_agent_role(agent_id, conn) 

313 manifest_uri = manifest_row["fact_uri"] 

314 stub_body = _build_boot_stub( 

315 agent_id=agent_id, 

316 agent_role=agent_role, 

317 manifest_uri=manifest_uri, 

318 manifest_version=manifest_row["version"], 

319 adapter_profile=profile, 

320 ) 

321 token_count = _approx_tokens(stub_body) 

322 if token_count > _BOOT_STUB_TOKEN_LIMIT: 322 ↛ 323line 322 didn't jump to line 323 because the condition on line 322 was never true

323 raise HTTPException( 

324 status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, 

325 detail=( 

326 f"boot_stub_too_large: {token_count} tokens exceeds " 

327 f"{_BOOT_STUB_TOKEN_LIMIT}" 

328 ), 

329 ) 

330 now_ms = _now_ms() 

331 conn.execute( 

332 """INSERT OR REPLACE INTO boot_stubs 

333 (agent_id, adapter_profile, stub_version, body, token_count, 

334 generated_at, manifest_version) 

335 VALUES (?,?,?,?,?,?,?)""", 

336 (agent_id, profile, 1, stub_body, token_count, now_ms, manifest_row["version"]), 

337 ) 

338 stub_body_out = stub_body 

339 token_count_out = token_count 

340 manifest_version_out = manifest_row["version"] 

341 else: 

342 stub_body_out = stub_row["body"] 

343 token_count_out = stub_row["token_count"] 

344 manifest_version_out = stub_row["manifest_version"] 

345 

346 return PlainTextResponse( 

347 content=stub_body_out, 

348 media_type="text/markdown", 

349 headers={ 

350 "X-Stub-Version": "1", 

351 "X-Manifest-Version": manifest_version_out, 

352 "X-Token-Count": str(token_count_out), 

353 }, 

354 ) 

355 

356 

357def _derive_agent_role(agent_id: str, conn: Any) -> str: 

358 """Best-effort: look up a human-readable role for agent_id.""" 

359 row = conn.execute( 

360 "SELECT entity_uri FROM api_keys WHERE entity_uri LIKE ? LIMIT 1", 

361 (f"%{agent_id}%",), 

362 ).fetchone() 

363 if row: 363 ↛ 364line 363 didn't jump to line 364 because the condition on line 363 was never true

364 uri: str = row["entity_uri"] 

365 # e.g. "agent:cto" or "stigmem://org/agent/cto" 

366 parts = uri.replace("//", "/").rstrip("/").split("/") 

367 if parts: 

368 return parts[-1].upper() 

369 return "Agent" 

370 

371 

372# --------------------------------------------------------------------------- 

373# 21.8.2 Get Instruction Manifest 

374# --------------------------------------------------------------------------- 

375 

376 

377@router.get("/v1/agents/{agent_id}/instruction-manifest") 

378def get_instruction_manifest( 

379 agent_id: str, 

380 identity: Annotated[Identity, Depends(resolve_identity)], 

381) -> dict[str, Any]: 

382 _check_agent_access(identity, agent_id) 

383 

384 with db() as conn: 

385 row = _get_current_manifest(conn, agent_id) 

386 

387 if row is None: 387 ↛ 388line 387 didn't jump to line 388 because the condition on line 387 was never true

388 raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="manifest_not_found") 

389 

390 entries = json.loads(row["body"]) 

391 created_ms: int = row["created_at"] 

392 last_updated = datetime.fromtimestamp(created_ms / 1000, tz=UTC).isoformat() 

393 

394 return { 

395 "manifest_version": row["version"], 

396 "fact_uri": row["fact_uri"], 

397 "token_count": row["token_count"], 

398 "entries": entries, 

399 "last_updated_at": last_updated, 

400 } 

401 

402 

403# --------------------------------------------------------------------------- 

404# 21.8.3 Publish / Replace Instruction Manifest 

405# --------------------------------------------------------------------------- 

406 

407 

408@router.put("/v1/agents/{agent_id}/instruction-manifest", status_code=200) 

409def publish_instruction_manifest( 

410 agent_id: str, 

411 req: PublishManifestRequest, 

412 identity: Annotated[Identity, Depends(resolve_identity)], 

413) -> dict[str, Any]: 

414 if not _is_admin(identity): 

415 raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="admin key required") 

416 

417 _validate_manifest_entries(req.entries) 

418 

419 # Serialize entries for storage 

420 entries_json = json.dumps([e.model_dump() for e in req.entries]) 

421 token_count = _approx_tokens(entries_json) 

422 if token_count > _MANIFEST_TOKEN_LIMIT: 422 ↛ 423line 422 didn't jump to line 423 because the condition on line 422 was never true

423 raise HTTPException( 

424 400, 

425 detail=(f"manifest_too_large: {token_count} tokens exceeds {_MANIFEST_TOKEN_LIMIT}"), 

426 ) 

427 

428 # Build the instruction: URI for this manifest 

429 fact_uri = f"instruction:default/agent/{agent_id}/manifest/{req.version}" 

430 

431 with db() as conn: 

432 # Check version uniqueness 

433 existing = conn.execute( 

434 "SELECT id FROM instruction_manifests WHERE agent_id = ? AND version = ?", 

435 (agent_id, req.version), 

436 ).fetchone() 

437 if existing: 

438 raise HTTPException(status_code=409, detail="manifest_version_conflict") 

439 

440 # Run coverage gate (simplified: check entry validity; full paraphrase eval is Phase 11) 

441 coverage_report = [] 

442 for entry in req.entries: 

443 coverage_pct: float 

444 if req.skip_coverage_gate: 

445 coverage_pct = 1.0 

446 passed = True 

447 else: 

448 # Lightweight check: verify fact_uri exists if specified 

449 # (full N=5 paraphrase eval is Phase 11) 

450 if entry.fact_uri: 450 ↛ 459line 450 didn't jump to line 459 because the condition on line 450 was always true

451 row = conn.execute( 

452 "SELECT id FROM facts WHERE entity = ? LIMIT 1", (entry.fact_uri,) 

453 ).fetchone() 

454 # If fact doesn't exist yet (pre-seeding), warn but don't block 

455 coverage_pct = 1.0 if row else 0.5 

456 passed = coverage_pct >= 0.80 

457 else: 

458 # path-only entries pass coverage (read from filesystem, not stigmem) 

459 coverage_pct = 1.0 

460 passed = True 

461 coverage_report.append( 

462 { 

463 "unit": entry.name, 

464 "coverage_pct": coverage_pct, 

465 "passed": passed, 

466 } 

467 ) 

468 

469 failing = [r["unit"] for r in coverage_report if not r["passed"]] 

470 if failing and not req.skip_coverage_gate: 470 ↛ 471line 470 didn't jump to line 471 because the condition on line 470 was never true

471 raise HTTPException( 

472 status_code=400, 

473 detail=f"manifest_coverage_failure: units failed coverage gate: {failing}", 

474 ) 

475 

476 now_ms = _now_ms() 

477 manifest_id = str(uuid.uuid4()) 

478 

479 # Supersede previous current version 

480 conn.execute( 

481 "UPDATE instruction_manifests SET superseded_at = ?" 

482 " WHERE agent_id = ? AND superseded_at IS NULL", 

483 (now_ms, agent_id), 

484 ) 

485 

486 conn.execute( 

487 """INSERT INTO instruction_manifests 

488 (id, agent_id, version, fact_uri, token_count, body, created_at) 

489 VALUES (?,?,?,?,?,?,?)""", 

490 (manifest_id, agent_id, req.version, fact_uri, token_count, entries_json, now_ms), 

491 ) 

492 

493 # Invalidate boot stub cache for all profiles 

494 conn.execute("DELETE FROM boot_stubs WHERE agent_id = ?", (agent_id,)) 

495 

496 # Store the manifest itself as a fact in the instruction: scope 

497 fact_id = str(uuid.uuid4()) 

498 ts = datetime.now(UTC).isoformat() 

499 conn.execute( 

500 """INSERT INTO facts 

501 (id, entity, relation, value_type, value_v, source, confidence, scope, 

502 timestamp, valid_until, garden_id) 

503 VALUES (?,?,?,?,?,?,?,?,?,?,?)""", 

504 ( 

505 fact_id, 

506 fact_uri, 

507 "instruction:manifest", 

508 "text", 

509 entries_json, 

510 identity.entity_uri, 

511 1.0, 

512 "local", 

513 ts, 

514 None, 

515 None, 

516 ), 

517 ) 

518 

519 logger.info( 

520 "Instruction manifest published: agent=%s version=%s units=%d", 

521 agent_id, 

522 req.version, 

523 len(req.entries), 

524 ) 

525 

526 return { 

527 "fact_uri": fact_uri, 

528 "token_count": token_count, 

529 "coverage_report": coverage_report, 

530 } 

531 

532 

533# --------------------------------------------------------------------------- 

534# 21.8.4 Recall Instructions 

535# --------------------------------------------------------------------------- 

536 

537 

538def _resolve_hint_chunks( 

539 entries: list[ManifestEntry], 

540 hints: list[str], 

541 token_budget: int, 

542) -> tuple[list[dict[str, Any]], set[str], list[str], int]: 

543 """Step 1: resolve manifest_hint entries. 

544 

545 Returns (chunks, used_names, missed_hints, tokens_used). 

546 """ 

547 chunks: list[dict[str, Any]] = [] 

548 used_names: set[str] = set() 

549 missed_hints: list[str] = [] 

550 tokens_used = 0 

551 for hint_name in hints: 

552 entry = next((e for e in entries if e.name == hint_name), None) 

553 if entry is None: 

554 missed_hints.append(hint_name) 

555 continue 

556 try: 

557 content, source = _fetch_instruction_content(entry) 

558 except LookupError: 

559 missed_hints.append(hint_name) 

560 continue 

561 tokens = _approx_tokens(content) 

562 if tokens_used + tokens <= token_budget: 562 ↛ 551line 562 didn't jump to line 551 because the condition on line 562 was always true

563 chunks.append(_make_chunk(entry, content, tokens, source, score=1.0)) 

564 used_names.add(entry.name) 

565 tokens_used += tokens 

566 return chunks, used_names, missed_hints, tokens_used 

567 

568 

569def _resolve_ranked_chunks( 

570 entries: list[ManifestEntry], 

571 intent: str, 

572 used_names: set[str], 

573 remaining_slots: int, 

574 token_budget: int, 

575 tokens_used: int, 

576) -> tuple[list[dict[str, Any]], int]: 

577 """Step 2: ranked retrieval for remaining slots. Returns (new_chunks, updated_tokens_used).""" 

578 if remaining_slots <= 0: 578 ↛ 579line 578 didn't jump to line 579 because the condition on line 578 was never true

579 return [], tokens_used 

580 scored: list[tuple[float, ManifestEntry]] = [] 

581 for entry in entries: 

582 if entry.name in used_names or entry.guarantee_load: 

583 continue # guaranteed entries handled in step 3 

584 scored.append((_score_intent_against_entry(intent, entry), entry)) 

585 scored.sort(key=lambda x: -x[0]) 

586 

587 new_chunks: list[dict[str, Any]] = [] 

588 for score, entry in scored[:remaining_slots]: 

589 try: 

590 content, source = _fetch_instruction_content(entry) 

591 except LookupError as exc: 

592 logger.debug("skipping recall candidate %s: %s", entry.name, exc) 

593 continue 

594 tokens = _approx_tokens(content) 

595 if tokens_used + tokens <= token_budget: 595 ↛ 588line 595 didn't jump to line 588 because the condition on line 595 was always true

596 new_chunks.append(_make_chunk(entry, content, tokens, source, score=score)) 

597 used_names.add(entry.name) 

598 tokens_used += tokens 

599 return new_chunks, tokens_used 

600 

601 

602def _append_guaranteed_chunks( 

603 entries: list[ManifestEntry], 

604 used_names: set[str], 

605 chunks: list[dict[str, Any]], 

606 tokens_used: int, 

607 token_budget: int, 

608) -> tuple[int, bool]: 

609 """Step 3: insert/append guaranteed entries. Returns (tokens_used, truncated_flag).""" 

610 truncated = False 

611 guaranteed = [e for e in entries if e.guarantee_load and e.name not in used_names] 

612 

613 for entry in [e for e in guaranteed if e.force_position == "prepend"]: 613 ↛ 614line 613 didn't jump to line 614 because the loop on line 613 never started

614 try: 

615 content, source = _fetch_instruction_content(entry) 

616 except LookupError as exc: 

617 logger.warning("guaranteed prepend instruction %s unavailable: %s", entry.name, exc) 

618 continue 

619 tokens = _approx_tokens(content) 

620 chunks.insert(0, _make_chunk(entry, content, tokens, source, score=1.0)) 

621 used_names.add(entry.name) 

622 tokens_used += tokens 

623 if tokens_used > token_budget: 

624 truncated = True 

625 

626 for entry in [e for e in guaranteed if e.force_position != "prepend"]: 626 ↛ 627line 626 didn't jump to line 627 because the loop on line 626 never started

627 try: 

628 content, source = _fetch_instruction_content(entry) 

629 except LookupError as exc: 

630 logger.warning("guaranteed append instruction %s unavailable: %s", entry.name, exc) 

631 continue 

632 tokens = _approx_tokens(content) 

633 chunks.append(_make_chunk(entry, content, tokens, source, score=1.0)) 

634 used_names.add(entry.name) 

635 tokens_used += tokens 

636 if tokens_used > token_budget: 

637 truncated = True 

638 

639 return tokens_used, truncated 

640 

641 

642def _write_recall_audit( 

643 audit_id: str, 

644 agent_id: str, 

645 identity: Identity, 

646 intent: str, 

647 loaded_chunk_names: list[str], 

648 audit_token: str, 

649 now_ms: int, 

650) -> None: 

651 """Best-effort INSERT into instruction_audit; failures are logged not raised.""" 

652 try: 

653 with db() as conn: 

654 conn.execute( 

655 """INSERT INTO instruction_audit 

656 (id, agent_id, heartbeat_id, session_start, intent, loaded_chunks, 

657 used_chunks, missed_chunks, audit_token, audit_closed, created_at) 

658 VALUES (?,?,?,?,?,?,?,?,?,?,?)""", 

659 ( 

660 audit_id, 

661 agent_id, 

662 identity.entity_uri, 

663 now_ms, 

664 intent, 

665 json.dumps(loaded_chunk_names), 

666 "[]", 

667 "[]", 

668 audit_token, 

669 None, 

670 now_ms, 

671 ), 

672 ) 

673 except Exception as exc: 

674 logger.warning("audit_write_failed: %s", exc) 

675 

676 

677@router.post("/v1/agents/{agent_id}/recall-instruction") 

678def recall_instruction( 

679 agent_id: str, 

680 req: RecallInstructionRequest, 

681 identity: Annotated[Identity, Depends(resolve_identity)], 

682) -> dict[str, Any]: 

683 _check_agent_access(identity, agent_id) 

684 

685 with db() as conn: 

686 manifest_row = _get_current_manifest(conn, agent_id) 

687 if manifest_row is None: 

688 raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="manifest_not_found") 

689 

690 entries: list[ManifestEntry] = [ManifestEntry(**e) for e in json.loads(manifest_row["body"])] 

691 

692 chunks, used_names, missed_hints, tokens_used = _resolve_hint_chunks( 

693 entries, 

694 req.manifest_hint, 

695 req.token_budget, 

696 ) 

697 

698 ranked_chunks, tokens_used = _resolve_ranked_chunks( 

699 entries, 

700 req.intent, 

701 used_names, 

702 req.max_chunks - len(chunks), 

703 req.token_budget, 

704 tokens_used, 

705 ) 

706 chunks.extend(ranked_chunks) 

707 

708 tokens_used, truncated = _append_guaranteed_chunks( 

709 entries, 

710 used_names, 

711 chunks, 

712 tokens_used, 

713 req.token_budget, 

714 ) 

715 

716 audit_token = _AUDIT_TOKEN_PREFIX + secrets.token_urlsafe(16) 

717 now_ms = _now_ms() 

718 _write_recall_audit( 

719 _AUDEVENT_PREFIX + str(uuid.uuid4()), 

720 agent_id, 

721 identity, 

722 req.intent, 

723 [c["name"] for c in chunks], 

724 audit_token, 

725 now_ms, 

726 ) 

727 

728 return { 

729 "chunks": chunks, 

730 "total_tokens": tokens_used, 

731 "truncated": truncated, 

732 "missed_hints": missed_hints, 

733 "audit_token": audit_token, 

734 } 

735 

736 

737def _make_chunk( 

738 entry: ManifestEntry, content: str, tokens: int, source: str, score: float 

739) -> dict[str, Any]: 

740 valid_until = _get_fact_valid_until(entry.fact_uri) if entry.fact_uri else None 

741 # Extract version from fact_uri, e.g. "instruction:.../v2" → "v2" 

742 version = "v1" 

743 if entry.fact_uri: 743 ↛ 747line 743 didn't jump to line 747 because the condition on line 743 was always true

744 parts = entry.fact_uri.rstrip("/").split("/") 

745 if parts: 745 ↛ 747line 745 didn't jump to line 747 because the condition on line 745 was always true

746 version = parts[-1] 

747 return { 

748 "name": entry.name, 

749 "fact_uri": entry.fact_uri, 

750 "content": content, 

751 "tokens": tokens, 

752 "valid_until": valid_until, 

753 "version": version, 

754 "score": round(score, 4), 

755 "source": source, 

756 } 

757 

758 

759# --------------------------------------------------------------------------- 

760# 21.8.5 Submit Discovery Audit 

761# --------------------------------------------------------------------------- 

762 

763 

764@router.post("/v1/instruction/audit", status_code=status.HTTP_204_NO_CONTENT) 

765def submit_discovery_audit( 

766 req: AuditSubmitRequest, 

767 identity: Annotated[Identity, Depends(resolve_identity)], 

768) -> Response: 

769 now_ms = _now_ms() 

770 

771 with db() as conn: 

772 row = conn.execute( 

773 "SELECT id, created_at, audit_closed FROM instruction_audit WHERE audit_token = ?", 

774 (req.audit_token,), 

775 ).fetchone() 

776 

777 if row is None: 

778 raise HTTPException(400, detail="audit_token_invalid") 

779 

780 # Idempotent: already closed 

781 if row["audit_closed"] is not None: 

782 return Response(status_code=status.HTTP_204_NO_CONTENT) 

783 

784 # TTL check 

785 age_s = (now_ms - row["created_at"]) / 1000 

786 if age_s > _AUDIT_TOKEN_TTL_S: 786 ↛ 787line 786 didn't jump to line 787 because the condition on line 786 was never true

787 raise HTTPException(400, detail="audit_token_expired") 

788 

789 conn.execute( 

790 "UPDATE instruction_audit" 

791 " SET used_chunks = ?, missed_chunks = ?, audit_closed = ?" 

792 " WHERE audit_token = ?", 

793 ( 

794 json.dumps(req.used_chunks), 

795 json.dumps(req.missed_chunks), 

796 now_ms, 

797 req.audit_token, 

798 ), 

799 ) 

800 

801 return Response(status_code=status.HTTP_204_NO_CONTENT) 

802 

803 

804# --------------------------------------------------------------------------- 

805# 21.8.6 Get Manifest Coverage Report 

806# --------------------------------------------------------------------------- 

807 

808 

809@router.get("/v1/agents/{agent_id}/instruction-manifest/coverage") 

810def get_manifest_coverage( 

811 agent_id: str, 

812 identity: Annotated[Identity, Depends(resolve_identity)], 

813) -> dict[str, Any]: 

814 # Scope validation (S9) 

815 _check_agent_access(identity, agent_id) 

816 

817 with db() as conn: 

818 manifest_row = _get_current_manifest(conn, agent_id) 

819 if manifest_row is None: 

820 raise HTTPException(status_code=404, detail="manifest_not_found") 

821 

822 entries_raw: list[dict[str, Any]] = json.loads(manifest_row["body"]) 

823 entries = [ManifestEntry(**e) for e in entries_raw] 

824 

825 # Compute per-unit metrics from audit log 

826 cutoff_ms = _now_ms() - 7 * 86_400 * 1000 # 7-day window 

827 audit_rows = conn.execute( 

828 "SELECT loaded_chunks, used_chunks FROM instruction_audit" 

829 " WHERE agent_id = ? AND created_at >= ?", 

830 (agent_id, cutoff_ms), 

831 ).fetchall() 

832 

833 is_admin = _is_admin(identity) 

834 now_iso = datetime.now(UTC).isoformat() 

835 

836 unit_stats: dict[str, dict[str, int]] = {} 

837 for entry in entries: 

838 unit_stats[entry.name] = {"loaded": 0, "used": 0, "total": len(audit_rows)} 

839 

840 for row in audit_rows: 

841 loaded = set(json.loads(row["loaded_chunks"])) 

842 used = set(json.loads(row["used_chunks"])) 

843 for name in unit_stats: 

844 if name in loaded: 844 ↛ 846line 844 didn't jump to line 846 because the condition on line 844 was always true

845 unit_stats[name]["loaded"] += 1 

846 if name in used: 846 ↛ 843line 846 didn't jump to line 843 because the condition on line 846 was always true

847 unit_stats[name]["used"] += 1 

848 

849 units_out = [] 

850 for entry in entries: 

851 stats = unit_stats[entry.name] 

852 total = stats["total"] 

853 hit_at_10 = stats["loaded"] / total if total > 0 else 0.0 

854 coverage_pct = stats["used"] / total if total > 0 else 0.0 

855 unit_info: dict[str, Any] = { 

856 "name": entry.name, 

857 "coverage_pct": round(coverage_pct, 4), 

858 "hit_at_10": round(hit_at_10, 4), 

859 "probe_count": total, 

860 "last_evaluated_at": now_iso, 

861 } 

862 # S11: coverage_status only in admin-key responses 

863 if is_admin: 863 ↛ 871line 863 didn't jump to line 871 because the condition on line 863 was always true

864 if total == 0: 

865 cs = "not_evaluated" 

866 elif hit_at_10 >= 0.4: 866 ↛ 869line 866 didn't jump to line 869 because the condition on line 866 was always true

867 cs = "ok" 

868 else: 

869 cs = "coverage_critical" 

870 unit_info["coverage_status"] = cs 

871 units_out.append(unit_info) 

872 

873 # Best-effort embedding model version 

874 from ..settings import settings as _settings_for_model 

875 

876 emb_model: str = getattr(_settings_for_model, "embed_model_id", "unknown") 

877 

878 return { 

879 "manifest_version": manifest_row["version"], 

880 "embedding_model_version": emb_model, 

881 "evaluated_at": now_iso, 

882 "units": units_out, 

883 }