@mindflight/mindbrain-personal-studio 0.6.1 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -8
- package/build/client/_app/immutable/chunks/CIErFlYG.js +1 -0
- package/build/client/_app/immutable/chunks/CIErFlYG.js.br +0 -0
- package/build/client/_app/immutable/chunks/CIErFlYG.js.gz +0 -0
- package/build/client/_app/immutable/entry/{app.CVz6aYsT.js → app.mURYm8o_.js} +2 -2
- package/build/client/_app/immutable/entry/app.mURYm8o_.js.br +0 -0
- package/build/client/_app/immutable/entry/app.mURYm8o_.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.D4M9ZeGO.js +1 -0
- package/build/client/_app/immutable/entry/start.D4M9ZeGO.js.br +2 -0
- package/build/client/_app/immutable/entry/start.D4M9ZeGO.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{1.BBtxY46Q.js → 1.DHKtMeFI.js} +1 -1
- package/build/client/_app/immutable/nodes/1.DHKtMeFI.js.br +1 -0
- package/build/client/_app/immutable/nodes/1.DHKtMeFI.js.gz +0 -0
- package/build/client/_app/version.json +1 -1
- package/build/client/_app/version.json.br +0 -0
- package/build/client/_app/version.json.gz +0 -0
- package/build/handler.js +4 -4
- package/build/index.js +4 -4
- package/build/server/chunks/chunks/{internal.js-D8EA_he2.js → internal.js-C3tV0XXj.js} +2 -2
- package/build/server/chunks/chunks/{internal.js-D8EA_he2.js.map → internal.js-C3tV0XXj.js.map} +1 -1
- package/build/server/chunks/entries/endpoints/api/graph/schema-registry/{_server.ts.js-Dyfsc-VA.js → _server.ts.js-CAsXxBRq.js} +7 -2
- package/build/server/chunks/entries/endpoints/api/graph/schema-registry/_server.ts.js-CAsXxBRq.js.map +1 -0
- package/build/server/chunks/{handler-BjXBCd1c.js → handler-DlaCCnxx.js} +3 -3
- package/build/server/chunks/{handler-BjXBCd1c.js.map → handler-DlaCCnxx.js.map} +1 -1
- package/build/server/chunks/{index.js-BJYcV8V7.js → index.js-BGfKWHak.js} +2 -2
- package/build/server/chunks/{index.js-BJYcV8V7.js.map → index.js-BGfKWHak.js.map} +1 -1
- package/build/server/chunks/{manifest.js-Ddaot0P4.js → manifest.js-CnmaNf5D.js} +4 -4
- package/build/server/chunks/{manifest.js-Ddaot0P4.js.map → manifest.js-CnmaNf5D.js.map} +1 -1
- package/build/server/chunks/nodes/{1.js-BRigw_9J.js → 1.js-BypjwBYB.js} +2 -2
- package/build/server/chunks/nodes/{1.js-BRigw_9J.js.map → 1.js-BypjwBYB.js.map} +1 -1
- package/examples/immeuble/ACCEPTANCE.yaml +82 -0
- package/examples/immeuble/BIM_LITE.md +15 -0
- package/examples/immeuble/CHECKLIST.md +128 -0
- package/examples/immeuble/README.md +121 -0
- package/examples/immeuble/bundle/immeuble.bundle.json +22786 -0
- package/examples/immeuble/contracts/answer_artifacts.seed.jsonl +34 -0
- package/examples/immeuble/contracts/business_capabilities.seed.jsonl +25 -0
- package/examples/immeuble/contracts/consumer_contract.yaml +131 -0
- package/examples/immeuble/contracts/immeuble_structured_import_model.json +310 -0
- package/examples/immeuble/contracts/mapping_external_to_canonical.json +375 -0
- package/examples/immeuble/contracts/mapping_external_to_canonical.yaml +55 -0
- package/examples/immeuble/contracts/mapping_external_to_canonical_ws.json +65 -0
- package/examples/immeuble/contracts/model_contract.json +943 -0
- package/examples/immeuble/contracts/projection_catalog.yaml +366 -0
- package/examples/immeuble/contracts/scenarios.yaml +27 -0
- package/examples/immeuble/contracts/semantic_proposal.golden.json +1 -0
- package/examples/immeuble/contracts/source_profile.yaml +38 -0
- package/examples/immeuble/fake_data/DeltaFinding.csv +20 -0
- package/examples/immeuble/fake_data/ProjectionResult.csv +13 -0
- package/examples/immeuble/fake_data/ag_meeting.csv +4 -0
- package/examples/immeuble/fake_data/agenda_item.csv +4 -0
- package/examples/immeuble/fake_data/architect.csv +3 -0
- package/examples/immeuble/fake_data/architecture_firm.csv +2 -0
- package/examples/immeuble/fake_data/bank_account.csv +3 -0
- package/examples/immeuble/fake_data/billing_group.csv +41 -0
- package/examples/immeuble/fake_data/block.csv +10 -0
- package/examples/immeuble/fake_data/budget_line.csv +3 -0
- package/examples/immeuble/fake_data/building.csv +6 -0
- package/examples/immeuble/fake_data/cellar.csv +41 -0
- package/examples/immeuble/fake_data/change_order.csv +2 -0
- package/examples/immeuble/fake_data/charge_call.csv +58 -0
- package/examples/immeuble/fake_data/claim.csv +4 -0
- package/examples/immeuble/fake_data/coda_entry.csv +49 -0
- package/examples/immeuble/fake_data/compliance_certificate.csv +10 -0
- package/examples/immeuble/fake_data/contractor.csv +4 -0
- package/examples/immeuble/fake_data/decision.csv +5 -0
- package/examples/immeuble/fake_data/defect_reserve.csv +3 -0
- package/examples/immeuble/fake_data/household.csv +41 -0
- package/examples/immeuble/fake_data/inspection.csv +3 -0
- package/examples/immeuble/fake_data/insurance_policy.csv +4 -0
- package/examples/immeuble/fake_data/intervention.csv +13 -0
- package/examples/immeuble/fake_data/invoice.csv +3 -0
- package/examples/immeuble/fake_data/lease_contract.csv +12 -0
- package/examples/immeuble/fake_data/maintenance_ticket.csv +13 -0
- package/examples/immeuble/fake_data/meter.csv +4 -0
- package/examples/immeuble/fake_data/meter_reading.csv +19 -0
- package/examples/immeuble/fake_data/milestone.csv +3 -0
- package/examples/immeuble/fake_data/organization.csv +12 -0
- package/examples/immeuble/fake_data/parking_space.csv +8 -0
- package/examples/immeuble/fake_data/permit.csv +3 -0
- package/examples/immeuble/fake_data/person.csv +85 -0
- package/examples/immeuble/fake_data/private_garden.csv +7 -0
- package/examples/immeuble/fake_data/progress_event.csv +2 -0
- package/examples/immeuble/fake_data/quote.csv +3 -0
- package/examples/immeuble/fake_data/receipt.csv +2 -0
- package/examples/immeuble/fake_data/reminder.csv +11 -0
- package/examples/immeuble/fake_data/service_contract.csv +4 -0
- package/examples/immeuble/fake_data/shared_equipment.csv +8 -0
- package/examples/immeuble/fake_data/shared_space.csv +10 -0
- package/examples/immeuble/fake_data/unit.csv +41 -0
- package/examples/immeuble/fake_data/work_package.csv +4 -0
- package/examples/immeuble/fake_data/worksite_project.csv +3 -0
- package/examples/immeuble/gap-rules/L0-patrimoine.json +57 -0
- package/examples/immeuble/gap-rules/L1-syndic-naive.json +36 -0
- package/examples/immeuble/gap-rules/L1-syndic.json +61 -0
- package/examples/immeuble/gap-rules/L2-chantier.json +87 -0
- package/examples/immeuble/gap-rules/L2-exploitation.json +87 -0
- package/examples/immeuble/gap-rules/L2-finance.json +48 -0
- package/examples/immeuble/gap-rules/L2-maintenance.json +107 -0
- package/examples/immeuble/gap-rules/L2-syndic-filtered.json +39 -0
- package/examples/immeuble/gap-rules/L3-full.json +332 -0
- package/examples/immeuble/gap-rules/closed-world-contract.md +76 -0
- package/examples/immeuble/gap-rules/demo.json +51 -0
- package/examples/immeuble/gap-rules/expected-findings.yaml +100 -0
- package/examples/immeuble/gap-rules/gap-scenarios.yaml +79 -0
- package/examples/immeuble/gap-rules/motifs.json +38 -0
- package/examples/immeuble/gap-rules/syndic.json +40 -0
- package/examples/immeuble/import_manifest.yaml +25 -0
- package/examples/immeuble/import_ready/graph_edges_import.csv +848 -0
- package/examples/immeuble/import_ready/mfo_facets_import.csv +559 -0
- package/examples/immeuble/index.md +140 -0
- package/examples/immeuble/model/immeuble_model.json +418 -0
- package/examples/immeuble/reports/01-model.validation.json +56 -0
- package/examples/immeuble/reports/02-mapping.validation.json +9 -0
- package/examples/immeuble/reports/acceptance.validation.json +161 -0
- package/examples/immeuble/reports/consumer_contract.validation.json +162 -0
- package/examples/immeuble/reports/graph_edges.jsonl +847 -0
- package/examples/immeuble/reports/graph_nodes.jsonl +558 -0
- package/examples/immeuble/reports/hybrid-compare.json +144 -0
- package/examples/immeuble/reports/immeuble-import-scenario.json +233 -0
- package/examples/immeuble/reports/live-artifacts-refresh.validation.json +51 -0
- package/examples/immeuble/reports/pipeline_audit.json +59 -0
- package/examples/immeuble/reports/projection_audit.json +69 -0
- package/examples/immeuble/reports/projection_audit_immeuble.json +257 -0
- package/examples/immeuble/reports/projection_audit_immeuble.md +122 -0
- package/examples/immeuble/reports/projection_candidates.json +1596 -0
- package/examples/immeuble/reports/projection_candidates.md +117 -0
- package/examples/immeuble/reports/projection_model_validation.md +115 -0
- package/examples/immeuble/reports/reindex.json +4 -0
- package/examples/immeuble/reports/reset-immeuble-workspace.json +32 -0
- package/examples/immeuble/reports/schema-id-prefix-check.json +5 -0
- package/examples/immeuble/scripts/audit-immeuble-projections.mjs +254 -0
- package/examples/immeuble/scripts/build-immeuble-model.mjs +308 -0
- package/examples/immeuble/scripts/compare-immeuble-snapshots.sh +227 -0
- package/examples/immeuble/scripts/enrich-immeuble-demo.mjs +1135 -0
- package/examples/immeuble/scripts/reset-immeuble-workspace.mjs +139 -0
- package/examples/immeuble/scripts/run-immeuble-backend.sh +164 -0
- package/examples/immeuble/scripts/run-immeuble-import.mjs +232 -0
- package/examples/immeuble/scripts/run-immeuble-live-lab.sh +439 -0
- package/examples/immeuble/scripts/seed-immeuble-gap-rules.mjs +69 -0
- package/examples/immeuble/scripts/start-immeuble-demo.sh +52 -0
- package/examples/immeuble/scripts/starterkit/analysis-lenses.mjs +181 -0
- package/examples/immeuble/scripts/starterkit/analyze-projection-candidates.mjs +714 -0
- package/examples/immeuble/scripts/starterkit/audit-ghostcrab-projections.mjs +674 -0
- package/examples/immeuble/scripts/starterkit/facet-prefix.mjs +166 -0
- package/examples/immeuble/scripts/starterkit/sqlite-utils.mjs +131 -0
- package/examples/immeuble/scripts/verify-immeuble-acceptance.mjs +284 -0
- package/examples/immeuble/scripts/verify-immeuble-live-artifacts.mjs +140 -0
- package/examples/immeuble/scripts/yaml-lite.mjs +96 -0
- package/examples/immeuble/sources/agent-prompts/prompts/00-prerequisites-immo-mcp.md +161 -0
- package/examples/immeuble/sources/agent-prompts/prompts/00-prerequisites.md +39 -0
- package/examples/immeuble/sources/agent-prompts/prompts/01-discovery-and-model-proposal.md +42 -0
- package/examples/immeuble/sources/agent-prompts/prompts/02-ontology-register.md +44 -0
- package/examples/immeuble/sources/agent-prompts/prompts/03-gap-rules-design.md +44 -0
- package/examples/immeuble/sources/agent-prompts/prompts/04-document-ingest.md +40 -0
- package/examples/immeuble/sources/agent-prompts/prompts/05-graph-extraction.md +44 -0
- package/examples/immeuble/sources/agent-prompts/prompts/06-validate-and-compare-immo-mcp.md +109 -0
- package/examples/immeuble/sources/agent-prompts/prompts/06-validate-and-compare-test-immo-mcp3.md +30 -0
- package/examples/immeuble/sources/agent-prompts/prompts/06-validate-and-compare.md +63 -0
- package/examples/immeuble/sources/checklists/gap-rules-checklist.md +42 -0
- package/examples/immeuble/sources/checklists/ontology-checklist.md +54 -0
- package/examples/immeuble/sources/documents/README.md +42 -0
- package/examples/immeuble/sources/documents/annexes-caves-garages-jardins.md +8 -0
- package/examples/immeuble/sources/documents/annexes-jardins-garages.md +1 -0
- package/examples/immeuble/sources/documents/baux-erables.md +1 -0
- package/examples/immeuble/sources/documents/baux-locatifs.md +11 -0
- package/examples/immeuble/sources/documents/coda-janvier-2026.md +10 -0
- package/examples/immeuble/sources/documents/composition-menages.md +1 -0
- package/examples/immeuble/sources/documents/composition-occupants.md +18 -0
- package/examples/immeuble/sources/documents/expected-coverage.json +70 -0
- package/examples/immeuble/sources/documents/extrait-coda-janvier-2026.md +1 -0
- package/examples/immeuble/sources/documents/groupes-facturation.md +30 -0
- package/examples/immeuble/sources/documents/manifest.json +79 -0
- package/examples/immeuble/sources/documents/note-architecte-chantier-erables.md +3 -0
- package/examples/immeuble/sources/documents/permis-urbanisme-erables.md +3 -0
- package/examples/immeuble/sources/documents/procedures-operationnelles.md +3 -0
- package/examples/immeuble/sources/documents/pv-ag-budget-2026.md +1 -0
- package/examples/immeuble/sources/documents/pv-reception-reserves-erables.md +3 -0
- package/examples/immeuble/sources/documents/registre-coproprietaires.md +24 -0
- package/examples/immeuble/sources/documents/reglement-copropriete-tilleuls.md +1 -0
- package/examples/immeuble/sources/documents/statuts-erables.md +22 -0
- package/examples/immeuble/sources/documents/statuts-tilleuls.md +19 -0
- package/examples/immeuble/sources/documents/succession-jean-dupont.md +3 -0
- package/examples/immeuble/sources/documents/titre-propriete-tilleuls-a3.md +1 -0
- package/examples/immeuble/sources/documents/trous-pedagogiques.md +3 -0
- package/examples/immeuble/sources/ontology/README.md +1 -0
- package/examples/immeuble/sources/ontology/core.yaml +444 -0
- package/examples/immeuble/success-criteria.yaml +35 -0
- package/fixtures/immeuble-demo.sqlite +0 -0
- package/package.json +16 -3
- package/scripts/lib/sqlite-runtime.mjs +1 -1
- package/scripts/load-immeuble-demo.sh +103 -0
- package/scripts/seed-immeuble-projections.mjs +75 -148
- package/scripts/verify-immeuble-demo-sources.mjs +93 -0
- package/scripts/verify-immeuble-demo.mjs +69 -0
- package/build/client/_app/immutable/chunks/BmeSanva.js +0 -1
- package/build/client/_app/immutable/chunks/BmeSanva.js.br +0 -0
- package/build/client/_app/immutable/chunks/BmeSanva.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.CVz6aYsT.js.br +0 -0
- package/build/client/_app/immutable/entry/app.CVz6aYsT.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.Bt5tVOz8.js +0 -1
- package/build/client/_app/immutable/entry/start.Bt5tVOz8.js.br +0 -2
- package/build/client/_app/immutable/entry/start.Bt5tVOz8.js.gz +0 -0
- package/build/client/_app/immutable/nodes/1.BBtxY46Q.js.br +0 -0
- package/build/client/_app/immutable/nodes/1.BBtxY46Q.js.gz +0 -0
- package/build/server/chunks/entries/endpoints/api/graph/schema-registry/_server.ts.js-Dyfsc-VA.js.map +0 -1
- package/scripts/build-serenity-v6-concept-review-pack.mjs +0 -493
- package/scripts/build-serenity-v6-review-pack.mjs +0 -479
- package/scripts/create-serenity-production-v6.mjs +0 -627
- package/scripts/export-serenity-v6-backup.mjs +0 -178
- package/scripts/import-serenity-v6-user-decisions.mjs +0 -543
- package/scripts/materialize-serenity-v6-snapshots.mjs +0 -675
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Verify live projection artifacts on a running MindBrain backend.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* node examples/immeuble/scripts/verify-immeuble-live-artifacts.mjs
|
|
7
|
+
* [--workspace immeuble] [--url http://127.0.0.1:8091]
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { readFileSync, mkdirSync, writeFileSync } from "node:fs";
|
|
11
|
+
import { dirname, join, resolve } from "node:path";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
13
|
+
import { parseYaml } from "./yaml-lite.mjs";
|
|
14
|
+
import { spawnSync } from "node:child_process";
|
|
15
|
+
|
|
16
|
+
const immeubleRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
17
|
+
const pkgRoot = resolve(immeubleRoot, "..", "..");
|
|
18
|
+
const gcp = join(pkgRoot, "bin", "gcp.mjs");
|
|
19
|
+
const reportsDir = join(immeubleRoot, "reports");
|
|
20
|
+
const acceptancePath = join(immeubleRoot, "ACCEPTANCE.yaml");
|
|
21
|
+
|
|
22
|
+
const args = process.argv.slice(2);
|
|
23
|
+
const workspaceId = parseFlag(args, "--workspace-id", "immeuble");
|
|
24
|
+
const backendUrl = parseFlag(args, "--url", process.env.GHOSTCRAB_MINDBRAIN_URL ?? "http://127.0.0.1:8091");
|
|
25
|
+
|
|
26
|
+
const acceptance = parseYaml(readFileSync(acceptancePath, "utf8"));
|
|
27
|
+
const requiredArtifacts = acceptance?.projections?.live_answer_view ?? [];
|
|
28
|
+
const result = { ok: true, workspace_id: workspaceId, checks: [] };
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const list = runArtifactCmd(["artifact", "list", "--url", backendUrl, "--workspace-id", workspaceId, "--kind", "live_answer_view"]);
|
|
32
|
+
result.checks.push({ name: "artifact.list", ok: true, detail: `status=${list.status}` });
|
|
33
|
+
|
|
34
|
+
const listPayload = parseJson(list.stdout);
|
|
35
|
+
const artifacts = Array.isArray(listPayload?.artifacts) ? listPayload.artifacts : [];
|
|
36
|
+
const present = new Set(artifacts.map((a) => a?.artifact_id).filter(Boolean));
|
|
37
|
+
|
|
38
|
+
const missing = requiredArtifacts.filter((artifactId) => !present.has(artifactId));
|
|
39
|
+
result.checks.push({
|
|
40
|
+
name: "required_artifacts_present",
|
|
41
|
+
ok: missing.length === 0,
|
|
42
|
+
detail: missing.length ? `missing: ${missing.join(", ")}` : "all required ids listed"
|
|
43
|
+
});
|
|
44
|
+
if (missing.length > 0) {
|
|
45
|
+
throw new Error("missing required live_answer_view artifacts");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const refreshChecks = [];
|
|
49
|
+
for (const artifactId of requiredArtifacts) {
|
|
50
|
+
const refresh = runArtifactCmd(["artifact", "refresh", "--url", backendUrl, artifactId]);
|
|
51
|
+
const refreshPayload = parseJson(refresh.stdout);
|
|
52
|
+
const refreshArtifactId = refreshPayload?.artifact_id || refreshPayload?.artifact?.artifact_id;
|
|
53
|
+
if (typeof refreshArtifactId === "string" && refreshArtifactId.length > 0) {
|
|
54
|
+
result.checks.push({ name: `artifact.refresh.${artifactId}`, ok: true, detail: `artifact_id=${refreshArtifactId}` });
|
|
55
|
+
} else {
|
|
56
|
+
result.checks.push({ name: `artifact.refresh.${artifactId}`, ok: true, detail: "refresh returned JSON payload" });
|
|
57
|
+
}
|
|
58
|
+
refreshChecks.push(refreshPayload);
|
|
59
|
+
|
|
60
|
+
const get = runArtifactCmd(["artifact", "get", "--url", backendUrl, artifactId]);
|
|
61
|
+
const getPayload = parseJson(get.stdout);
|
|
62
|
+
const payload = extractPayload(getPayload) ?? extractPayload(refreshPayload);
|
|
63
|
+
const artifactSummary = typeof payload?.summary === "string" && payload.summary.trim().length > 0;
|
|
64
|
+
const artifactRefreshChecks = Array.isArray(payload?.refresh_checks) && payload.refresh_checks.length > 0;
|
|
65
|
+
const refreshedOperational =
|
|
66
|
+
refreshPayload?.ok === true &&
|
|
67
|
+
payload &&
|
|
68
|
+
(typeof payload.graph_entities === "number" ||
|
|
69
|
+
typeof payload.facts === "number" ||
|
|
70
|
+
typeof payload.graph_relations === "number");
|
|
71
|
+
const payloadOk = (artifactSummary && artifactRefreshChecks) || refreshedOperational;
|
|
72
|
+
result.checks.push({
|
|
73
|
+
name: `artifact.payload.${artifactId}`,
|
|
74
|
+
ok: payloadOk,
|
|
75
|
+
detail: JSON.stringify({
|
|
76
|
+
has_summary: artifactSummary,
|
|
77
|
+
has_refresh_checks: artifactRefreshChecks,
|
|
78
|
+
refreshed_operational: refreshedOperational
|
|
79
|
+
})
|
|
80
|
+
});
|
|
81
|
+
if (!payloadOk) {
|
|
82
|
+
throw new Error(`artifact payload invalid for ${artifactId}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
result.checks.push({ name: "refresh_count", ok: refreshChecks.length === requiredArtifacts.length, detail: `${refreshChecks.length}` });
|
|
87
|
+
result.ok = result.checks.every((item) => item.ok);
|
|
88
|
+
} catch (err) {
|
|
89
|
+
result.ok = false;
|
|
90
|
+
result.error = err instanceof Error ? err.message : String(err);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
mkdirSync(reportsDir, { recursive: true });
|
|
94
|
+
writeFileSync(
|
|
95
|
+
join(reportsDir, "live-artifacts-refresh.validation.json"),
|
|
96
|
+
JSON.stringify(result, null, 2) + "\n",
|
|
97
|
+
"utf8"
|
|
98
|
+
);
|
|
99
|
+
console.log(JSON.stringify(result, null, 2));
|
|
100
|
+
process.exit(result.ok ? 0 : 1);
|
|
101
|
+
|
|
102
|
+
function runArtifactCmd(argsList) {
|
|
103
|
+
const res = spawnSync(process.execPath, [gcp, "brain", ...argsList], {
|
|
104
|
+
cwd: pkgRoot,
|
|
105
|
+
env: {
|
|
106
|
+
...process.env,
|
|
107
|
+
GHOSTCRAB_MINDBRAIN_URL: backendUrl
|
|
108
|
+
},
|
|
109
|
+
encoding: "utf8"
|
|
110
|
+
});
|
|
111
|
+
if (res.status !== 0) {
|
|
112
|
+
throw new Error(`gcp brain ${argsList.join(" ")} failed (${res.status}): ${(res.stderr || res.stdout || "").trim()}`);
|
|
113
|
+
}
|
|
114
|
+
return { status: res.status, stdout: res.stdout || "", stderr: res.stderr || "" };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function parseJson(text) {
|
|
118
|
+
return JSON.parse(text || "{}");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function extractPayload(getPayload) {
|
|
122
|
+
const payloadJson = getPayload?.payload_json;
|
|
123
|
+
if (typeof payloadJson === "string") {
|
|
124
|
+
try {
|
|
125
|
+
return JSON.parse(payloadJson);
|
|
126
|
+
} catch {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (getPayload?.payload && typeof getPayload.payload === "object") {
|
|
131
|
+
return getPayload.payload;
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function parseFlag(argv, name, defaultValue) {
|
|
137
|
+
const index = argv.indexOf(name);
|
|
138
|
+
if (index === -1) return defaultValue;
|
|
139
|
+
return argv[index + 1] ?? defaultValue;
|
|
140
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
export function parseYaml(text) {
|
|
2
|
+
const root = {};
|
|
3
|
+
const stack = [{ indent: -1, value: root }];
|
|
4
|
+
const lines = String(text)
|
|
5
|
+
.split(/\r?\n/)
|
|
6
|
+
.map((raw) => raw.replace(/\s+#.*$/, ""))
|
|
7
|
+
.filter((raw) => raw.trim() && !raw.trim().startsWith("#"));
|
|
8
|
+
|
|
9
|
+
for (const raw of lines) {
|
|
10
|
+
const indent = raw.match(/^ */)?.[0].length ?? 0;
|
|
11
|
+
const line = raw.trim();
|
|
12
|
+
while (stack.length > 1 && indent <= stack[stack.length - 1].indent) stack.pop();
|
|
13
|
+
const parent = stack[stack.length - 1].value;
|
|
14
|
+
|
|
15
|
+
if (line.startsWith("- ")) {
|
|
16
|
+
if (!Array.isArray(parent)) continue;
|
|
17
|
+
const body = line.slice(2).trim();
|
|
18
|
+
if (body.includes(":")) {
|
|
19
|
+
const [key, rest] = splitKeyValue(body);
|
|
20
|
+
const item = {};
|
|
21
|
+
item[key] = parseScalar(rest);
|
|
22
|
+
parent.push(item);
|
|
23
|
+
stack.push({ indent, value: item });
|
|
24
|
+
} else {
|
|
25
|
+
parent.push(parseScalar(body));
|
|
26
|
+
}
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const [key, rest] = splitKeyValue(line);
|
|
31
|
+
if (!key) continue;
|
|
32
|
+
if (rest === "") {
|
|
33
|
+
const next = nextMeaningfulLine(lines, raw);
|
|
34
|
+
const value = next?.trim().startsWith("- ") ? [] : {};
|
|
35
|
+
parent[key] = value;
|
|
36
|
+
stack.push({ indent, value });
|
|
37
|
+
} else {
|
|
38
|
+
parent[key] = parseScalar(rest);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return root;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function nextMeaningfulLine(lines, currentRaw) {
|
|
45
|
+
const currentIndex = lines.indexOf(currentRaw);
|
|
46
|
+
return lines.slice(currentIndex + 1).find((line) => line.trim());
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function splitKeyValue(line) {
|
|
50
|
+
const index = line.indexOf(":");
|
|
51
|
+
if (index === -1) return [line.trim(), ""];
|
|
52
|
+
return [line.slice(0, index).trim(), line.slice(index + 1).trim()];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function parseScalar(raw) {
|
|
56
|
+
const value = raw.trim();
|
|
57
|
+
if (value === "") return "";
|
|
58
|
+
if (value === "true") return true;
|
|
59
|
+
if (value === "false") return false;
|
|
60
|
+
if (value === "null") return null;
|
|
61
|
+
if (/^-?\d+(\.\d+)?$/.test(value)) return Number(value);
|
|
62
|
+
if (value.startsWith("[") && value.endsWith("]")) {
|
|
63
|
+
const inner = value.slice(1, -1).trim();
|
|
64
|
+
if (!inner) return [];
|
|
65
|
+
return splitInlineList(inner).map(parseScalar);
|
|
66
|
+
}
|
|
67
|
+
if (
|
|
68
|
+
(value.startsWith("\"") && value.endsWith("\"")) ||
|
|
69
|
+
(value.startsWith("'") && value.endsWith("'"))
|
|
70
|
+
) {
|
|
71
|
+
try {
|
|
72
|
+
return JSON.parse(value);
|
|
73
|
+
} catch {
|
|
74
|
+
return value.slice(1, -1);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return value;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function splitInlineList(value) {
|
|
81
|
+
const parts = [];
|
|
82
|
+
let current = "";
|
|
83
|
+
let quote = "";
|
|
84
|
+
for (const char of value) {
|
|
85
|
+
if ((char === "\"" || char === "'") && !quote) quote = char;
|
|
86
|
+
else if (char === quote) quote = "";
|
|
87
|
+
if (char === "," && !quote) {
|
|
88
|
+
parts.push(current.trim());
|
|
89
|
+
current = "";
|
|
90
|
+
} else {
|
|
91
|
+
current += char;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (current.trim()) parts.push(current.trim());
|
|
95
|
+
return parts;
|
|
96
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Prerequisites — MCP lab immeuble (workspace `immo-mcp`)
|
|
2
|
+
|
|
3
|
+
**Phase 0 — read only, no writes.**
|
|
4
|
+
|
|
5
|
+
Variant of [`00-prerequisites.md`](00-prerequisites.md) with fixed IDs for workspace `immo-mcp`.
|
|
6
|
+
|
|
7
|
+
## Human pre-flight (before opening the agent)
|
|
8
|
+
|
|
9
|
+
1. **GhostCrab backend** reachable (`ghostcrab_status` must respond).
|
|
10
|
+
2. **MCP `ghostcrab-personal-mcp`** enabled in Cursor — same SQLite as this lab (see below).
|
|
11
|
+
3. **Single SQLite file** — do **not** use a separate `immo-mcp.sqlite`. Cursor MCP (`.cursor/mcp.json`) starts:
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
gcp brain up --db /home/dlamotte/Documents/ghostcrab-personal-mcp/data/ghostcrab.sqlite
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Lab process data lives in workspace **`immo-mcp`** inside that file. Golden reference uses workspace **`immeuble`** in the same file.
|
|
18
|
+
|
|
19
|
+
For CLI commands outside Cursor, align explicitly:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
export GHOSTCRAB_SQLITE_PATH="/home/dlamotte/Documents/ghostcrab-personal-mcp/data/ghostcrab.sqlite"
|
|
23
|
+
# optional: gcp brain db-who → must show the same path
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
4. **Golden workspace** (phase 06 comparison only — never load into `immo-mcp`):
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
export GHOSTCRAB_SQLITE_PATH="/home/dlamotte/Documents/ghostcrab-personal-mcp/data/ghostcrab.sqlite"
|
|
30
|
+
node bin/gcp.mjs load examples/immeuble/bundle/immeuble.bundle.json \
|
|
31
|
+
--workspace immeuble --reindex all \
|
|
32
|
+
--db "$GHOSTCRAB_SQLITE_PATH"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
MCP and CLI must target the **same** `--db` / `GHOSTCRAB_SQLITE_PATH` for the whole lab.
|
|
36
|
+
|
|
37
|
+
## Two workspaces, one SQLite — comparison model
|
|
38
|
+
|
|
39
|
+
| Workspace | Role |
|
|
40
|
+
|-----------|------|
|
|
41
|
+
| **`immo-mcp`** | What GhostCrab MCP **built** from corpus (phases 2–5) |
|
|
42
|
+
| **`immeuble`** | What we **expect** — golden from `bundle/immeuble.bundle.json` (load in phase 6 only) |
|
|
43
|
+
|
|
44
|
+
Both live in **`ghostcrab.sqlite`**. Phase 6 compares `immo-mcp` (process) vs `immeuble` (reference) vs [`success-criteria.yaml`](../success-criteria.yaml). See [`06-validate-and-compare-immo-mcp.md`](06-validate-and-compare-immo-mcp.md).
|
|
45
|
+
|
|
46
|
+
Never load the bundle into `immo-mcp`.
|
|
47
|
+
|
|
48
|
+
## Run identifiers
|
|
49
|
+
|
|
50
|
+
| Field | Value |
|
|
51
|
+
|-------|-------|
|
|
52
|
+
| `workspace_id` | `immo-mcp` |
|
|
53
|
+
| `collection_id` | `immo-mcp::docs` |
|
|
54
|
+
| `ontology_id` | `immeuble::core` |
|
|
55
|
+
| `golden_workspace_id` | `immeuble` |
|
|
56
|
+
| `golden_bundle` | `examples/immeuble/bundle/immeuble.bundle.json` |
|
|
57
|
+
| `corpus` | `examples/immeuble/sources/documents/` (8 md files) |
|
|
58
|
+
| `criteria` | `examples/immeuble/success-criteria.yaml` |
|
|
59
|
+
|
|
60
|
+
## Tools
|
|
61
|
+
|
|
62
|
+
1. `ghostcrab_status`
|
|
63
|
+
2. `ghostcrab_modeling_guidance`
|
|
64
|
+
|
|
65
|
+
## Agent prompt (copy-paste)
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
Tu es un agent GhostCrab MCP en session vierge. Ta mission : reconstruire le domaine
|
|
69
|
+
syndic belge (Résidence Les Tilleuls + Les Érables) depuis le corpus brut, en suivant
|
|
70
|
+
strictement le MCP lab documenté.
|
|
71
|
+
|
|
72
|
+
## Documentation de référence (lire en premier)
|
|
73
|
+
|
|
74
|
+
1. docs/explanation/mcp-lab-context.md — contexte, phases 00→06, critères
|
|
75
|
+
2. examples/immeuble/README.md — point d'entrée opérationnel
|
|
76
|
+
3. examples/immeuble/sources/agent-prompts/prompts/00-prerequisites-immo-mcp.md — démarrage (ce fichier)
|
|
77
|
+
|
|
78
|
+
## Identifiants de cette run
|
|
79
|
+
|
|
80
|
+
| Champ | Valeur |
|
|
81
|
+
|-------|--------|
|
|
82
|
+
| workspace_id | immo-mcp |
|
|
83
|
+
| collection_id | immo-mcp::docs |
|
|
84
|
+
| ontology_id | immeuble::core |
|
|
85
|
+
| golden_workspace_id | immeuble |
|
|
86
|
+
| golden_bundle | examples/immeuble/bundle/immeuble.bundle.json |
|
|
87
|
+
| corpus | examples/immeuble/sources/documents/ (8 fichiers md) |
|
|
88
|
+
| critères | examples/immeuble/success-criteria.yaml |
|
|
89
|
+
|
|
90
|
+
## Règles absolues
|
|
91
|
+
|
|
92
|
+
- Appeler ghostcrab_status en PREMIER.
|
|
93
|
+
- Lire avant d'écrire : count → search → pack (ou graph_search pour le graphe).
|
|
94
|
+
- NE PAS charger le bundle golden dans immo-mcp — le golden (immeuble) sert
|
|
95
|
+
uniquement à comparer en phase 06.
|
|
96
|
+
- Phases 00–01 : lecture seule — aucune écriture.
|
|
97
|
+
- Avant toute écriture (phases 02–05) : produire un Model Proposal (entités, arêtes,
|
|
98
|
+
facettes, questions de compétence) et ATTENDRE ma confirmation explicite
|
|
99
|
+
(ONBOARDING_CONTRACT §9).
|
|
100
|
+
- Ingestion documentaire : CLI gcp brain document (pas streaming MCP unitaire).
|
|
101
|
+
- Outils graph/gap extended : découvrir via ghostcrab_tool_search si absents du défaut.
|
|
102
|
+
|
|
103
|
+
## Workflow — exécuter dans l'ordre
|
|
104
|
+
|
|
105
|
+
Phase 0 — examples/immeuble/sources/agent-prompts/prompts/00-prerequisites-immo-mcp.md
|
|
106
|
+
→ ghostcrab_status, ghostcrab_modeling_guidance
|
|
107
|
+
→ lire corpus/manifest.json, success-criteria.yaml, contracts/scenarios.yaml
|
|
108
|
+
|
|
109
|
+
Phase 1 — prompts/01-discovery-and-model-proposal.md
|
|
110
|
+
→ affiner le Model Proposal depuis le corpus (toujours sans écriture)
|
|
111
|
+
|
|
112
|
+
GATE : stop et présente le Model Proposal. N'écris rien tant que je n'ai pas confirmé.
|
|
113
|
+
|
|
114
|
+
Phase 2 — prompts/02-ontology-register.md (après confirmation)
|
|
115
|
+
→ gcp brain ontology compile sur ontologies/immeuble/core.yaml
|
|
116
|
+
|
|
117
|
+
Phase 3 — prompts/03-gap-rules-design.md
|
|
118
|
+
→ ghostcrab_graph_gap_rules_import (réf. training/reference gap-rules)
|
|
119
|
+
|
|
120
|
+
Phase 4 — prompts/04-document-ingest.md
|
|
121
|
+
→ gcp brain document : collection-create, ingest 8 corpus, profile, qualify
|
|
122
|
+
|
|
123
|
+
Phase 5 — prompts/05-graph-extraction.md
|
|
124
|
+
→ ghostcrab_learn (incrémental) OU document-business-extract (batch)
|
|
125
|
+
|
|
126
|
+
Phase 6 — prompts/06-validate-and-compare-immo-mcp.md
|
|
127
|
+
→ ghostcrab_graph_search, ghostcrab_graph_diagnostics vs success-criteria.yaml
|
|
128
|
+
→ comparer immo-mcp (process) vs immeuble (bundle golden), même SQLite
|
|
129
|
+
|
|
130
|
+
## Livrables attendus par phase
|
|
131
|
+
|
|
132
|
+
- Phase 0–1 : Model Proposal textuel
|
|
133
|
+
- Phase 2–5 : rapport court (ce qui a été écrit, outils utilisés, counts)
|
|
134
|
+
- Phase 6 : tableau écart vs success-criteria.yaml + recommandations
|
|
135
|
+
|
|
136
|
+
## Commence maintenant
|
|
137
|
+
|
|
138
|
+
1. ghostcrab_status
|
|
139
|
+
2. Résume mcp-lab-context.md en 5 lignes
|
|
140
|
+
3. Lis corpus/manifest.json et success-criteria.yaml
|
|
141
|
+
4. Propose un premier Model Proposal (sans écrire)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Required reading
|
|
145
|
+
|
|
146
|
+
- `corpus/manifest.json`
|
|
147
|
+
- `success-criteria.yaml`
|
|
148
|
+
- `../contracts/scenarios.yaml`
|
|
149
|
+
|
|
150
|
+
## Deliverable
|
|
151
|
+
|
|
152
|
+
Model Proposal textuel (entités, arêtes, facettes, competency questions couvertes).
|
|
153
|
+
|
|
154
|
+
## Gate
|
|
155
|
+
|
|
156
|
+
**Confirmation humaine requise** — reply **« je confirme »** (ou corrections) before `01-discovery-and-model-proposal.md` refinement and before any write phases (ONBOARDING_CONTRACT §9).
|
|
157
|
+
|
|
158
|
+
## Docs if blocked
|
|
159
|
+
|
|
160
|
+
- [`01-reference-to-graph`](../../../docs/explanation/01-reference-to-graph.md)
|
|
161
|
+
- [`mcp-lab-context`](../../../docs/explanation/mcp-lab-context.md)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Prerequisites — MCP lab immeuble
|
|
2
|
+
|
|
3
|
+
**Phase 0 — read only, no writes.**
|
|
4
|
+
|
|
5
|
+
## Tools
|
|
6
|
+
|
|
7
|
+
1. `ghostcrab_status`
|
|
8
|
+
2. `ghostcrab_modeling_guidance`
|
|
9
|
+
|
|
10
|
+
## Agent prompt (copy-paste)
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
Je veux reconstruire le domaine syndic belge "Résidence Les Tilleuls + Les Érables"
|
|
14
|
+
depuis le corpus brut dans examples/immeuble/sources/documents/manifest.json.
|
|
15
|
+
Workspace cible : immeuble.
|
|
16
|
+
Référence de validation : examples/immeuble/bundle/immeuble.bundle.json (bundle golden immeuble).
|
|
17
|
+
|
|
18
|
+
Ne charge pas le bundle golden dans le workspace LLM — compare seulement à la fin.
|
|
19
|
+
Propose un Model Proposal (entités, relations, facettes documentaires) avant toute écriture.
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Required reading
|
|
23
|
+
|
|
24
|
+
- `manifest.json`
|
|
25
|
+
- `success-criteria.yaml`
|
|
26
|
+
- `../contracts/scenarios.yaml`
|
|
27
|
+
- `workspace.json`
|
|
28
|
+
|
|
29
|
+
## Deliverable
|
|
30
|
+
|
|
31
|
+
Model Proposal textuel (entités, arêtes, facettes, competency questions couvertes).
|
|
32
|
+
|
|
33
|
+
## Gate
|
|
34
|
+
|
|
35
|
+
**Confirmation humaine requise** avant de passer à `01-discovery-and-model-proposal.md` puis aux phases d'écriture (ONBOARDING_CONTRACT §9).
|
|
36
|
+
|
|
37
|
+
## Next
|
|
38
|
+
|
|
39
|
+
→ [`01-discovery-and-model-proposal.md`](01-discovery-and-model-proposal.md)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Discovery and model proposal
|
|
2
|
+
|
|
3
|
+
**Phase 1 — read corpus, propose model (no writes yet).**
|
|
4
|
+
|
|
5
|
+
## Tools
|
|
6
|
+
|
|
7
|
+
- File reads: `corpus/*.md`, `corpus/manifest.json`
|
|
8
|
+
- Optional: `ghostcrab_tool_search` if you need specialized tools
|
|
9
|
+
|
|
10
|
+
## Agent prompt
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
Lis les 8 fichiers listés dans examples/immeuble/sources/documents/manifest.json.
|
|
14
|
+
|
|
15
|
+
Produis une table avec :
|
|
16
|
+
1. Entity types (building, block, unit, person, household, lease_contract, cellar, parking_space, …)
|
|
17
|
+
2. Edge types (contains, owns, occupies, leases, assigned_cellar, assigned_garage, …)
|
|
18
|
+
3. Facet dimensions documentaires (source.document_type, domain.building, domain.unit, domain.role, …)
|
|
19
|
+
4. Mapping doc_id → document_type → entités/relations attendues
|
|
20
|
+
5. Competency questions couvertes (réf. examples/immeuble/contracts/scenarios.yaml)
|
|
21
|
+
|
|
22
|
+
Compare à ../checklists/ontology-checklist.md. Si tu t'écartes, explique pourquoi.
|
|
23
|
+
Ne crée rien dans GhostCrab tant que le Model Proposal n'est pas validé.
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Deliverable
|
|
27
|
+
|
|
28
|
+
| Column | Content |
|
|
29
|
+
|--------|---------|
|
|
30
|
+
| Entity types | List with brief definition |
|
|
31
|
+
| Edge types | List with source/target |
|
|
32
|
+
| Facet dimensions | Namespace.dimension + value examples |
|
|
33
|
+
| Doc mapping | 8 rows from manifest |
|
|
34
|
+
| Scenarios | Which scenario IDs each doc supports |
|
|
35
|
+
|
|
36
|
+
## Gate
|
|
37
|
+
|
|
38
|
+
Human validation of Model Proposal before `02-ontology-register.md`.
|
|
39
|
+
|
|
40
|
+
## Next
|
|
41
|
+
|
|
42
|
+
→ [`02-ontology-register.md`](02-ontology-register.md)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Ontology register
|
|
2
|
+
|
|
3
|
+
**Phase 2 — create workspace and register ontology.**
|
|
4
|
+
|
|
5
|
+
## Tools
|
|
6
|
+
|
|
7
|
+
- `ghostcrab_workspace_create`
|
|
8
|
+
- `ghostcrab_schema_register` or `ghostcrab_schema_inspect` / `ghostcrab_schema_list`
|
|
9
|
+
- CLI (documented): `gcp brain ontology compile …`
|
|
10
|
+
|
|
11
|
+
## Agent prompt
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
Crée le workspace immeuble (domain_profile: syndic).
|
|
15
|
+
Enregistre l'ontology immeuble::core alignée sur le Model Proposal validé :
|
|
16
|
+
|
|
17
|
+
Option A — LinkML :
|
|
18
|
+
gcp brain ontology compile \
|
|
19
|
+
--workspace-id immeuble \
|
|
20
|
+
--ontology-id immeuble::core \
|
|
21
|
+
--input ontologies/immeuble/core.yaml \
|
|
22
|
+
--profile syndic \
|
|
23
|
+
--import-db --force
|
|
24
|
+
|
|
25
|
+
Option B — MCP schema :
|
|
26
|
+
ghostcrab_schema_register avec facet dimensions du Model Proposal
|
|
27
|
+
|
|
28
|
+
Vérifie avec ghostcrab_schema_list / ghostcrab_schema_inspect sur immeuble.
|
|
29
|
+
Ne charge pas examples/immeuble/bundle/immeuble.bundle.json dans ce workspace.
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Reference (read-only)
|
|
33
|
+
|
|
34
|
+
Canonical LinkML: `ontologies/immeuble/core.yaml`
|
|
35
|
+
Checklist: `reference/ontology-checklist.md`
|
|
36
|
+
|
|
37
|
+
## Deliverable
|
|
38
|
+
|
|
39
|
+
- Workspace `immeuble` exists
|
|
40
|
+
- Ontology `immeuble::core` visible in workspace
|
|
41
|
+
|
|
42
|
+
## Next
|
|
43
|
+
|
|
44
|
+
→ [`03-gap-rules-design.md`](03-gap-rules-design.md)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Gap rules design
|
|
2
|
+
|
|
3
|
+
**Phase 3 — design and import closed-world gap rules.**
|
|
4
|
+
|
|
5
|
+
## Tools
|
|
6
|
+
|
|
7
|
+
- `ghostcrab_graph_gap_rules_import`
|
|
8
|
+
- `ghostcrab_graph_gap_rules`
|
|
9
|
+
- Optional: `ghostcrab_graph_diagnostics` (smoke on empty graph)
|
|
10
|
+
|
|
11
|
+
## Agent prompt
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
Conçois les graph_gap_rules closed-world pour workspace immeuble, ontology immeuble::core.
|
|
15
|
+
|
|
16
|
+
Niveau 1 — Patrimoine (cf. examples/immeuble/gap-rules/L0-patrimoine.json) :
|
|
17
|
+
- unit-one-cellar, unit-in-building, garage-at-most-one-unit
|
|
18
|
+
|
|
19
|
+
Niveau 2 — Syndic filtré (cf. `../gap-rules/L2-syndic-filtered.json`) :
|
|
20
|
+
- unit-has-owner, occupied-unit-has-occupant, tenant-occupied-has-lease
|
|
21
|
+
- entity_filter sur usage_status (exclure vacant / vacant_works)
|
|
22
|
+
|
|
23
|
+
Importe avec replace:true via ghostcrab_graph_gap_rules_import.
|
|
24
|
+
Liste les rules actives via ghostcrab_graph_gap_rules.
|
|
25
|
+
Explique chaque rule_id en langage métier (cf. `../gap-rules/closed-world-contract.md`).
|
|
26
|
+
|
|
27
|
+
Pédagogie optionnelle : importer d'abord L1-syndic-naive.json, diagnostiquer le FP sur
|
|
28
|
+
Érables Appartement A4 (vacant_works), puis passer à L2.
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Reference files
|
|
32
|
+
|
|
33
|
+
- `../gap-rules/demo.json` — patrimoine demo
|
|
34
|
+
- `../gap-rules/syndic.json` — syndic L2 for immeuble
|
|
35
|
+
- `../gap-rules/` — curriculum L0–L3
|
|
36
|
+
- `../checklists/gap-rules-checklist.md`
|
|
37
|
+
|
|
38
|
+
## Deliverable
|
|
39
|
+
|
|
40
|
+
JSON gap-rules imported; list of active rule_ids with business labels.
|
|
41
|
+
|
|
42
|
+
## Next
|
|
43
|
+
|
|
44
|
+
→ [`04-document-ingest.md`](04-document-ingest.md)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Document ingest
|
|
2
|
+
|
|
3
|
+
**Phase 4 — enqueue, profile, and qualify source documents.**
|
|
4
|
+
|
|
5
|
+
## Tools
|
|
6
|
+
|
|
7
|
+
MCP: `ghostcrab_workspace_create` (if needed)
|
|
8
|
+
CLI: `gcp brain document …` (profile + qualify pipeline)
|
|
9
|
+
|
|
10
|
+
## Agent prompt
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
Pour chaque entrée de examples/immeuble/sources/documents/ :
|
|
14
|
+
|
|
15
|
+
1. collection-create --workspace-id immeuble --collection-id immeuble::docs
|
|
16
|
+
2. ontology-attach --ontology-id immeuble::core --role taxonomy
|
|
17
|
+
3. document-profile-enqueue --content-file examples/immeuble/sources/documents/<filename> \
|
|
18
|
+
--doc-id <doc_id> --language fr
|
|
19
|
+
4. document-profile-worker --limit <n>
|
|
20
|
+
5. qualification-vocab-list
|
|
21
|
+
6. document-qualify --taxonomies immeuble::core \
|
|
22
|
+
--facets source.document_type,domain.building,domain.unit,domain.role,domain.scenario,finance.payment_status
|
|
23
|
+
|
|
24
|
+
Commence par 1 document si itération prompts (--limit-docs 1).
|
|
25
|
+
Vérifie les qualifications par doc_id avant de continuer.
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Mock CI reference
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
node examples/immeuble/scripts/run-immeuble-import.mjs --apply --skip-provenance-validation --skip-preflight
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Deliverable
|
|
35
|
+
|
|
36
|
+
8 documents profiled and qualified in `immeuble::docs`.
|
|
37
|
+
|
|
38
|
+
## Next
|
|
39
|
+
|
|
40
|
+
→ [`05-graph-extraction.md`](05-graph-extraction.md)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Graph extraction
|
|
2
|
+
|
|
3
|
+
**Phase 5 — extract business entities and relations from qualified documents.**
|
|
4
|
+
|
|
5
|
+
## Tools
|
|
6
|
+
|
|
7
|
+
- `ghostcrab_remember` / `ghostcrab_upsert`
|
|
8
|
+
- `ghostcrab_graph_search`
|
|
9
|
+
- Reindex: `gcp load` partial or workspace reindex CLI
|
|
10
|
+
|
|
11
|
+
## Agent prompt
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
À partir des documents qualifiés dans `immeuble`, extrais le graphe métier syndic :
|
|
15
|
+
|
|
16
|
+
Structure :
|
|
17
|
+
- 2 immeubles (Tilleuls, Érables), 13 lots, personnes, ménages
|
|
18
|
+
- 13 caves, garages sélectifs, jardins privatifs RDC
|
|
19
|
+
- 5 contrats de bail, 3 écritures CODA
|
|
20
|
+
|
|
21
|
+
Relations minimales :
|
|
22
|
+
contains, owns, occupies, household_member, leases, rented_to,
|
|
23
|
+
assigned_cellar, assigned_garage, uses_exclusive, matched_to
|
|
24
|
+
|
|
25
|
+
Utilise ghostcrab_remember / ghostcrab_upsert ou l'extraction LLM documentée
|
|
26
|
+
dans le flux d'ingestion `run-immeuble-import.mjs`.
|
|
27
|
+
Reindex le graphe après écriture.
|
|
28
|
+
|
|
29
|
+
Vérifie :
|
|
30
|
+
ghostcrab_graph_search query "appartement" → ≥ 13 unités
|
|
31
|
+
ghostcrab_graph_search query "Dupont" → résultats pertinents
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Success thresholds
|
|
35
|
+
|
|
36
|
+
See `success-criteria.yaml` → `entity_counts`, `relation_edges`.
|
|
37
|
+
|
|
38
|
+
## Deliverable
|
|
39
|
+
|
|
40
|
+
Populated `graph_entity` for workspace `immeuble`; counts near success criteria.
|
|
41
|
+
|
|
42
|
+
## Next
|
|
43
|
+
|
|
44
|
+
→ [`06-validate-and-compare.md`](06-validate-and-compare.md)
|