Spaces:
Running
Running
Chaudhry Waleed commited on
Commit ·
b7bc437
1
Parent(s): 97816bd
Deploy RICS v2 (senior baseline, CPU Spaces Dockerfile)
Browse files
backend/api/routes/legacy_api_routes.py
CHANGED
|
@@ -712,6 +712,7 @@ def _content_catalog(survey_level: int, property_type: str = "") -> dict:
|
|
| 712 |
"group_labels": review_taxonomy.group_labels_for(resolved),
|
| 713 |
"structure_mode": "content",
|
| 714 |
"property_type": resolved,
|
|
|
|
| 715 |
}
|
| 716 |
|
| 717 |
|
|
|
|
| 712 |
"group_labels": review_taxonomy.group_labels_for(resolved),
|
| 713 |
"structure_mode": "content",
|
| 714 |
"property_type": resolved,
|
| 715 |
+
"taxonomy_version": review_taxonomy.REVIEW_TAXONOMY_VERSION,
|
| 716 |
}
|
| 717 |
|
| 718 |
|
backend/content_based/review_taxonomy.py
CHANGED
|
@@ -37,7 +37,7 @@ from typing import Any
|
|
| 37 |
from backend.content_based import taxonomy
|
| 38 |
from backend.domain.property_type import PROPERTY_TYPES, try_canonical_property_type
|
| 39 |
|
| 40 |
-
REVIEW_TAXONOMY_VERSION = "r2.
|
| 41 |
|
| 42 |
# Ordered groups, each with its fixed sub-topics (id + label only). Catch-all
|
| 43 |
# "Other" chips and the second Heating chip use disambiguated on-screen labels
|
|
@@ -81,7 +81,7 @@ REVIEW_GROUPS: tuple[dict[str, Any], ...] = (
|
|
| 81 |
},
|
| 82 |
{
|
| 83 |
"id": "built_in_fittings",
|
| 84 |
-
"label": "Built-in fittings (
|
| 85 |
},
|
| 86 |
{
|
| 87 |
"id": "woodwork_joinery",
|
|
|
|
| 37 |
from backend.content_based import taxonomy
|
| 38 |
from backend.domain.property_type import PROPERTY_TYPES, try_canonical_property_type
|
| 39 |
|
| 40 |
+
REVIEW_TAXONOMY_VERSION = "r2.4"
|
| 41 |
|
| 42 |
# Ordered groups, each with its fixed sub-topics (id + label only). Catch-all
|
| 43 |
# "Other" chips and the second Heating chip use disambiguated on-screen labels
|
|
|
|
| 81 |
},
|
| 82 |
{
|
| 83 |
"id": "built_in_fittings",
|
| 84 |
+
"label": "Built-in fittings (built-in kitchen and other fittings, not including appliances)",
|
| 85 |
},
|
| 86 |
{
|
| 87 |
"id": "woodwork_joinery",
|
backend/note_quality/orchestrator.py
CHANGED
|
@@ -21,6 +21,7 @@ import logging
|
|
| 21 |
|
| 22 |
from backend.config import settings
|
| 23 |
from backend.content_based import review_taxonomy
|
|
|
|
| 24 |
from backend.note_quality import judge as judge_llm
|
| 25 |
from backend.note_quality.models import (
|
| 26 |
GRADE_RED,
|
|
@@ -186,7 +187,7 @@ async def grade_subtopics(items: list[GradeItem]) -> NoteQualityResult:
|
|
| 186 |
continue
|
| 187 |
|
| 188 |
notes = (item.notes or "").strip()
|
| 189 |
-
if not notes:
|
| 190 |
result.grades[code] = SubtopicGrade(
|
| 191 |
code=code,
|
| 192 |
grade=GRADE_RED,
|
|
|
|
| 21 |
|
| 22 |
from backend.config import settings
|
| 23 |
from backend.content_based import review_taxonomy
|
| 24 |
+
from backend.content_based.intake import EMPTY_SUBSECTION
|
| 25 |
from backend.note_quality import judge as judge_llm
|
| 26 |
from backend.note_quality.models import (
|
| 27 |
GRADE_RED,
|
|
|
|
| 187 |
continue
|
| 188 |
|
| 189 |
notes = (item.notes or "").strip()
|
| 190 |
+
if not notes or notes == EMPTY_SUBSECTION:
|
| 191 |
result.grades[code] = SubtopicGrade(
|
| 192 |
code=code,
|
| 193 |
grade=GRADE_RED,
|
backend/note_quality/rubric.py
CHANGED
|
@@ -33,7 +33,7 @@ from backend.note_quality.rubric_entries import ENTRIES as _SOURCE
|
|
| 33 |
# Bumped whenever the practice reissues the document, or whenever entries are
|
| 34 |
# re-keyed onto a new schema as here, so cached grades can be invalidated and a
|
| 35 |
# stale grade is never silently trusted.
|
| 36 |
-
RUBRIC_VERSION = "practice-2026-
|
| 37 |
|
| 38 |
# Sub-topics shown to the surveyor but deliberately not graded, because the source
|
| 39 |
# document does not cover them. They render neutral and stay out of the tally.
|
|
|
|
| 33 |
# Bumped whenever the practice reissues the document, or whenever entries are
|
| 34 |
# re-keyed onto a new schema as here, so cached grades can be invalidated and a
|
| 35 |
# stale grade is never silently trusted.
|
| 36 |
+
RUBRIC_VERSION = "practice-2026-08e"
|
| 37 |
|
| 38 |
# Sub-topics shown to the surveyor but deliberately not graded, because the source
|
| 39 |
# document does not cover them. They render neutral and stay out of the tally.
|
backend/note_quality/rubric_entries.py
CHANGED
|
@@ -512,25 +512,24 @@ _put(
|
|
| 512 |
"Built-in Fittings",
|
| 513 |
"""**GREEN – Sufficient information**
|
| 514 |
|
| 515 |
-
Green if the notes provide sufficient information regarding the principal built-in fittings and their general visible condition.
|
| 516 |
|
| 517 |
Relevant information may include:
|
| 518 |
|
| 519 |
-
* Type of fittings
|
| 520 |
-
*
|
| 521 |
-
*
|
| 522 |
-
*
|
| 523 |
-
*
|
| 524 |
-
* Significant defects
|
| 525 |
|
| 526 |
A complete inventory of every built-in fitting is not required.
|
| 527 |
|
| 528 |
**YELLOW – Limited information**
|
| 529 |
|
| 530 |
-
Yellow if built-in fittings are merely identified without meaningful information regarding their condition.
|
| 531 |
|
| 532 |
Example Yellow:
|
| 533 |
-
|
| 534 |
|
| 535 |
**RED – No information**
|
| 536 |
|
|
|
|
| 512 |
"Built-in Fittings",
|
| 513 |
"""**GREEN – Sufficient information**
|
| 514 |
|
| 515 |
+
Green if the notes provide sufficient information regarding the principal built-in fittings (e.g., kitchen units, worktops, taps, extractor hoods) and their general visible condition, operation, or testing limitations.
|
| 516 |
|
| 517 |
Relevant information may include:
|
| 518 |
|
| 519 |
+
* Type and description of fittings (e.g., units, worktops, recirculating/ducted extractor hoods)
|
| 520 |
+
* General condition and Condition Ratings (e.g., acceptable, average, good; CR1 or CR2)
|
| 521 |
+
* Operation where relevant (e.g., tap water flow/pressure, extractor fan functionality or need for upgrades)
|
| 522 |
+
* Damage/deterioration or maintenance advice (e.g., sealant condition, discolouration, water ingress risks)
|
| 523 |
+
* Limitations on testing (e.g., disconnected water/electricity supply or disclaimers on built-in appliances)
|
|
|
|
| 524 |
|
| 525 |
A complete inventory of every built-in fitting is not required.
|
| 526 |
|
| 527 |
**YELLOW – Limited information**
|
| 528 |
|
| 529 |
+
Yellow if built-in fittings are merely identified without meaningful information regarding their condition, operational state, or defect notes.
|
| 530 |
|
| 531 |
Example Yellow:
|
| 532 |
+
"Kitchen contains fitted units, worktops, a mixer tap, and an extractor hood."
|
| 533 |
|
| 534 |
**RED – No information**
|
| 535 |
|
frontend/index.html
CHANGED
|
@@ -1332,6 +1332,8 @@ const state = {
|
|
| 1332 |
noteStagesDumpPath: '',
|
| 1333 |
/** Stage A review-chip notes keyed by review sub-topic id (for note-quality UI). */
|
| 1334 |
reviewAssignments: {},
|
|
|
|
|
|
|
| 1335 |
/** After content-mode Stage A, Configure shows RICS leaf cards instead of review chips. */
|
| 1336 |
notesUiRics: false,
|
| 1337 |
currentStep: 1,
|
|
@@ -1366,7 +1368,7 @@ const STATIC_L3_SECTIONS = [
|
|
| 1366 |
{ code:'E3', group:'E', title:'Walls and partitions', hint:'walls · partitions · damp · cracking · condition rating' },
|
| 1367 |
{ code:'E4', group:'E', title:'Floors', hint:'floors · suspended · solid · springy · condition rating' },
|
| 1368 |
{ code:'E5', group:'E', title:'Fireplaces, chimney breasts and flues', hint:'fireplaces · chimney breasts · flues · hearth · condition rating' },
|
| 1369 |
-
{ code:'E6', group:'E', title:'Built-in fittings', hint:'built-in kitchen ·
|
| 1370 |
{ code:'E7', group:'E', title:'Woodwork', hint:'staircase · skirting · architrave · internal doors · condition rating' },
|
| 1371 |
{ code:'E8', group:'E', title:'Bathroom fittings', hint:'bathroom fittings · sanitaryware · shower · WC · condition rating' },
|
| 1372 |
{ code:'E9', group:'E', title:'Other', hint:'cellar · basement · other inside · condition rating' },
|
|
@@ -1429,7 +1431,12 @@ async function loadTemplateCatalog(surveyLevel) {
|
|
| 1429 |
const modeQ = `&structure_mode=${encodeURIComponent(state.structureMode || 'rics')}`;
|
| 1430 |
// Content mode scopes the sub-topic list by property type; RICS mode ignores it.
|
| 1431 |
const ptQ = `&property_type=${encodeURIComponent(state.propertyType || 'house')}`;
|
| 1432 |
-
const
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1433 |
RICS_SECTIONS = (cat.sections || []).map(s => ({
|
| 1434 |
code: s.code,
|
| 1435 |
group: s.group,
|
|
@@ -1438,7 +1445,7 @@ async function loadTemplateCatalog(surveyLevel) {
|
|
| 1438 |
}));
|
| 1439 |
RICS_GROUP_LABELS = { ...(cat.group_labels || {}) };
|
| 1440 |
state.surveyLevel = cat.survey_level;
|
| 1441 |
-
if (
|
| 1442 |
state.notesUiRics = false;
|
| 1443 |
REVIEW_SUBTOPICS = RICS_SECTIONS.slice();
|
| 1444 |
REVIEW_GROUP_LABELS = { ...RICS_GROUP_LABELS };
|
|
@@ -1450,11 +1457,15 @@ async function loadReviewSubtopicCatalog(surveyLevel) {
|
|
| 1450 |
const sl = (Number.isFinite(surveyLevel) && surveyLevel >= 1 && surveyLevel <= 3)
|
| 1451 |
? Math.floor(Number(surveyLevel)) : 3;
|
| 1452 |
const ptQ = `&property_type=${encodeURIComponent(state.propertyType || 'house')}`;
|
|
|
|
|
|
|
|
|
|
| 1453 |
const cat = await apiFetch(
|
| 1454 |
'GET',
|
| 1455 |
-
`/templates/catalog?survey_level=${encodeURIComponent(sl)}&structure_mode=content${ptQ}`,
|
| 1456 |
null,
|
| 1457 |
);
|
|
|
|
| 1458 |
REVIEW_SUBTOPICS = (cat.sections || []).map(s => ({
|
| 1459 |
code: s.code,
|
| 1460 |
group: s.group,
|
|
@@ -1462,6 +1473,7 @@ async function loadReviewSubtopicCatalog(surveyLevel) {
|
|
| 1462 |
hint: s.hint || '',
|
| 1463 |
}));
|
| 1464 |
REVIEW_GROUP_LABELS = { ...(cat.group_labels || {}) };
|
|
|
|
| 1465 |
}
|
| 1466 |
|
| 1467 |
/** Reload Configure cards as RICS leaves after content-mode Stage A remap. */
|
|
|
|
| 1332 |
noteStagesDumpPath: '',
|
| 1333 |
/** Stage A review-chip notes keyed by review sub-topic id (for note-quality UI). */
|
| 1334 |
reviewAssignments: {},
|
| 1335 |
+
/** Content-mode catalog version from GET /templates/catalog (cache-bust + relabel). */
|
| 1336 |
+
reviewTaxonomyVersion: '',
|
| 1337 |
/** After content-mode Stage A, Configure shows RICS leaf cards instead of review chips. */
|
| 1338 |
notesUiRics: false,
|
| 1339 |
currentStep: 1,
|
|
|
|
| 1368 |
{ code:'E3', group:'E', title:'Walls and partitions', hint:'walls · partitions · damp · cracking · condition rating' },
|
| 1369 |
{ code:'E4', group:'E', title:'Floors', hint:'floors · suspended · solid · springy · condition rating' },
|
| 1370 |
{ code:'E5', group:'E', title:'Fireplaces, chimney breasts and flues', hint:'fireplaces · chimney breasts · flues · hearth · condition rating' },
|
| 1371 |
+
{ code:'E6', group:'E', title:'Built-in fittings', hint:'built-in kitchen · worktops · cupboards · extractor hood · not appliances' },
|
| 1372 |
{ code:'E7', group:'E', title:'Woodwork', hint:'staircase · skirting · architrave · internal doors · condition rating' },
|
| 1373 |
{ code:'E8', group:'E', title:'Bathroom fittings', hint:'bathroom fittings · sanitaryware · shower · WC · condition rating' },
|
| 1374 |
{ code:'E9', group:'E', title:'Other', hint:'cellar · basement · other inside · condition rating' },
|
|
|
|
| 1431 |
const modeQ = `&structure_mode=${encodeURIComponent(state.structureMode || 'rics')}`;
|
| 1432 |
// Content mode scopes the sub-topic list by property type; RICS mode ignores it.
|
| 1433 |
const ptQ = `&property_type=${encodeURIComponent(state.propertyType || 'house')}`;
|
| 1434 |
+
const isContent = (state.structureMode || 'rics') === 'content';
|
| 1435 |
+
const vQ = isContent && state.reviewTaxonomyVersion
|
| 1436 |
+
? `&taxonomy_version=${encodeURIComponent(state.reviewTaxonomyVersion)}`
|
| 1437 |
+
: '';
|
| 1438 |
+
const cat = await apiFetch('GET', `/templates/catalog?survey_level=${encodeURIComponent(sl)}${modeQ}${ptQ}${vQ}`, null);
|
| 1439 |
+
if (cat.taxonomy_version) state.reviewTaxonomyVersion = cat.taxonomy_version;
|
| 1440 |
RICS_SECTIONS = (cat.sections || []).map(s => ({
|
| 1441 |
code: s.code,
|
| 1442 |
group: s.group,
|
|
|
|
| 1445 |
}));
|
| 1446 |
RICS_GROUP_LABELS = { ...(cat.group_labels || {}) };
|
| 1447 |
state.surveyLevel = cat.survey_level;
|
| 1448 |
+
if (isContent) {
|
| 1449 |
state.notesUiRics = false;
|
| 1450 |
REVIEW_SUBTOPICS = RICS_SECTIONS.slice();
|
| 1451 |
REVIEW_GROUP_LABELS = { ...RICS_GROUP_LABELS };
|
|
|
|
| 1457 |
const sl = (Number.isFinite(surveyLevel) && surveyLevel >= 1 && surveyLevel <= 3)
|
| 1458 |
? Math.floor(Number(surveyLevel)) : 3;
|
| 1459 |
const ptQ = `&property_type=${encodeURIComponent(state.propertyType || 'house')}`;
|
| 1460 |
+
const vQ = state.reviewTaxonomyVersion
|
| 1461 |
+
? `&taxonomy_version=${encodeURIComponent(state.reviewTaxonomyVersion)}`
|
| 1462 |
+
: '';
|
| 1463 |
const cat = await apiFetch(
|
| 1464 |
'GET',
|
| 1465 |
+
`/templates/catalog?survey_level=${encodeURIComponent(sl)}&structure_mode=content${ptQ}${vQ}`,
|
| 1466 |
null,
|
| 1467 |
);
|
| 1468 |
+
if (cat.taxonomy_version) state.reviewTaxonomyVersion = cat.taxonomy_version;
|
| 1469 |
REVIEW_SUBTOPICS = (cat.sections || []).map(s => ({
|
| 1470 |
code: s.code,
|
| 1471 |
group: s.group,
|
|
|
|
| 1473 |
hint: s.hint || '',
|
| 1474 |
}));
|
| 1475 |
REVIEW_GROUP_LABELS = { ...(cat.group_labels || {}) };
|
| 1476 |
+
if ((state.structureMode || 'rics') === 'content') renderTopicCoverage();
|
| 1477 |
}
|
| 1478 |
|
| 1479 |
/** Reload Configure cards as RICS leaves after content-mode Stage A remap. */
|