============================================================
LIMBFORGE — LIVE 3D ENTRYPOINT AUDIT
============================================================
UTC: 2026-08-05T03:06:40+00:00
------------------------------------------------------------
1. VERIFY LIVE MODULE REMAINED UNCHANGED
------------------------------------------------------------
Live index: /home/shire3d/ARMOR/agents/apps/limbforge/dist/shire-module/shire-index.html
Live SHA: 6a02ce7b9a88dab19b762032cf89d56d0eb8c62ec8ddb2119dcb28ddf60e457b
shire-limbforge-workspace.service active
shire-limbforge-canvas-gateway.service active
http://127.0.0.1:8787/health HTTP 200
http://127.0.0.1:8786/health HTTP 200
http://127.0.0.1:8787/agents/limbforge/ HTTP 200
Temporary staged directories still present:
------------------------------------------------------------
2. SOURCE SHIRE ENTRYPOINT
------------------------------------------------------------
1
2
3
4
5
9
10 SHiRE limbforge
11
12
13
14
18
19
------------------------------------------------------------
3. DEDICATED SHIRE VITE CONFIGURATION
------------------------------------------------------------
1 import path from 'node:path';
2 import { fileURLToPath } from 'node:url';
3 import react from '@vitejs/plugin-react';
4 import { defineConfig } from 'vite';
5
6 const root = path.dirname(fileURLToPath(import.meta.url));
7
8 export default defineConfig({
9 base: '/agents/limbforge/',
10 plugins: [react()],
11 resolve: {
12 alias: [
13 {
14 find: '@/api/base44Client',
15 replacement: path.resolve(
16 root,
17 'src/shire/localBase44Client.js'
18 ),
19 },
20 {
21 find: '@',
22 replacement: path.resolve(root, 'src'),
23 },
24 ],
25 },
26 build: {
27 outDir: 'dist/shire-module',
28 emptyOutDir: true,
29 sourcemap: false,
30 rollupOptions: {
31 input: path.resolve(root, 'shire-index.html'),
32 },
33 },
34 });
------------------------------------------------------------
4. SHIRE-SPECIFIC SOURCE FILES
------------------------------------------------------------
/home/shire3d/ARMOR/agents/apps/limbforge/src/shire/ShireApp.jsx
/home/shire3d/ARMOR/agents/apps/limbforge/src/shire/localBase44Client.js
/home/shire3d/ARMOR/agents/apps/limbforge/src/shire/shire.css
============================================================
FILE: /home/shire3d/ARMOR/agents/apps/limbforge/src/shire/ShireApp.jsx
============================================================
1 import React from 'react';
2 import {
3 BrowserRouter,
4 Navigate,
5 Route,
6 Routes,
7 } from 'react-router-dom';
8 import { QueryClientProvider } from '@tanstack/react-query';
9
10 import { queryClientInstance } from '@/lib/query-client';
11 import { Toaster } from '@/components/ui/toaster';
12 import ScrollToTop from '@/components/ScrollToTop';
13 import WorkshopLayout from '@/components/workshop/WorkshopLayout';
14
15 import Dashboard from '@/pages/Dashboard';
16 import Customers from '@/pages/Customers';
17 import CustomerDetail from '@/pages/CustomerDetail';
18 import Projects from '@/pages/Projects';
19 import ProjectDetail from '@/pages/ProjectDetail';
20 import Components from '@/pages/Components';
21 import ComponentDimensions from '@/pages/ComponentDimensions';
22 import NewCover from '@/pages/NewCover';
23 import Measurements from '@/pages/Measurements';
24 import MeasurementSession from '@/pages/MeasurementSession';
25 import OssiguardLibrary from '@/pages/OssiguardLibrary';
26 import OssiguardDetail from '@/pages/OssiguardDetail';
27 import OssiguardWizard from '@/pages/OssiguardWizard';
28 import DesignForge from '@/pages/DesignForge';
29 import Validation from '@/pages/Validation';
30 import Manufacturing from '@/pages/Manufacturing';
31 import ManufacturingJobDetail from '@/pages/ManufacturingJobDetail';
32 import CompletedCovers from '@/pages/CompletedCovers';
33 import CompletedCoverDetail from '@/pages/CompletedCoverDetail';
34 import Settings from '@/pages/Settings';
35
36 import TakeMeasurements from '@/pages/TakeMeasurements';
37 export default function ShireApp() {
38 return (
39
40
41
42
43
44 }>
45 } />
46 } />
47 } />
48 } />
49 } />
50 } />
51 } />
52 } />
53 } />
54 }
57 />
58 } />
59 }
62 />
63 } />
64 }
67 />
68 }
71 />
72 }
75 />
76 } />
77 } />
78 }
81 />
82 } />
83 } />
84 }
87 />
88 } />
89 }
92 />
93 } />
94 } />
95
96
97
98
99
100
101 );
102 }
============================================================
FILE: /home/shire3d/ARMOR/agents/apps/limbforge/src/shire/localBase44Client.js
============================================================
1 const API_ROOT = '/api/v1';
2
3 async function request(path, options = {}) {
4 const response = await fetch(`${API_ROOT}${path}`, {
5 cache: 'no-store',
6 ...options,
7 headers: {
8 ...(options.body instanceof FormData
9 ? {}
10 : { 'Content-Type': 'application/json' }),
11 ...(options.headers || {}),
12 },
13 });
14
15 let payload = null;
16
17 try {
18 payload = await response.json();
19 } catch (_) {
20 payload = null;
21 }
22
23 if (!response.ok) {
24 const error = new Error(
25 payload?.error || `Local SHiRE request failed (${response.status})`
26 );
27
28 error.status = response.status;
29 error.data = payload;
30 throw error;
31 }
32
33 return payload;
34 }
35
36 function collection(name) {
37 return {
38 async list(sort = '-updated_date', limit = 500) {
39 const params = new URLSearchParams({
40 sort,
41 limit: String(limit),
42 });
43
44 const result = await request(
45 `/collections/${encodeURIComponent(name)}?${params}`
46 );
47
48 return result.records || [];
49 },
50
51 async filter(query = {}, sort = '-updated_date', limit = 500) {
52 const result = await request(
53 `/collections/${encodeURIComponent(name)}/filter`,
54 {
55 method: 'POST',
56 body: JSON.stringify({ query, sort, limit }),
57 }
58 );
59
60 return result.records || [];
61 },
62
63 async get(id) {
64 const result = await request(
65 `/collections/${encodeURIComponent(name)}/${encodeURIComponent(id)}`
66 );
67
68 return result.record;
69 },
70
71 async create(data) {
72 const result = await request(
73 `/collections/${encodeURIComponent(name)}`,
74 {
75 method: 'POST',
76 body: JSON.stringify(data || {}),
77 }
78 );
79
80 return result.record;
81 },
82
83 async update(id, data) {
84 const result = await request(
85 `/collections/${encodeURIComponent(name)}/${encodeURIComponent(id)}`,
86 {
87 method: 'PATCH',
88 body: JSON.stringify(data || {}),
89 }
90 );
91
92 return result.record;
93 },
94
95 async delete(id) {
96 const result = await request(
97 `/collections/${encodeURIComponent(name)}/${encodeURIComponent(id)}`,
98 {
99 method: 'DELETE',
100 }
101 );
102
103 return result;
104 },
105
106 async bulkCreate(records) {
107 const result = await request(
108 `/collections/${encodeURIComponent(name)}/bulk-create`,
109 {
110 method: 'POST',
111 body: JSON.stringify({ records: records || [] }),
112 }
113 );
114
115 return result.records || [];
116 },
117
118 async bulkUpdate(records) {
119 const output = [];
120
121 for (const record of records || []) {
122 const id = record.id || record.uuid;
123
124 if (!id) {
125 throw new Error(`bulkUpdate record in ${name} has no id or uuid`);
126 }
127
128 output.push(await this.update(id, record));
129 }
130
131 return output;
132 },
133 };
134 }
135
136 const entities = new Proxy(
137 {},
138 {
139 get(_target, property) {
140 return collection(String(property));
141 },
142 }
143 );
144
145 const localUser = {
146 id: 'shire-local-owner',
147 email: '',
148 full_name: 'Ray',
149 role: 'owner_admin',
150 roles: ['owner_admin', 'admin', 'builder'],
151 local_only: true,
152 };
153
154 async function uploadFile({ file, destination = 'Uploads' }) {
155 if (!(file instanceof Blob)) {
156 throw new Error('A valid file is required.');
157 }
158
159 const result = await request('/files', {
160 method: 'POST',
161 body: file,
162 headers: {
163 'Content-Type': file.type || 'application/octet-stream',
164 'X-SHiRE-Filename': file.name || 'upload.bin',
165 'X-SHiRE-Destination': destination,
166 },
167 });
168
169 return {
170 file_url: result.file.location,
171 ...result.file,
172 };
173 }
174
175 function unavailable(feature) {
176 return async () => {
177 throw new Error(
178 `${feature} is not connected to a native SHiRE engine yet.`
179 );
180 };
181 }
182
183 export const base44 = {
184 entities,
185
186 auth: {
187 me: async () => localUser,
188 isAuthenticated: () => true,
189 logout: () => {},
190 redirectToLogin: () => {},
191 loginViaEmailPassword: async () => localUser,
192 loginWithProvider: async () => localUser,
193 register: async () => localUser,
194 verifyOtp: async () => ({ access_token: 'shire-local-session' }),
195 resendOtp: async () => ({ ok: true }),
196 resetPassword: async () => ({ ok: true }),
197 resetPasswordRequest: async () => ({ ok: true }),
198 setToken: () => {},
199 updateMe: async changes => ({ ...localUser, ...(changes || {}) }),
200 },
201
202 functions: {
203 invoke: unavailable('Local server function'),
204 },
205
206 integrations: {
207 Core: {
208 UploadFile: uploadFile,
209 GenerateImage: unavailable('Native image generation'),
210 InvokeLLM: unavailable('Native SHiRE reasoning'),
211 createAdaptationPreview: unavailable(
212 'Native CoverCanvas adaptation preview'
213 ),
214 },
215 },
216 };
217
218 export default base44;
------------------------------------------------------------
5. ROUTE AND IMPORT OWNERSHIP
------------------------------------------------------------
/home/shire3d/ARMOR/agents/apps/limbforge/src/shire/ShireApp.jsx:23:import Measurements from '@/pages/Measurements';
/home/shire3d/ARMOR/agents/apps/limbforge/src/shire/ShireApp.jsx:24:import MeasurementSession from '@/pages/MeasurementSession';
/home/shire3d/ARMOR/agents/apps/limbforge/src/shire/ShireApp.jsx:36:import TakeMeasurements from '@/pages/TakeMeasurements';
/home/shire3d/ARMOR/agents/apps/limbforge/src/shire/ShireApp.jsx:52: } />
/home/shire3d/ARMOR/agents/apps/limbforge/src/shire/ShireApp.jsx:53: } />
/home/shire3d/ARMOR/agents/apps/limbforge/src/shire/ShireApp.jsx:55: path="/measurements/:uuid"
/home/shire3d/ARMOR/agents/apps/limbforge/src/shire/ShireApp.jsx:56: element={ }
/home/shire3d/ARMOR/agents/apps/limbforge/src/App.jsx:22:import Measurements from '@/pages/Measurements';
/home/shire3d/ARMOR/agents/apps/limbforge/src/App.jsx:23:import MeasurementSession from '@/pages/MeasurementSession';
/home/shire3d/ARMOR/agents/apps/limbforge/src/App.jsx:28:import ViewportV2Test from '@/pages/ViewportV2Test';
/home/shire3d/ARMOR/agents/apps/limbforge/src/App.jsx:69:import TakeMeasurements from '@/pages/TakeMeasurements';
/home/shire3d/ARMOR/agents/apps/limbforge/src/App.jsx:96: } />
/home/shire3d/ARMOR/agents/apps/limbforge/src/App.jsx:125: } />
/home/shire3d/ARMOR/agents/apps/limbforge/src/App.jsx:126: } />
/home/shire3d/ARMOR/agents/apps/limbforge/src/App.jsx:127: } />
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/DesignYourCover.jsx:15: { id: 'measure', title: 'Measurements', icon: Ruler },
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/DesignYourCover.jsx:30: measurements: { coverLength: '', calfWidth: '', ankleWidth: '', footLength: '', footWidth: '' },
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/DesignYourCover.jsx:72: Manufacturing has not started. A SHiRE team member will contact you via {form.contact_method.toLowerCase()} to verify measurements and confirm your design. No payment has been taken.
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/DesignYourCover.jsx:176: Enter what you can — estimates are fine. We'll verify everything before manufacturing. All measurements in millimetres.
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/DesignYourCover.jsx:184: set({ measurements: { ...form.measurements, [k]: v } })} />
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/DesignYourCover.jsx:236:
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/DesignYourCover.jsx:245: I understand this is a cosmetic, non-load-bearing cover; workshop review is required; measurements may need verification; the final design may require prosthetist approval; and manufacturing has not started.
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/MeasurementSession.jsx:4:import MeasurementGuide from '@/components/measurements/MeasurementGuide';
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/MeasurementSession.jsx:5:import MeasurementEntry from '@/components/measurements/MeasurementEntry';
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/MeasurementSession.jsx:17:export default function MeasurementSession() {
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/MeasurementSession.jsx:69: const pause = async () => { await measurementService.pause(session); navigate('/measurements'); };
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/MeasurementSession.jsx:82: Back
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/TakeMeasurements.jsx:97:export default function TakeMeasurements() {
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/TakeMeasurements.jsx:493: `/measurements/${sessionUuid}`
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/TakeMeasurements.jsx:497: Begin measurements
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/Orders.jsx:11:const FILTERS = ['All', 'Awaiting measurements', 'Awaiting NDIS/plan-manager approval', 'Ready for CAD', 'In manufacturing', 'Awaiting inspection', 'Ready to ship', 'Shipped', 'Delivered', 'Complete', 'Cancelled', 'Archived'];
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/ProjectDetail.jsx:27:const SECTIONS = [['customer','Customer'],['intake','Intake'],['measurements','Measurements'],['components','Components'],['ossiguard','Ossiguard'],['sensitive','Sensitive Zones'],['design','Design Brief'],['customDesign','Custom Design'],['validation','Validation'],['quote','Quote'],['order','Order'],['manufacturing','Manufacturing'],['covers','Completed Covers'],['audit','Audit']];
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/ProjectDetail.jsx:56: adapters.database.filter('MeasurementSession', { project_uuid: projectId }),
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/ProjectDetail.jsx:100: checks.push(['Measurements recorded', data.values.length > 0, 'warning']);
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/ProjectDetail.jsx:123: return <> Open Design Forge Open 3D Workshop Open Customer{sessions[0] && Open Measurements} Prepare Quote {orders[0] && View Order}} />{project.status} {geometry && {geometry.geometryStatus} }{quotes[0] && Quote: {quotes[0].approval_status} }{orders[0] && Order: {orders[0].production_status} }{covers[0] && Cover: {covers[0].cover_reference} }
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/ProjectDetail.jsx:131: {section === 'measurements' && Measurement Sessions ({sessions.length}) · {values.length} values {sessions.length ? {sessions.map((s) =>
{s.workflow} {s.measured_date} · {s.measured_by}
{s.status} Open session
)}
: No measurement sessions. {sessions[0] ? '' : Go to Measurement Studio}.
} }
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/NewCover.jsx:6:export default function NewCover() { const [created,setCreated]=useState(null); return <> {created?PROJECT CREATED
{created.project_id} Revision {created.revision} · {created.status}
Open projectssetCreated(null)}>Create another
:
}> }
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/Workshop3D.jsx:19:import MeasurementStudio3D from '@/components/workshop3d/workflows/MeasurementStudio3D';
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/Workshop3D.jsx:54:export default function Workshop3D() {
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/Workshop3D.jsx:70: const [display, setDisplay] = useState({ measurements: true, sensitive: true, keepOut: true, access: true, cover: true, movement: true, logo: true });
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/Workshop3D.jsx:84: // Bind the sole open session so guided 3D measurements can still be saved.
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/Workshop3D.jsx:307: return setActiveWorkflow(null)} />;
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/Workshop3D.jsx:336: View All Measurements
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/Workshop3D.jsx:342: const sessionStatus = session?.status === 'Complete' ? 'Session Complete' : session ? 'Live Capture' : 'Missing Measurements';
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/Workshop3D.jsx:346:
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/Workshop3D.jsx:425: onReset={() => { setViewPreset('reset'); setDisplay(d => ({ ...d, measurements: true })); setCompatibility(false); }}
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/Workshop3D.jsx:516: onDisableLayers={() => setDisplay({ measurements: false, access: false, keepOut: false, sensitive: false, movement: false, cover: false, logo: false })}
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/Workshop3D.jsx:517: onReloadLayers={() => setDisplay({ measurements: true, access: true, keepOut: true, sensitive: true, movement: true, cover: true, logo: true })}
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/builder/BuilderProjectDetail.jsx:11: { key: 'measurements', label: 'Measurements', icon: Ruler, perm: 'measurements.record', entity: 'MeasurementSession', filter: 'project_uuid' },
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/OrderDetail.jsx:16:const PRODUCTION = ['Awaiting measurements','Ready for design','Awaiting approval','Ready for CAD','CAD in progress','Test print','Fit review','Final print','Post-processing','Inspection','Ready to ship','Shipped','Delivered','Complete'];
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/Dashboard.jsx:7:export default function Dashboard() { const [data,setData]=useState(null); useEffect(()=>{dashboardService.summary().then(setData)},[]); if(!data)return ; const cards=[['Active cover projects',data.active,'/projects?active=true'],['Measurements awaiting completion',data.measurements,'/measurements?status=open'],['Awaiting customer clarification',data.clarification,'/projects?status=Awaiting+customer+clarification'],['Designs awaiting selection',data.selection,'/projects?status=Designs+awaiting+selection'],['Awaiting workshop review',data.review,'/projects?status=Awaiting+workshop+review'],['Quotes awaiting acceptance',0,'/not-implemented?feature=Quotes'],['Orders awaiting payment',0,'/not-implemented?feature=Orders'],['NDIS / plan approval',0,'/not-implemented?feature=Orders'],['Covers awaiting print',0,'/not-implemented?feature=Manufacturing'],['Currently printing',0,'/not-implemented?feature=Manufacturing'],['Awaiting final inspection',0,'/not-implemented?feature=Manufacturing'],['Ready to ship',0,'/not-implemented?feature=Shipping'],['Recently completed',data.completed.length,'/projects?status=Complete'],['Returning customers',data.returning,'/customers?returning=true']]; return <>{cards.map(c=>)}
> }
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/Measurements.jsx:5:import SessionCard from '@/components/measurements/SessionCard';
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/Measurements.jsx:6:import StartWorkflowDialog from '@/components/measurements/StartWorkflowDialog';
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/Measurements.jsx:9:export default function Measurements() { const [sessions,setSessions]=useState([]); const [projects,setProjects]=useState([]); const [starting,setStarting]=useState(false); useEffect(()=>{Promise.all([measurementService.sessions(),projectService.list()]).then(([s,p])=>{setSessions(s);setProjects(p)})},[]); return <>setStarting(true)}> Start workflow}/> {starting&&setStarting(false)} />}{sessions.map(s=>p.uuid===s.project_uuid)}/>)}
> }
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/Customers.jsx:13:const FILTERS = ['All', 'New customers', 'Returning customers', 'Active projects', 'Awaiting measurements', 'Awaiting quote', 'Current orders', 'Completed customers', 'Archived'];
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/Customers.jsx:39: else if (filter === 'Awaiting measurements') list = list.filter((c) => projects.some((p) => p.customer_uuid === c.uuid && p.status === 'Awaiting measurements'));
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/CustomerDetail.jsx:21:const TABS = [['overview','Overview'],['limbs','Limb Profiles'],['prostheses','Prostheses & Components'],['measurements','Measurements'],['projects','Projects'],['quotes','Quotes'],['orders','Orders'],['covers','Completed Covers'],['history','History']];
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/CustomerDetail.jsx:34: adapters.database.filter('MeasurementSession', { customer_uuid: uuid }),
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/CustomerDetail.jsx:56: return <> setMode('edit')}> Edit Customer Start New Cover setMode('limb')}>Add Limb Profile setMode('prosthesis')}>Add Prosthesis Request Measurements Prepare Quote } />{customer.record_state === 'archived' ? 'Archived' : 'Active'} {returning && Returning customer }
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/CustomerDetail.jsx:70: {tab === 'measurements' && Measurement Sessions ({sessions.length}) {sessions.length ? {sessions.map((s) =>
{s.workflow} {s.measured_date} · {s.measured_by}
{s.status} {s.progress_percent || 0}%
)}
: No measurement sessions recorded.
} }
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/ViewportV2Test.jsx:20:export default function ViewportV2Test() {
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/ViewportV2Test.jsx:61: const created = await base44.entities.MeasurementSession.create({
/home/shire3d/ARMOR/agents/apps/limbforge/src/pages/portal/CustomerPortal.jsx:12: 'Awaiting measurements': 'Getting your measurements',
------------------------------------------------------------
6. STATIC IMPORT GRAPH FROM THE SHIRE ENTRYPOINT
------------------------------------------------------------
HTML module reference: /src/shire-main.jsx
Resolved entrypoint: /home/shire3d/ARMOR/agents/apps/limbforge/src/shire-main.jsx
Reachable local source files: 144
WORKSHOP3D_REACHABLE=NO
REACHABLE FILES CONTAINING 3D OR MEASUREMENT FEATURES
src/components/viewportV2/BabylonViewportV2.jsx :: BabylonViewport
src/components/workshop/navItems.js :: Measurement Studio
src/pages/DesignForge.jsx :: BabylonViewport
src/pages/Measurements.jsx :: Measurement Studio
src/pages/ProjectDetail.jsx :: BabylonViewport, Measurement Studio
src/services/measurementGeometryService.js :: saveStationMeasurement
ALL REACHABLE PAGE FILES
src/pages/CompletedCoverDetail.jsx
src/pages/CompletedCovers.jsx
src/pages/ComponentDimensions.jsx
src/pages/Components.jsx
src/pages/CustomerDetail.jsx
src/pages/Customers.jsx
src/pages/Dashboard.jsx
src/pages/DesignForge.jsx
src/pages/Manufacturing.jsx
src/pages/ManufacturingJobDetail.jsx
src/pages/MeasurementSession.jsx
src/pages/Measurements.jsx
src/pages/NewCover.jsx
src/pages/OssiguardDetail.jsx
src/pages/OssiguardLibrary.jsx
src/pages/OssiguardWizard.jsx
src/pages/ProjectDetail.jsx
src/pages/Projects.jsx
src/pages/Settings.jsx
src/pages/TakeMeasurements.jsx
src/pages/Validation.jsx
------------------------------------------------------------
7. IDENTIFY THE LIVE BUNDLE'S FEATURE STRINGS
------------------------------------------------------------
Live JavaScript: /home/shire3d/ARMOR/agents/apps/limbforge/dist/shire-module/assets/shire-index-C4QDmV6J.js
Bundle SHA: b6fd6ae0e2302711563f6baea448939853a18ce769aa3c499fee8b414d135b97
ABSENT: Bound sole open measurement session
ABSENT: No active measurement session
ABSENT: Guided 3D Measurement
ABSENT: Save & Next
PRESENT: Measurement Studio
ABSENT: Measurement location diagram
ABSENT: Dedicated diagram not yet implemented
ABSENT: Select a component from the project tree
ABSENT: Missing Measurements
------------------------------------------------------------
8. SOURCE FILES THAT CAN SAVE A MEASUREMENT
------------------------------------------------------------
=== src/components/workshop3d/ContextInspectorV2.jsx ===
4:import { saveStationMeasurement, GEOMETRY_STATUS, STATUS_TONE } from '@/services/measurementGeometryService';
85: await saveStationMeasurement({
106: await saveStationMeasurement({ sessionUuid: sessionId, componentUuid: componentUuid || 'generic', station: { station_name: name, notes: 'Not applicable', shape_classification: 'Not applicable' } });
145: Save & Continue
=== src/components/workshop3d/workflows/MeasurementStudio3D.jsx ===
74: const saved = await measurementService.save(session, current, { value: Number(value), entered_unit: enteredUnit, confidence, notes, photo_url: '' }, actor);
160: {saving ? 'Saving...' : 'Save & Next'}
=== src/pages/MeasurementSession.jsx ===
63: await measurementService.save(session, tasks[index], data, 'Ray');
101:
=== src/services/dimensionService.js ===
60: const saved = existing ? await adapters.database.update('EnvelopeStation', existing.id, payload) : await adapters.database.create('EnvelopeStation', { ...payload, uuid: newUuid('station'), ...migrationFields(actor) });
=== src/services/measurementGeometryService.js ===
91:export async function saveStationMeasurement({ sessionUuid, componentUuid, station }) {
117: return base44.entities.EnvelopeStation.create(payload);
=== src/services/measurementService.js ===
8: async save(session, definition, data, actor) { const existing = (await adapters.database.filter('MeasurementValue', { session_uuid: session.uuid, definition_uuid: definition.uuid }, '-updated_date', 1))[0]; const previous = (await adapters.database.filter('MeasurementValue', { definition_uuid: definition.uuid }, '-measured_date', 20)).find(v => v.session_uuid !== session.uuid && v.value_mm); const value_mm = data.entered_unit === 'cm' ? Number(data.value) * 10 : Number(data.value); const warnings = []; if (definition.unit === 'mm' && (value_mm < definition.minimum_value || value_mm > definition.maximum_value)) warnings.push(`Outside expected range ${definition.minimum_value}–${definition.maximum_value} mm.`); if (data.entered_unit === 'mm' && value_mm < definition.minimum_value && value_mm * 10 <= definition.maximum_value) warnings.push('Likely wrong unit: this value may have been entered in centimetres.'); if (previous && Math.abs(value_mm - previous.value_mm) / previous.value_mm > 0.2) warnings.push(`More than 20% different from a previous ${definition.name} record.`); const warning = warnings.length ? `${warnings.join(' ')} Manual review required.` : ''; const payload = { value_mm, entered_unit: data.entered_unit, confidence: data.confidence, measured_by: actor, measured_date: new Date().toISOString().slice(0,10), notes: data.notes, photo_url: data.photo_url || '', storage_destination: data.storage_destination || '', warning, updated_by_name: actor }; const saved = existing ? await adapters.database.update('MeasurementValue', existing.id, payload) : await adapters.database.create('MeasurementValue', { ...payload, uuid: newUuid('measure'), session_uuid: session.uuid, definition_uuid: definition.uuid, project_uuid: session.project_uuid, ...migrationFields(actor) }); await auditService.record('measurement_changed', 'MeasurementValue', saved.uuid, `Saved ${definition.name}`, actor, warning); return saved; },
============================================================
LIVE ENTRYPOINT AUDIT COMPLETE — NOTHING CHANGED
============================================================
Evidence: /SHiREVault/Backup/OSBackups/LIMBFORGE-LIVE-3D-ENTRYPOINT-AUDIT-20260805T030639Z
No source, build, database or service was modified.
No build was run.
No service was restarted.
Sentinel was not modified or restarted.