Compare commits
3 Commits
e096c51037
...
worktree-s
| Author | SHA1 | Date | |
|---|---|---|---|
| e4651a9d06 | |||
| a571ad535b | |||
| afc1548bca |
@@ -463,6 +463,7 @@ The draft's biggest structural error was adding the "נבאר" doctrinal paragra
|
||||
- **Problem:** legal-writer updates `decision_blocks` in the DB, but legal-qa reads from `drafts/decision.md` on disk. In CMPA-62 the writer reported updating block headers in DB but the file did not re-sync, causing QA-2 to fail on exactly the same issue twice.
|
||||
- **Lesson:** Single source of truth is mandatory — either the writer must write to BOTH the DB and the decision.md file in one atomic step, or there must be an automatic `regenerate-draft` hook that runs after every block update so the file always reflects the latest DB state. Two unsynchronized sources will keep producing the same false-fail loop.
|
||||
- **Owner:** Infrastructure task — not a writer/QA prompt fix.
|
||||
- **✅ RESOLVED (GAP-88, 2026-06-06):** `block_writer._update_draft_file` is now an automatic regenerate hook called from `store_block` (every persist) **and** `renumber_all_blocks` — so `drafts/decision.md` always reflects `decision_blocks`. legal-qa already validates against the DB; both sides are now identical.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1088,37 +1088,39 @@ async def save_block_content(case_id: UUID, block_id: str, content: str) -> dict
|
||||
result["generation_type"] = "claude-code"
|
||||
result["model_used"] = "claude-code"
|
||||
|
||||
await store_block(UUID(decision["id"]), result)
|
||||
await store_block(UUID(decision["id"]), result) # store_block syncs the file (#35)
|
||||
await db.mark_blocks_stale(case_id, False)
|
||||
|
||||
# Also write/update the draft file on disk
|
||||
await _update_draft_file(case_id, UUID(decision["id"]))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
async def _update_draft_file(case_id: UUID, decision_id: UUID) -> None:
|
||||
"""Rebuild drafts/decision.md from all blocks in DB."""
|
||||
from pathlib import Path
|
||||
|
||||
case = await db.get_case(case_id)
|
||||
if not case:
|
||||
return
|
||||
|
||||
case_dir = config.find_case_dir(case["case_number"])
|
||||
draft_dir = case_dir / "drafts"
|
||||
draft_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
async def _update_draft_file(decision_id: UUID) -> None:
|
||||
"""Rebuild drafts/decision.md from all blocks in DB — the single
|
||||
regenerate-draft hook (lessons #35 / GAP-88). Called after EVERY
|
||||
decision_blocks mutation (store_block, renumber) so the on-disk file never
|
||||
drifts from the DB. legal-qa validates against the DB; export and the chair
|
||||
read the file — keeping them identical kills the "QA fails twice on the same
|
||||
already-fixed issue" loop (CMPA-62). Resolves case from decision_id so no
|
||||
caller has to thread case_id through."""
|
||||
pool = await db.get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
case_row = await conn.fetchrow(
|
||||
"SELECT c.case_number FROM decisions d JOIN cases c ON c.id = d.case_id "
|
||||
"WHERE d.id = $1",
|
||||
decision_id,
|
||||
)
|
||||
if not case_row:
|
||||
return
|
||||
rows = await conn.fetch(
|
||||
"SELECT content FROM decision_blocks WHERE decision_id = $1 AND content != '' ORDER BY block_index",
|
||||
decision_id,
|
||||
)
|
||||
|
||||
draft_dir = config.find_case_dir(case_row["case_number"]) / "drafts"
|
||||
draft_dir.mkdir(parents=True, exist_ok=True)
|
||||
draft_path = draft_dir / "decision.md"
|
||||
draft_path.write_text("\n\n".join(row["content"] for row in rows if row["content"]), encoding="utf-8")
|
||||
logger.info("Draft file updated: %s (%d blocks)", draft_path, len(rows))
|
||||
logger.info("Draft file synced: %s (%d blocks)", draft_path, len(rows))
|
||||
|
||||
|
||||
# ── Renumbering ───────────────────────────────────────────────────
|
||||
@@ -1172,6 +1174,11 @@ async def renumber_all_blocks(decision_id: UUID) -> dict:
|
||||
)
|
||||
updated += 1
|
||||
|
||||
# #35 — renumber mutates content via raw UPDATE (bypasses store_block), so
|
||||
# sync the draft file here too, otherwise the file keeps stale numbering.
|
||||
if updated:
|
||||
await _update_draft_file(decision_id)
|
||||
|
||||
return {"total_paragraphs": current_num - 1, "blocks_updated": updated}
|
||||
|
||||
|
||||
@@ -1204,6 +1211,9 @@ async def store_block(decision_id: UUID, block_result: dict) -> None:
|
||||
block_result["model_used"],
|
||||
block_result["temperature"],
|
||||
)
|
||||
# #35 — regenerate the on-disk draft on every persist so DB and file stay
|
||||
# identical (legal-qa reads DB; export/chair read the file).
|
||||
await _update_draft_file(decision_id)
|
||||
|
||||
|
||||
async def write_and_store_block(
|
||||
|
||||
@@ -104,7 +104,7 @@ CLAIMS_CHECK_PROMPT = """אתה בודק איכות החלטות משפטיות.
|
||||
"""
|
||||
|
||||
|
||||
async def check_claims_coverage(blocks: list[dict], claims: list[dict]) -> dict:
|
||||
async def check_claims_coverage(blocks: list[dict], claims: list[dict], outcome: str = "") -> dict:
|
||||
"""בדיקה סמנטית (Claude) שכל טענה נענתה בדיון."""
|
||||
yod = next((b for b in blocks if b["block_id"] == "block-yod"), None)
|
||||
if not yod or not yod.get("content"):
|
||||
@@ -114,16 +114,26 @@ async def check_claims_coverage(blocks: list[dict], claims: list[dict]) -> dict:
|
||||
if not claims:
|
||||
return {"name": "claims_coverage", "passed": True, "errors": [], "severity": "critical"}
|
||||
|
||||
# Filter: only APPELLANT claims from original pleadings.
|
||||
# Committee/permit_applicant claims are defensive positions, not claims
|
||||
# that need to be "addressed" in the discussion.
|
||||
# #87/GAP-87 — only the appellant's claims from the APPEAL PLEADING itself
|
||||
# must be addressed. claim_type: 'claim'=כתב ערר (mandatory), 'response'=כתב
|
||||
# תשובה, 'reply'=תגובה/השלמת-טיעון/תכתובת (supplementary correspondence — NOT
|
||||
# a standalone duty to answer, especially on full acceptance). Counting reply/
|
||||
# correspondence claims as "unanswered" produced false QA fails (1033-25).
|
||||
source_claims = [
|
||||
c for c in claims
|
||||
if c.get("source_document", "") != "block-zayin"
|
||||
and c.get("party_role") in ("appellant", "respondent")
|
||||
and c.get("claim_type") == "claim"
|
||||
and c.get("party_role") == "appellant"
|
||||
]
|
||||
if not source_claims:
|
||||
# Fallback: all non-block-zayin claims
|
||||
# Fallback: appellant/respondent pleadings, excluding supplementary replies.
|
||||
source_claims = [
|
||||
c for c in claims
|
||||
if c.get("source_document", "") != "block-zayin"
|
||||
and c.get("claim_type") != "reply"
|
||||
and c.get("party_role") in ("appellant", "respondent")
|
||||
]
|
||||
if not source_claims:
|
||||
source_claims = [c for c in claims if c.get("source_document", "") != "block-zayin"]
|
||||
if not source_claims:
|
||||
source_claims = claims
|
||||
@@ -165,9 +175,14 @@ async def check_claims_coverage(blocks: list[dict], claims: list[dict]) -> dict:
|
||||
total = len(source_claims)
|
||||
covered = len(addressed) + len(partial)
|
||||
|
||||
# On full acceptance the appellant prevailed in full — not every sub-claim
|
||||
# needs individual treatment (the chair noted this for correspondence claims,
|
||||
# 1033-25). Relax the missing-tolerance accordingly.
|
||||
allowed_missing_ratio = 0.4 if outcome == "full_acceptance" else 0.2
|
||||
|
||||
return {
|
||||
"name": "claims_coverage",
|
||||
"passed": len(missing) <= total * 0.2, # Allow up to 20% missing
|
||||
"passed": len(missing) <= total * allowed_missing_ratio,
|
||||
"errors": errors,
|
||||
"severity": "critical",
|
||||
"details": f"{covered}/{total} טענות נענו ({covered/total*100:.0f}%), {len(partial)} חלקית, {len(missing)} חסרות",
|
||||
@@ -361,8 +376,10 @@ async def validate_decision(case_id: UUID) -> dict:
|
||||
# Get claims
|
||||
claims = await db.get_claims(case_id)
|
||||
|
||||
# Determine appeal type
|
||||
# Determine appeal type + outcome (outcome relaxes claims coverage on full acceptance — #87)
|
||||
appeal_type = case.get("appeal_type", "licensing")
|
||||
from legal_mcp.services.lessons import canonical_outcome
|
||||
outcome = canonical_outcome(decision.get("outcome", "") or "")
|
||||
|
||||
# Run all checks
|
||||
# Run sync checks
|
||||
@@ -370,7 +387,7 @@ async def validate_decision(case_id: UUID) -> dict:
|
||||
check_neutral_background(blocks),
|
||||
]
|
||||
# Async check: claims coverage with Claude
|
||||
results.append(await check_claims_coverage(blocks, claims))
|
||||
results.append(await check_claims_coverage(blocks, claims, outcome))
|
||||
# More sync checks
|
||||
results.extend([
|
||||
check_weight_compliance(blocks, appeal_type),
|
||||
|
||||
@@ -27,6 +27,62 @@ _BLOCK_TO_SECTION = {
|
||||
"block-yod-alef": "summary",
|
||||
}
|
||||
|
||||
# chunker section_type → golden-ratio section (for corpus measurement, T10)
|
||||
_CHUNK_SECTION_TO_GOLDEN = {
|
||||
"facts": "background", "intro": "background",
|
||||
"appellant_claims": "claims", "respondent_claims": "claims",
|
||||
"legal_analysis": "discussion",
|
||||
"conclusion": "summary", "ruling": "summary",
|
||||
}
|
||||
|
||||
_CORPUS_RATIOS_CACHE: dict | None = None
|
||||
|
||||
|
||||
async def measure_corpus_ratios() -> dict:
|
||||
"""Measure ACTUAL section %-of-total from Dafna's style_corpus, averaged per
|
||||
outcome — the empirical counterpart to lessons.GOLDEN_RATIOS (T10). Splits each
|
||||
decision via chunker (accurate, not the filtered exemplars). Cached for the
|
||||
process. Returns {outcome: {"n": int, "sections": {sec: pct}}}."""
|
||||
global _CORPUS_RATIOS_CACHE
|
||||
if _CORPUS_RATIOS_CACHE is not None:
|
||||
return _CORPUS_RATIOS_CACHE
|
||||
|
||||
from legal_mcp.services.chunker import _split_into_sections
|
||||
pool = await db.get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
rows = await conn.fetch("SELECT full_text, outcome FROM style_corpus WHERE full_text <> ''")
|
||||
|
||||
# Per-outcome AND an "_all" aggregate. style_corpus.outcome is currently
|
||||
# unpopulated for the imported corpus, so per-outcome may be empty — "_all"
|
||||
# is the meaningful signal today, and per-outcome becomes live once outcomes
|
||||
# are backfilled. No silent loss: callers see which buckets have data via n.
|
||||
by_outcome: dict[str, list[dict]] = {}
|
||||
for r in rows:
|
||||
sect_words: dict[str, int] = {}
|
||||
for stype, stext in _split_into_sections(r["full_text"]):
|
||||
g = _CHUNK_SECTION_TO_GOLDEN.get(stype)
|
||||
if g:
|
||||
sect_words[g] = sect_words.get(g, 0) + len(stext.split())
|
||||
total = sum(sect_words.values())
|
||||
if total < 100: # sections didn't parse — skip
|
||||
continue
|
||||
pct = {s: w / total * 100 for s, w in sect_words.items()}
|
||||
by_outcome.setdefault("_all", []).append(pct)
|
||||
outcome = canonical_outcome(r["outcome"] or "")
|
||||
if outcome:
|
||||
by_outcome.setdefault(outcome, []).append(pct)
|
||||
|
||||
result: dict = {}
|
||||
for outcome, decs in by_outcome.items():
|
||||
avg = {}
|
||||
for sec in ("background", "claims", "discussion", "summary"):
|
||||
vals = [d.get(sec, 0.0) for d in decs]
|
||||
if vals:
|
||||
avg[sec] = round(sum(vals) / len(vals), 1)
|
||||
result[outcome] = {"n": len(decs), "sections": avg}
|
||||
_CORPUS_RATIOS_CACHE = result
|
||||
return result
|
||||
|
||||
|
||||
def count_anti_patterns(text: str) -> dict:
|
||||
"""Count each anti-pattern occurrence in text. Lower = closer to Dafna."""
|
||||
|
||||
@@ -170,6 +170,41 @@ async def get_style_guide() -> str:
|
||||
)
|
||||
result += "\n"
|
||||
|
||||
# T10 — measured-from-corpus ratios alongside the targets, ⚠️ flags a gap
|
||||
# (actual average outside the target range → revisit the target or the corpus).
|
||||
try:
|
||||
from legal_mcp.services.style_distance import measure_corpus_ratios
|
||||
measured = await measure_corpus_ratios()
|
||||
if measured:
|
||||
result += "### נמדד מהקורפוס בפועל (ממוצע) — ⚠️ = פער מהיעד\n\n"
|
||||
result += "| קבוצה | רקע | טענות | דיון | סיכום |\n|---|------|-------|------|-------|\n"
|
||||
# Per-outcome rows (flagged vs that outcome's target), when outcomes exist.
|
||||
for outcome in VALID_OUTCOMES:
|
||||
m = measured.get(outcome)
|
||||
if not m:
|
||||
continue
|
||||
tgt = GOLDEN_RATIOS[outcome]
|
||||
cells = []
|
||||
for sec in ("background", "claims", "discussion", "summary"):
|
||||
val = m["sections"].get(sec)
|
||||
if val is None:
|
||||
cells.append("—")
|
||||
continue
|
||||
lo, hi = tgt[sec]
|
||||
cells.append(f"{val}%" + ("" if lo <= val <= hi else " ⚠️"))
|
||||
result += f"| {outcome_labels[outcome]} (n={m['n']}) | " + " | ".join(cells) + " |\n"
|
||||
# "_all" aggregate — the meaningful row today (corpus outcome unpopulated);
|
||||
# shown informationally (no single target to flag against).
|
||||
allm = measured.get("_all")
|
||||
if allm:
|
||||
cells = [f"{allm['sections'].get(s, '—')}%" if allm['sections'].get(s) is not None else "—"
|
||||
for s in ("background", "claims", "discussion", "summary")]
|
||||
result += f"| כל ההחלטות (n={allm['n']}) | " + " | ".join(cells) + " |\n"
|
||||
result += ("\n_⚠️ = הממוצע בפועל חורג מטווח-היעד; שקול לעדכן יעד ב-/methodology או לבדוק את הקורפוס. "
|
||||
"פיצול לפי-תוצאה יופיע כש-`style_corpus.outcome` יאוכלס._\n\n")
|
||||
except Exception as e: # surfaced, not swallowed
|
||||
result += f"_מדידת יחסי-זהב מהקורפוס נכשלה: {e}_\n\n"
|
||||
|
||||
# Opening and summary strategies
|
||||
result += "## אסטרטגיות פתיחה וסיכום לפי תוצאה\n\n"
|
||||
for outcome in VALID_OUTCOMES:
|
||||
|
||||
@@ -1113,6 +1113,52 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/cases/{case_number}/decision-blocks": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/**
|
||||
* Api Get Decision Blocks
|
||||
* @description Return all 12 decision blocks as JSON (empty blocks included).
|
||||
*
|
||||
* Read path for the interactive block viewer — content lives in
|
||||
* decision_blocks but was previously only reachable via DOCX export.
|
||||
*/
|
||||
get: operations["api_get_decision_blocks_api_cases__case_number__decision_blocks_get"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/cases/{case_number}/decision-blocks/{block_id}": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
get?: never;
|
||||
/**
|
||||
* Api Update Decision Block
|
||||
* @description Save inline-edited content for a single decision block.
|
||||
*
|
||||
* Writes to decision_blocks (upsert, status='draft') and rebuilds the
|
||||
* on-disk decision.md. Creates a decision row if none exists yet.
|
||||
*/
|
||||
put: operations["api_update_decision_block_api_cases__case_number__decision_blocks__block_id__put"];
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/cases/{case_number}/learn": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -1959,6 +2005,88 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/learning/pairs": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/**
|
||||
* Api Learning Pairs
|
||||
* @description פנקס-ההתאמה (INV-LRN4) — כל ההחלטות וסטטוס ההשוואה מול הסופי.
|
||||
* status אופציונלי: final_received / analyzed / lessons_folded.
|
||||
*/
|
||||
get: operations["api_learning_pairs_api_learning_pairs_get"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/learning/style-distance/{case_number}": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/**
|
||||
* Api Learning Style Distance
|
||||
* @description מדד מרחק-סגנון (T7) לתיק — האם הטיוטה מתכנסת לדפנה.
|
||||
*/
|
||||
get: operations["api_learning_style_distance_api_learning_style_distance__case_number__get"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/learning/pairs/{pair_id}": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/**
|
||||
* Api Learning Pair Detail
|
||||
* @description פירוט שורת-פנקס כולל הצעת-הדיסטילציה (analysis) לאישור יו"ר (T14).
|
||||
*/
|
||||
get: operations["api_learning_pair_detail_api_learning_pairs__pair_id__get"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/learning/pairs/{pair_id}/promote": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
get?: never;
|
||||
put?: never;
|
||||
/**
|
||||
* Api Learning Promote
|
||||
* @description שער-יו"ר (INV-G10/LRN1): מאשר לקחי-סגנון + ביטויי-מעבר מהצעת-הדיסטילציה
|
||||
* ומטמיע אותם בערוצים שהכותב צורך (methodology overrides → T15). מקדם status.
|
||||
*/
|
||||
post: operations["api_learning_promote_api_learning_pairs__pair_id__promote_post"];
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/api/admin/skills": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -2254,7 +2382,14 @@ export interface paths {
|
||||
head?: never;
|
||||
/**
|
||||
* Api Resolve Feedback
|
||||
* @description Mark feedback as resolved.
|
||||
* @description Mark feedback as resolved. When ``fold`` is true (default) and the entry
|
||||
* has an extracted lesson, also wake the CEO to fold that lesson into the
|
||||
* right knowledge file (the feedback→agent-knowledge loop).
|
||||
*
|
||||
* The fold is fire-and-forget (BackgroundTask) and best-effort — resolving
|
||||
* never fails because Paperclip is down. Pass ``fold=false`` for pure
|
||||
* bookkeeping resolves (e.g. from the per-case drafts panel) to avoid
|
||||
* spawning a CEO run per click.
|
||||
*/
|
||||
patch: operations["api_resolve_feedback_api_feedback__feedback_id__resolve_patch"];
|
||||
trace?: never;
|
||||
@@ -2566,7 +2701,13 @@ export interface paths {
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/** Halachot List */
|
||||
/**
|
||||
* Halachot List
|
||||
* @description List halachot. ``exclude_low_quality`` hides flagged items (#84.1) and
|
||||
* ``order_by_priority`` switches to the active-learning order (#84.3). Both
|
||||
* default off so existing callers are unaffected; the review-queue view opts
|
||||
* in.
|
||||
*/
|
||||
get: operations["halachot_list_api_halachot_get"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
@@ -2746,6 +2887,11 @@ export interface components {
|
||||
/** Issue Id */
|
||||
issue_id?: string | null;
|
||||
};
|
||||
/** BlockUpdateRequest */
|
||||
BlockUpdateRequest: {
|
||||
/** Content */
|
||||
content: string;
|
||||
};
|
||||
/** Body_api_create_feedback_api_feedback_post */
|
||||
Body_api_create_feedback_api_feedback_post: {
|
||||
/**
|
||||
@@ -3475,6 +3621,19 @@ export interface components {
|
||||
/** Citation Formatted */
|
||||
citation_formatted?: string | null;
|
||||
};
|
||||
/** PromoteLearningRequest */
|
||||
PromoteLearningRequest: {
|
||||
/**
|
||||
* Lessons
|
||||
* @default []
|
||||
*/
|
||||
lessons: string[];
|
||||
/**
|
||||
* Phrases
|
||||
* @default []
|
||||
*/
|
||||
phrases: string[];
|
||||
};
|
||||
/** ReviseRequest */
|
||||
ReviseRequest: {
|
||||
/** Revisions */
|
||||
@@ -5263,6 +5422,73 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
};
|
||||
api_get_decision_blocks_api_cases__case_number__decision_blocks_get: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
case_number: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": unknown;
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HTTPValidationError"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
api_update_decision_block_api_cases__case_number__decision_blocks__block_id__put: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
case_number: string;
|
||||
block_id: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["BlockUpdateRequest"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": unknown;
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HTTPValidationError"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
api_learn_api_cases__case_number__learn_post: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -6575,6 +6801,135 @@ export interface operations {
|
||||
};
|
||||
};
|
||||
};
|
||||
api_learning_pairs_api_learning_pairs_get: {
|
||||
parameters: {
|
||||
query?: {
|
||||
status?: string;
|
||||
limit?: number;
|
||||
};
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": unknown;
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HTTPValidationError"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
api_learning_style_distance_api_learning_style_distance__case_number__get: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
case_number: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": unknown;
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HTTPValidationError"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
api_learning_pair_detail_api_learning_pairs__pair_id__get: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
pair_id: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": unknown;
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HTTPValidationError"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
api_learning_promote_api_learning_pairs__pair_id__promote_post: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
pair_id: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["PromoteLearningRequest"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": unknown;
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HTTPValidationError"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
api_list_skills_api_admin_skills_get: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -7580,6 +7935,8 @@ export interface operations {
|
||||
practice_area?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
exclude_low_quality?: boolean;
|
||||
order_by_priority?: boolean;
|
||||
};
|
||||
header?: never;
|
||||
path?: never;
|
||||
|
||||
Reference in New Issue
Block a user