feat(seed): provision taxonomy buckets (infra) + exam-corpus loader skeleton
infra (buckets.py): add cc.public / cc.institutes / cc.admin to the bucket provisioner alongside cc.examboards; make initialize_buckets idempotent (already-exists treated as success). Bucket provisioning stays in infra init. new (seed_exam_corpus.py): manifest-driven loader scaffold that USES the buckets (does not create them) — validate -> upload to cc.examboards (canonical path) -> upsert eb_specifications/eb_exams -> optional user test subset -> optional --first-sweep auto-map pass. TODOs marked for the gathering task to complete. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
e6be762f0c
commit
9aabc12062
@@ -46,7 +46,7 @@ def initialize_buckets() -> dict:
|
||||
file_size_limit=1000 * 1024 * 1024, # 1GB
|
||||
)
|
||||
},
|
||||
# Exam Board files
|
||||
# Exam Board files (admin-curated public exam corpus: QP/MS/insert/ER + specs)
|
||||
{
|
||||
"id": "cc.examboards",
|
||||
"options": CreateBucketOptions(
|
||||
@@ -55,6 +55,34 @@ def initialize_buckets() -> dict:
|
||||
file_size_limit=1000 * 1024 * 1024, # 1GB
|
||||
)
|
||||
},
|
||||
# ── Storage taxonomy bins (access scoped by RLS on bucket + leading path segment; RLS = D1) ──
|
||||
# Platform-managed public/shared assets (readable by all authenticated users).
|
||||
{
|
||||
"id": "cc.public",
|
||||
"options": CreateBucketOptions(
|
||||
name="Classroom Copilot Public",
|
||||
public=False,
|
||||
file_size_limit=1000 * 1024 * 1024, # 1GB
|
||||
)
|
||||
},
|
||||
# Institute-scoped operational assets: cc.institutes/{institute_id}/...
|
||||
{
|
||||
"id": "cc.institutes",
|
||||
"options": CreateBucketOptions(
|
||||
name="Classroom Copilot Institutes",
|
||||
public=False,
|
||||
file_size_limit=1000 * 1024 * 1024, # 1GB
|
||||
)
|
||||
},
|
||||
# Platform-admin-only assets, seeds, intake/staging for unidentified papers.
|
||||
{
|
||||
"id": "cc.admin",
|
||||
"options": CreateBucketOptions(
|
||||
name="Classroom Copilot Admin",
|
||||
public=False,
|
||||
file_size_limit=1000 * 1024 * 1024, # 1GB
|
||||
)
|
||||
},
|
||||
]
|
||||
|
||||
results = {}
|
||||
@@ -81,11 +109,17 @@ def initialize_buckets() -> dict:
|
||||
logger.error(f"Failed to create bucket: {bucket['id']}")
|
||||
|
||||
except Exception as e:
|
||||
results[bucket["id"]] = {
|
||||
"status": "error",
|
||||
"error": str(e)
|
||||
}
|
||||
logger.error(f"Error creating bucket {bucket['id']}: {str(e)}")
|
||||
# Idempotent: an already-existing bucket is not a failure on re-run.
|
||||
if any(s in str(e).lower() for s in ("already exists", "duplicate", "resource already")):
|
||||
results[bucket["id"]] = {"status": "exists", "result": str(e)}
|
||||
success_count += 1
|
||||
logger.info(f"Bucket already exists (ok): {bucket['id']}")
|
||||
else:
|
||||
results[bucket["id"]] = {
|
||||
"status": "error",
|
||||
"error": str(e)
|
||||
}
|
||||
logger.error(f"Error creating bucket {bucket['id']}: {str(e)}")
|
||||
|
||||
# Determine overall success
|
||||
if success_count == total_count:
|
||||
|
||||
Reference in New Issue
Block a user