This is our first published snapshot - we're not backfilling a version history we can't verify. From here, entries get added as real changes ship.
Version 1.8.231
Quote Engine: room finishes and a 3D camera, a whole-floor plan, kitchens in the room designer, and a Finish step
Rooms now render in their real finishes with a camera you can stand anywhere with; a project's rooms come together on one floor plan, with ready-made 3, 2 and 1-bedroom floors; kitchens use the same room designer as wardrobes; and every product ends with a short Finish step for the project's name and customer.
Finishes for renders
Walls in paint, textured plaster, concrete, exposed brick, wallpaper or panelling, in any colour, matte, satin or high gloss.
Floors in wooden planks, tiles, marble, stone, polished concrete, carpet or vinyl, at their real plank or tile size.
A plain, false or cove ceiling with its light, and skirting; the cabinet fronts in matte, satin or high gloss.
A false ceiling lower than a wardrobe, or a skirting behind one, is flagged.
3D camera
Eye height (standing, seated, child or any) and lenses from 16 to 50 mm.
Stand in the room: the camera stays inside the walls and widens until the whole piece is in view.
Save views on the room; they show on the plan. Render any view as a high-resolution picture.
Furniture between the camera and the piece fades so it never hides it.
Floor plan
Every room of a project on one plan: drag rooms into place (they snap flush to share a wall) and double-click one to design it.
Start from a ready-made floor: 3 bedrooms with 3 baths and 4 balconies, 2 bedrooms, or 1 bedroom.
Drag any wall of an L, U, T or drawn room in or out; doors, wardrobes and furniture stay in place.
Kitchens and other products
The kitchen's Layout tab uses the same room designer, with its cabinets on the plan and on each wall.
Kitchens, bathrooms, beds, office workstations, uPVC openings and wall panelling end with a Finish step for the project's name, customer and site.
CRM and work management
Email is never required on a lead, and a failed save shows the reason.
Card views for eight Work Management lists.
Version 1.8.230
Quote Engine: a room planner, one 2D drawing that prints, TV walls, screens and shaped shelving
Design a room before the furniture: draw its walls, shape it as an L, U or T, add doors, windows, pillars, beams and furnishings, and see every wall. The wardrobe's 2D view is now the drawing you print, and new configurator options add TV wall panels, decorative screens, shaped shelving, stacked carcasses and storage above study tables.
Room planner
Start a room from a preset (rectangle, square, L, U, T, stepped, recess, bay) or one of 15 room types, or draw your own walls with the pencil.
Drag doors, windows and doorways onto the walls; double-click any of them, or a pillar or beam, for its settings, with a side view to set the window sill.
Pillars and beams: a bay that meets a pillar asks whether to cut it round the pillar or leave a space.
Furnish rooms room by room: lamps, rugs, plants, art, beds, sofas, appliances and bathroom fittings (WC, basin, shower, cubicle, bathtub, jacuzzi), drawn on the plan and modelled in 3D.
Plan view with Top and every wall's elevation, a north arrow with true north, and elevation markers. Space + drag pans the plan.
The walls, doors and windows stand around the wardrobe in 3D.
Wardrobe design
Two screens only: Design, and Advanced options for what Design does not set.
Wall views in Design: the wardrobe, the room from above, or any wall with the wardrobe on it.
The 2D view is the printed drawing: inside with numbered compartments and their clear heights, front with handles, plan, ends, back and sections. Print sends them all as one PDF.
Sliding doors slide, pocket doors tuck back and bi-fold doors fold in 3D.
Opening a project goes straight to its design; a new one starts by picking what to design.
A grey figure stands beside the wardrobe for scale.
New configurator options
TV wall panels: slatted, fluted and plain strips, floating shelves and a lit TV panel, with eight presets.
Decorative screens and partitions, with five room-divider presets.
Shaped shelving (diagonal X, diamond lattice, concentric squares) and an arch over lower doors.
Storage above a study table, and five study-wall examples.
Stacked carcasses per column, each box in its own board; a 10 × 6 ft board size.
B2B, library and kitchens
A B2B order starts at once; the customer and project are added at the end.
Panel Library: edge bands, worktops, installation rates and lighting kits; copy, new and delete on definitions.
Inventory items: hardware library search and filters.
In CAD planning a kitchen carcass stops at the wall when dragged or nudged.
Version 1.8.229
Quote Engine: corner and walk-in wardrobes, attic eaves, kitchen starter cabinets and a simpler wardrobe configurator
Wardrobes can now turn a corner, stand under an attic ceiling, leave open wall between carcasses, take a study table or dresser between them, or stand free as a dressing island. Kitchen templates start with real cabinets, every product area has templates, and the wardrobe configurator is quicker to use.
Corner and shaped wardrobes
A column can be a corner: an L box with bi-fold or two doors, a diagonal corner, or a blind corner with its filler. The run turns onto the next wall there.
The first or last open column can have an angled or quarter-round end; quarter-round panels are charged at the front material's CNC cutting rate.
Ten new Design your own examples, including L-shaped, U-shaped walk-in and corner prayer units.
Walk-in closets
Leave open wall between two carcasses: each keeps its own sides, and nothing is charged for the space.
A column can be a study table or a dresser: open underneath, with a drawer under the top and a mirror above it. The mirror glass is listed to be priced separately.
A new dressing island stands free in the room, with doors on both faces, a board, stone or glass top and an optional seat bench. Stone, glass and cushions are listed to be priced separately.
Under the eaves
Sloped top can now be low at the back, for an attic ceiling. The doors stay full height at the front; the sides, top and back follow the slope behind them.
A shelf the slope makes too shallow, or a rail the slope comes down on, is flagged.
Kitchens and templates
Each kitchen template (straight, L, U, parallel and island) now starts with real cabinets from the box library: sink and hob bases, drawers, corner units, wall units and a tall pantry.
Every product area now offers templates to start from.
Wardrobe configurator
A round tool menu in each column adds a shelf at the height you click, a rail, drawers, a divider or a locker.
Remove a column; narrowing the wardrobe drops empty columns; height goes up to 14 ft.
Lofts can hold one to four shelves.
The configurator asks how a column closes first, snaps sizes to standard widths and heights, and shows fixed shelves in red and loose ones in blue.
Full-screen workspace, width guides, and a 3D view with lights on or off, a 180° or 360° turn, and a Back to design button.
Version 1.8.228
Quote Engine: tilt-out shoe bins, pull-out racks, coat hooks, a hanging panel and lockers
Hallway and shoe storage can now be designed in the wardrobe configurator: tilt-out shoe bins, pull-out shoe and trouser racks, coat hooks, an open panel for coats, and lockers inside a compartment. Each is cut and priced. Hardware the library does not hold yet is listed unpriced, never guessed.
Shoe and hallway storage
Step 6 adds Tilt-out shoe bins: one, two or three bins in a compartment. Each bin is cut as its front, two sides, a back and a bottom, and tips on a pair of tilt fittings picked from the hardware library.
Step 5 adds a pull-out shoe rack and coat hooks beside the trouser rack. They can be placed even before the hardware library has one: the quote lists them unpriced, with the compartment's size, until the item is picked.
Step 4 adds Hanging panel with hooks: the column becomes one board on the wall, with no carcass, and hangs from the top to the height you set.
Design your own has eight new hallway and shoe designs, including tilt-out shoe cabinets, a hallway set with a coat panel, and a wardrobe with a pull-out trouser rack.
Lockers
Any compartment can take a locker: a wooden shutter with hinges and a cam lock, behind the doors. It can be full width, or half width beside a divider.
The shelves above and below a locker become fixed shelves, and stay fixed while the locker is there.
The hinges (two, or three on a tall locker) and the lock are picked from the hardware library. Until then they are listed unpriced. Design your own adds a wardrobe with a locker.
Version 1.8.227
Quote Engine: wardrobes under a slope, and wall-hung pieces drawn at their height
A wardrobe can now sit under a staircase or a sloping ceiling: each column steps down to meet the slope, with an angled panel closing the space above it. A piece hung on the wall is drawn off the floor even before its height is set.
Wardrobes under a slope
Step 1 adds Sloped top: choose which end is low, the height of the slope there and its angle, with 30, 35, 40 and 45° presets for common stairs.
Each column comes down to meet the slope and stays a square box, so its doors stay square; an angled panel of the door material, cut to the slope, closes the triangle above it.
Shelves, rails or drawers that no longer fit in a lowered column are taken out, and the screen says how many; a column too low to use, or an angled panel taller than 400 mm, is flagged.
The picture, the sizing drawing and the 3D view show the slope and the angled panels; saved presets keep the slope.
Wall-hung pieces
A piece set to hang on the wall is never drawn on the floor: until its height is entered it is drawn at an assumed height, marked as not set yet.
The sizing drawing shows the floor under a hung piece and the height to it.
Version 1.8.226
Design your own: 48 more designs, including mandir units
Design your own now offers 118 examples to start from, up from 70. The new ones include wardrobes with a loft, ten mandir (pooja) units, crockery units, a bar cabinet and many more, each opening in the configurator ready to change.
New designs to start from
Wardrobes with a loft up to the ceiling: two-, three- and four-door, sliding, and with a low chest beside it.
Ten mandir (pooja) units, wall-hung and floor-standing. They come under lotus, temple and canopy arches with a jali back, or closed behind wooden or glass doors, and one has storage cupboards on each side.
Wardrobes with double hanging, a glass display column, a dressing niche, a shallow bookshelf, built round a pillar, or with no visible handles. Kids', utility and linen cupboards are there too.
Crockery units with glass doors, a bar cabinet with a drop-down flap, a dresser, a TV wall with display towers and an arched display cabinet.
Hallway pieces: an entrance cupboard with a loft, a tall shoe cupboard, shoe cubbies and a floating console.
Wall-hung pieces: a floating vanity, a push-open floating TV unit and a lift-up wall cabinet.
Bookcases with glass doors, pigeonholes or arched openings, a study wall, kids' cubbies, and room dividers with pigeonholes.
Finding them
New filters include With loft, Glass doors, Mandir (pooja unit), Crockery unit, Bar cabinet, Pigeonholes and Arched.
The pictures show lofts, pigeonholes, glass doors and arch openings, so what you pick is what opens.
Very tall designs now take a loft on top, as the configurator does, so every example opens within what an 8 × 4 board can cut.
Version 1.8.225
Quote Engine: one Library, one Settings page, and Back on every screen
The Quote Engine side navigation now has Library and Settings, each opening one page that brings every library or every setting together, and a Back button on every screen. Every product area starts the same way: from a template, fresh, or from your earlier designs.
Finding your way
The side navigation reads Back, Home, Quote, Library, Design, Files and Settings, and the entry for the part you are in stays highlighted.
Library opens one page with every library, grouped as panels and boards, hardware and fittings, modules and boxes, office, bathroom, doors and millwork, CNC designs, finishes and surfaces, and presets, with a search box.
Settings opens one page with the setup checklist, production configuration, materials and consumables, pricing, processing and surface rates, proposal terms, calculation coverage and doors and millwork settings.
You see only the cards you have permission to open. Old Products & Fittings links open the Library.
Back returns to where you came from on every Quote Engine and design screen, or to the area above when you opened the page directly.
Design opens Product Categories, where every product has its own design interface.
Starting a design
Every product area opens with Start fresh and Earlier designs above its list of earlier quotes, and Start from a template where ready-made designs exist (Wardrobe and Loose Furniture).
Design your own starts with a Start fresh card that opens a blank design: an empty carcass of the kind you picked, ready to design from scratch.
Version 1.8.224
Quote Engine: arch openings and jalis, door straighteners and a Lights tab
An open wardrobe column can take a CNC-cut arch face instead of doors, with a jali behind it, for a display, a bookshelf or a mandir. Tall doors suggest straighteners, and a column's light grooves are placed by dragging.
Arch openings and jalis
Step 5 adds an Arch opening for a column: 32 styles from round, pointed and Mughal cusped to temple arches such as the lotus, gavaksha and chhatri.
Set the rise, where the arch springs, where the face starts, the side frames and the crown; choose a painted edge or edge band, and a plain back, a jali or a backlit jali in one of 12 patterns or your own drawing.
Make it a mandir sets drawers at the bottom, a deity shelf and a lotus arch with a backlit Om jali in one click.
The arch face and the jali are cut on the CNC and charged per sq ft at the door material's CNC cutting rate, a new field in the Panel Library; without a rate they are shown as unpriced.
Doors and lighting
Doors 1600 mm or taller suggest door straighteners: one per door up to 600 mm wide, two on a wider door, in the length that covers the door; add them from the doors step.
The column settings have a Lights tab: drag the light grooves on the sides, under the top and under the shelves into place; a groove where the hinges sit is flagged.
Platform
HR and confidential documents can be kept in a separate private storage area with its own credentials, set and checked in Application Settings.
Wardrobe kickboards and base-frame rails print under their own Plinth heading on the cut list.
Wardrobe drawers come in standard combinations, inside or on the front, with fronts of their own material. A column's settings open with a double-click, a pillar behind it can be cut round, shelves stop at standard heights, and the plinth can be built with a raised bottom or on a base frame.
Drawers
Step 4 offers seven drawer combinations, from two standard drawers to a graduated stack with jewellery drawers at the top; any that does not fit is greyed with the height it needs.
Choose Internal (behind the doors) or External (fronts of their own, no side fillers) for each compartment; the doors above and below follow.
Click or double-click a drawer to set its height, type, runner (telescopic or under-mount) and its front material, which can differ from the doors.
Columns
Double-click a column, or Settings on its card, for all its settings in one form: width, height, depth, loft, fixed and loose shelves, each shelf's behaviour and a pillar behind it.
A pillar can stand in a corner or anywhere along the back; the column keeps its depth and is cut round it.
A column is never taller than the height set in step 1 and snaps to it; dragging the right-hand edge back removes empty columns, and the width has no upper limit.
Standards and base
Dragged shelves stop at standard heights: over drawers at 700, 750 or 900 mm, 350 mm apart for folded clothes, and at the short, medium and long hanging drops.
A clothing rail has a hang length; a space too short for it, a shelf out of reach or drawers set high are shown under Worth a look, never blocked.
Step 2 builds the plinth with a raised bottom (sides to the floor) or on a base frame, with the kickboard set back or flush; both are cut and priced.
Version 1.8.222
Quote Engine: lofts, presets, drag to resize and shelves beside a divider
Wardrobes can be dragged to size, take a loft that fits the board, keep shelves in one section beside a divider, and be saved as presets. A new project now opens straight on its design; its details are filled in at the end.
Designing
A new project opens straight on Rooms & products. Its name, customer and site are filled in at the end, under Customer & site and Project details.
Design your own opens with the wardrobes. Save any design as a preset; your presets appear under Design your own.
Tick Drag to resize to drag widths, heights, shelves, rails and dividers in the picture, with the size in millimetres beside the pointer.
Materials are now the last step, and every step has a Back button beside Next step.
Lofts and boards
Choose the board in step 1: 8 × 4 (cut to 2400 × 1200 mm) or 10 × 4 (cut to 3000 × 1200 mm).
Any column can have a loft on top, built as a box of its own. A column taller than the board gets one automatically, and dragging a column down shrinks the loft first, never the cabinet under it.
A column wider than 1200 mm becomes two or more columns when you let go.
Shelves
Each column has two counters: Fixed shelves and Loose shelves. The shelf above drawers is always fixed.
Shelves can go in one section beside a divider: pick a divided compartment and set the shelves for each side. They are cut to that section's width.
With the dimensions shown, a line up each column gives the clear gap between its shelves.
Also
A column's side filler can have its own width.
Pieces on feet or on the wall are drawn and placed as such, with a mounting height for wall pieces in the picture and the 3D view.
The rear edges of every column with no back are edge-taped, and the proposal can be split by design type.
Version 1.8.221
Quote Engine: wardrobe columns of their own height, drawers that open in 3D
A tall wardrobe and a low sideboard can now stand in one run: each column can have its own height. Drawers slide open in the 3D view, and the 3D view can turn 180° or all the way round.
Wardrobe configurator
Each column can have its own height. Drag the handle on top of a column, use its Height stepper, or type it in step 4. A column cannot go lower than what it holds, and the run is always as tall as its tallest column.
Drag the handle on the right-hand edge to change the overall width.
The picture, the Sizing drawing, the 3D view and the example pictures show every column at its own height.
Step 4 has a Back wall panel checkbox; untick it to leave the back open.
Five new examples under Tall and low: wardrobe with low sideboard, wardrobe with low drawer unit, hallway cupboard with shoe bench, bookcase with low TV wing, and sideboard with tall cabinet.
3D view
Click a drawer to slide it out and click again to close it. Drawers with their own fronts also follow the Open doors slider.
The view bar has a Front checkbox, Sizing, and a 180° View button whose menu switches between 180° and a full 360° turn with a Back view.
Version 1.8.220
Files saved before the move to cloud storage open again
Storage moved to Amazon S3 on 9 October. Documents and files saved before that move would not open; they open again now.
Fixed
Employee documents saved before 9 October (Aadhaar, PAN, certificates and other HR files) open again from the employee record.
Files repository items, lesson media, task attachments and older site-survey photos saved before the move open again.
Files saved since the move are unaffected and keep opening from cloud storage.
Version 1.8.219
Quote Engine: step-by-step wardrobe configurator and Design your own
Wardrobes are now designed step by step beside a large live picture you can edit directly. A new Design your own tab starts sideboards, shelving, hallway storage, room dividers and more from 58 ready examples.
Wardrobe configurator
The wardrobe page starts with one Start designing button. It opens a 2000 × 2500 × 600 mm wardrobe with two columns, and the last step names it and sets the project, customer and site, or copies the design into an existing project.
Configure in seven steps (size, material, base, columns and compartments, interior, doors and drawers, extras and save) beside a live picture: drag shelves and dividers, add shelves, and pick a column or compartment directly.
Front, Sizing and 3D views, with an Open doors slider and click-to-open doors in 3D.
Materials come from the Panel Library (family, board, colour). Interior options that do not fit are greyed out with the reason.
Fronts per compartment: doors, flaps and drawer fronts; press and drag to make one tall door.
Drawer options: drawer type, runner (separately for door-covered and open drawers) and the bay's side fillers.
Extras from the hardware library with their prices: LED with sensor, trouser hanger, tie and belt holder, clothes lift, cable cut-out, cover strip, plus special requests.
Every change saves automatically and the price refreshes. Undo and redo with Ctrl+Z and Ctrl+Shift+Z.
Design your own
New Design your own tab in the Quote Engine with seven kinds: wardrobe and cupboard, hallway storage, cabinet and sideboard, hanging sideboard, shelving and bookcase, room divider, and hanging shelf.
Each kind has a plain start and examples with real sizes, 58 in all. Starting one creates the project, room and piece and opens the configurator.
Pieces can stand on a plinth, on feet or on the wall, with feet and wall brackets picked from the hardware library and priced as their own lines. Nothing is priced until a priced item is picked.
Shelving, room dividers and hanging shelves skip the interior step; room dividers have no back panel.
Known limits
A new design opens in the default board; example colours are hints only.
Wall-hung pieces are still drawn at floor level, and sideboards and shelving still appear in the Wardrobe category of extracts.
Version 1.8.218
Founders Vault: one email code per sign-in, stays open for 8 hours
Founders Vault is simpler to use. One email code opens it for 8 hours, even if you leave the page, and sensitive actions no longer ask for another code. Vault records now sit in the main database, still encrypted, and uploads open straight away.
Founders Vault
One email code opens your Vault in that browser for 8 hours. Leaving the page or switching screens no longer locks it; Lock Vault or signing out of the ERP does.
Revealing a value, opening or downloading a document, exporting, restoring and changing settings no longer ask for a second email code once the Vault is open.
Vault records are kept in the main ERP database. They stay encrypted with the Vault's own key, so they cannot be read from the database or its backups.
Uploaded PDFs and images open straight away. Where no malware scanner is set up they are marked "Accepted without malware scanning."
The Vault is still visible and usable only by the founder or a director whose employee record carries that governance capacity.
Version 1.8.217
Hotfix: files saved before the move to S3 open again; scheduled-email switch; HR and wardrobe fixes
Files and documents saved before storage moved to Amazon S3 open again. Also adds a Scheduled emails switch that is off by default, two HR fixes, buttons in link emails, and a simpler wardrobe screen.
Storage (hotfix)
After storage moved from local disk to Amazon S3, files saved earlier could not be opened: HR employee documents, lesson media, developer task attachments, older site survey evidence and Files repository content. They are served from local disk again when their bytes are there. Files with an S3 key still come from S3.
Email
New Scheduled emails switch in Application Settings, Transactional Email. Mail sent from inside a background job is held unless it is on, and it is off by default, so existing scheduled mail stops until someone switches it on. Mail triggered by a person's action is not affected.
Personal-email verification, offer letter, experience letter, quotation, portal invite, newsletter confirmation and SaaS quotation emails show a button instead of a bare link.
HR
Attendance check-out earlier than check-in is rejected.
The onboarding detail opens for an employee whose record was deleted, and links to deleted employees no longer lead to dead pages.
Quote Engine
The wardrobe configure screen opens as a simple six-step playground (size, material, base, columns, inside, doors and handles) with a live drawing and a price and Save bar; the tabbed form stays under Advanced details. The wardrobe page has a quick start: one required name, an optional project, then the project, room and wardrobe are built.
Fixes found in the walkthrough: the project picker lists existing projects, new wardrobes start with two 1000 mm columns, an Open column clears its door count, and a price of 0 reads Not priced yet.
Platform
No migration.
Version 1.8.216
Inventory screens repaired and made safer: lists that fill, price-list publish, confirmations and permission checks
Several Inventory lists that could never fill now do, publishing a price list works again, stock and valuation actions ask before they post, and every Inventory write checks your permission. Errors now say why, and money shows in rupees.
Inventory
Lists that never filled now show their rows: reservations, stock locations, stocking profiles and vendor sourcing profiles.
Publishing a price list works again; it was refused for every draft. Industry pack edit, submit, publish and retire, RFQ comparison and quotation, vendor profiles and migration mapping now send what the server expects.
Stock adjustments, lot consume, split, quarantine and release, transfers, reservations, blocks, quality decisions, Policy Apply, workbench actions, ABC exports and snapshots, RFQ and supplier lifecycle, and master deactivations now ask you to confirm first, naming what will change. A master CSV import asks before overwriting.
Every Inventory write button checks your permission and shows a reason when it is disabled for your role.
A failed load shows the server's reason with a working Try again. A permission error names the access the page needs and is not retried, and no empty message appears under a failed load.
Money shows in rupees in Indian number format, units appear only where the data carries them, and Tax Master pages honestly.
Sixteen pop-up panels became centred dialogs that stay open while they are saving; Escape and click-outside are ignored until the request finishes. Typed work is protected on the masters and on 17 stock, procurement and intelligence screens.
Brands save asks for confirmation; the workbench has Mark complete; the price-list revision keeps the reason you typed if you press Escape; stocking profiles show a Retired badge and can be reactivated; locations have a Role filter in place of Type.
Platform
No migration, no API change and no permission-catalogue change.
Version 1.8.215
Work Management Programs open as cards
Work Management Programs open as cards by default, with a Cards or Table choice remembered per user.
Work Management
Programs open as cards by default with a Cards or Table choice remembered per user, showing the name, code, status, portfolio and created date. Programs have no detail page or row actions, so the cards have none either. Load more works in both layouts.
Platform
No migration and no API change.
Version 1.8.214
Work Management Portfolios open as cards
Work Management Portfolios open as cards by default, with a Cards or Table choice remembered per user.
Work Management
Portfolios open as cards by default with a Cards or Table choice remembered per user, showing the name, code, status and health, and the created date. Portfolios have no detail page or row actions, so the cards have none either. Load more works in both layouts.
Platform
No migration and no API change.
Version 1.8.213
Application Settings now links to Operations, Go-Live Certification, Connection Checks and Database Backups
The Application Settings Overview has a new Operations & Security section, so the Operations page and its neighbours can be opened directly instead of only from the Analytics dashboard.
Application Settings
A new Operations & Security section on the Overview shows Database Backups, Connection Checks, Operations, Go-Live Certification and Module Control. It follows the same rules as the other cards: you see a card only if you have access to it, and the search box covers it.
The Operations description now says what the page does: feature flags, maintenance mode and live health.
The Operations page has a back link to Application Settings, and Go-Live Certification has breadcrumbs.
Platform
No migration, no API change and no permission change.
Version 1.8.212
Delete invitation on every onboarding row, and card views for Brands, Price Lists and Projects
Onboarding invitations whose employee record was deleted can now be cleared from the Onboarding page, and Brands, Price Lists and Work Management Projects open as cards.
HR
The Onboarding page has an Actions column with a visible Delete invitation button on each unfinished row, including rows whose employee record was deleted, which could not be expanded before. It asks for the same confirmation as before and is shown only to people who can update onboarding.
Inventory
Brands open as cards by default with a Cards or Table choice remembered per user, showing the discount, tier count and status, with Edit and Activate or Deactivate.
Price Lists open as cards by default showing the authority state (current, scheduled, expired or draft), Default and Active chips, eligibility and line count, with Publish, Withdraw, Edit, Deactivate, Create revision and History under the same rules as the table.
Work Management
Projects open as cards by default with a Cards or Table choice remembered per user, showing status and health, the financial job link and the created date. Load more works in both layouts.
Platform
No migration and no API change.
Version 1.8.211
Files can now be switched on: the Files module is added to the installation's entitlement
Adds a one-time data update that gives the Propulsive ERP installation the Files module, which the new Files workspace needs before it can be switched on. Nothing changes for users until the Files feature is turned on.
Platform
A data update (migration 102) adds the Files module to the Propulsive ERP edition and replaces the installation's active entitlement with one that includes it. The old entitlement is kept as history. It does not switch Files on, changes no feature flag, and does nothing if Files is already included.
It must be applied on each host after deploying; it does not run by itself.
Version 1.8.210
CAPA investigations (Five-Why and 8D) and reviewed Inspection Plan feedback
Corrective actions gain Five-Why and 8D investigations, and a CAPA can propose an Inspection Plan change that an independent approver turns into a draft plan version. The CAPA screen is rebuilt.
Quality
Five-Why and 8D investigations on corrective actions, with versions, evidence checks and safe retries.
A CAPA can propose a change to an Inspection Plan. A different person approves it, and the change becomes a draft plan version that keeps a permanent record of where it came from.
The CAPA screen under Manufacturing, Corrective actions is rebuilt: create, list, record detail, investigations, effectiveness and proposals. The Record preview button and unsaved-work protection are kept. Save and Cancel sit in the page header on this screen.
Platform
No migration. Corrective action reports gain new fields; access follows the existing corrective action and inspection plan permissions.
Version 1.8.209
A searchable More menu for every module, and a Simple or Full menu for HRMS and Accounts
The More menu on module rows is now a panel with a search box, section chips with page counts and a page grid, and HRMS and Accounts get a Simple menu or Full menu switch.
Navigation
The More menu on module rows opens as a panel with a search box, one chip per menu section showing its page count, and a grid of the pages in the chosen section. Typing searches every section. A menu with fewer than 12 pages stays a plain grouped list. It is used on the module row for HRMS, Accounts, Inventory, Manufacturing and the other modules, on the CRM row, and on Quote Engine, Product Library, Design Studio and Files.
HRMS and Accounts have a Simple menu or Full menu switch beside More, remembered for each person. Full puts every page in the row; every page is reachable under More either way.
The panel lists only the pages the existing menu rules already allow, so what you can open does not change.
Platform
No migration and no API change.
Version 1.8.208
Prospect Pool re-import fix, Warehouses cards, a tidier Email list and Files fixes
Re-uploading phone-only prospects now applies their real company names. Warehouses open as cards, the Email list columns line up like Gmail, and the Files New menu and Move to folder work.
CRM
Prospect Pool re-import: organizations created from a phone-only import and named Unnamed prospect followed by a phone number now take the real company name when you re-upload the file with Update existing prospects ticked. A real name that is already entered is never overwritten, and a name another organization already holds is kept with a note.
Inventory
Warehouses open as cards by default with a Cards or Table choice remembered per user, showing Default and Active chips and the city and state, with Edit and Activate or Deactivate for people who can update warehouses.
Email
The desktop message list has fixed columns in Gmail's order: select, star, sender, subject, attachment and date, with the select-all box and bulk actions in the table header above the row checkboxes.
Files
The New menu in the Files workspace is no longer clipped, so New folder can be reached.
A file's row menu has Move to folder, and the destination list starts with My files and the folders you created. The Files workspace only shows where the files feature is switched on.
Platform
No migration. Also includes the HR create-employee and validation fixes already on pilot.
Version 1.8.207
Card views for Credit Notes, Debit Notes, Delivery Challans, Goods Receipts, Purchase Indents and Inventory Items
Six more lists open as cards by default, with a Cards or Table choice remembered per user.
Sales
Credit Notes open as cards by default with Open or View, Preview PDF and Download PDF; a failed ledger posting shows its error on the card.
Delivery Challans open as cards by default showing the warehouse and delivery date, with Open or View, Preview PDF and Download PDF.
Purchase
Debit Notes open as cards by default with Open for drafts or View; a failed ledger posting shows its error on the card.
Goods Receipts open as cards by default with Open for drafts or View, and the receipt number links to the goods receipt page.
Purchase Indents open as cards by default with Edit or View, Submit, Approve, Reject and Cancel under the same status and permission rules as the table; Delete shows on drafts. Approve and Reject show disabled with the reason when you raised the indent yourself.
Inventory
Inventory Items open as cards by default at every width, with Edit and Activate or Deactivate for people who can update items. The table and the mobile list stay under the Table toggle.
Platform
No migration and no API change.
Version 1.8.206
Production inspections, CNC program lifecycle and the Training Operations workspace
Adds operation-level quality evidence for production inspections, a CNC program lifecycle for machines that need an approved program, and a Training Operations workspace.
Manufacturing
Production inspections can record quality evidence for each operation. Each inspection plan can optionally require that evidence before work continues; by default it is advisory, so nothing is blocked unless quality releases a plan set to required.
CNC programs have a lifecycle: issue, review, acknowledge, outcome and reconcile. On a machine marked as CNC-managed, starting or finishing an operation needs an issued and acknowledged program. Machines not marked as CNC-managed are unaffected.
Training
A Training Operations workspace at Training, Delivery, Operations.
Platform
No migration. The production inspection and CNC program data live in new collections.
Version 1.8.205
Field Operations: check-in, visit and attendance groundwork (switched off)
Adds the Field Operations foundation: a mobile check-in screen, visit lists, and the attendance, expense and posting checks behind them. Everything is switched off and does nothing until the owner turns it on.
Field Operations
A mobile field check-in screen and its check-in service, an offline queue that holds a check-in made without signal, and visit list and context pages for employees.
Checks for attendance, visit-linked expense claims and visit-linked ledger postings, with preview and execute steps. All are switched off: the Field Operations feature flags start disabled, and the attendance, expense and posting steps only act once the owner sets specific settings on the server.
Readiness scripts and notes for the owner's go-live review.
Platform
No migration. With the new settings unset, nothing changes for any user.
Version 1.8.204
Card views for Sales Invoices, Vendor Bills, Estimates and Receipts
Sales Invoices, Vendor Bills, Estimates and Receipts open as cards by default, with a Cards or Table choice remembered per user.
Sales
Sales Invoices open as cards by default with a Cards or Table toggle. Card actions match the table row menu: Open or View, Preview PDF and Download PDF; a failed ledger posting shows its error on the card.
Estimates open as cards by default. Card actions follow the table row menu under the same conditions and disabled states (PDF, payment link, email, edit, approve or deny, Mark as Proforma, reject, revision, record payment, convert to Sales Order), with an Open payment link button when a link exists. Delete shows on the latest draft for people who can delete.
Receipts open as cards by default with Preview PDF and Download PDF, a posted or not posted ledger chip and the journal entry number. The page stays read-only.
Purchase
Vendor Bills open as cards by default with Open for drafts or View, Match and ledger chips following the table's conditions, and a failed ledger posting shown on the card.
Platform
No migration and no API change.
Version 1.8.203
IT & Infrastructure registry replaces the placeholder screens
The IT & Infrastructure app now has a working registry for providers, assets and settings with a renewal workspace, replacing the placeholder screens on all seven Infrastructure pages.
IT & Infrastructure
A registry of infrastructure providers and assets with settings and a renewal lifecycle, replacing the placeholder on all seven Infrastructure pages. Access follows the existing Infrastructure permissions.
A new infrastructure service on the server holds the data in three new collections; their indexes build automatically the first time the server starts.
Platform
No migration. An optional index script ships but is not run automatically.
Version 1.8.202
Card views for Support Tickets, Purchase Orders and Sales Orders; Qualify and Convert on lead cards
Support Tickets, Purchase Orders and Sales Orders open as cards by default with a Cards or Table choice, and lead cards gain Qualify and Convert to opportunity.
CRM
Lead cards have Qualify (opens the lead with the qualification checklist) and Convert to opportunity, shown only to people who can update leads and hidden on converted leads, plus a Qualified or Not qualified chip.
Support Tickets open as cards by default with Open, Resolved and Closed, priority and channel chips, raised-by, assignee and dates, and Assign, Status, Edit and Delete behind the same permissions as the table.
Purchase
Purchase Orders open as cards by default with a Table toggle; the card actions follow the table's per-status rules, including why Approve is disabled when you raised the order yourself.
Sales
Sales Orders open as cards by default with a Cards or Table toggle remembered per user. Card actions match the table row menu under the same status and permission rules: Edit or View, PDF preview and download, Submit, Approve or Reject, Confirm, delivery challan, tax invoice and Cancel order; Delete shows on drafts.
Platform
No migration and no API change.
Version 1.8.201
Service Tickets as cards, and door set pricing that says Not priced instead of zero
The CRM Service Tickets page opens as cards by default, and the door set configure pricing breakdown shows Not priced for unstated rates instead of a free zero.
CRM
Service Tickets open as cards by default, with a Cards or Table choice that is remembered per user. Cards show status, priority and dispatch chips, assignee and site facts, and the SLA countdown (red when breached), with Edit, Call and Delete behind the same service permissions as the table. Call shows the dispatch site contact's number when there is one, otherwise the customer's.
Quote Engine
Door set configure: the Pricing breakdown prints Not priced for unstated rates and an unknown total, instead of showing a free zero.
Platform
No migration and no API change.
Version 1.8.200
Vendor cards, a Back button that no longer jumps home, and larger Cards/Table toggles
Vendors open as cards by default, the Back button returns to the right page even after a refresh, and the Cards or Table toggles on Parties, Contacts and Vendors are large enough to tap.
CRM
Vendors open as cards by default, with a Cards or Table choice, plus Edit, Call (a pop-up with the vendor's number) and Activate or Deactivate.
The Cards or Table toggles on Parties, Contacts and Vendors are now at least 44px tall.
Platform
The Back button no longer sends a refreshed page to the platform home: after a refresh it goes to the previous page, and a page opened directly falls back to its own module such as CRM or HR. The B2B quick-quote Back button has the same fix.
No migration and no API change.
Version 1.8.199
CRM card views, Call pop-up, Google profile on records, and Edit links across Party, Lead and Opportunity pages
Leads, Opportunities, Parties and Contacts open as detail cards by default with a Cards or Table choice, Call shows the number in a pop-up, saved Google profiles appear on records, and Party 360, Lead and Opportunity pages gain Edit and Open links.
CRM
Leads, Opportunities, Party accounts and Contacts open as detail cards by default, with a Cards or Table choice. Opportunities keep Kanban; Leads no longer have it. Cards show a Google verified badge, Edit, Call, Verify and Delete.
Call shows the number in a pop-up on the cards, the Follow-ups page and the Ctrl+K search bar.
The Leads table keeps its Actions column in view and labels Edit and Delete.
Lead, Party 360 and Prospect pages show the saved Google Places profile.
Party 360: Edit address, notes and territory; Add contact (a new contact starts under that party); Open and Edit on contacts, opportunities and estimates; Open or edit on sales orders, delivery challans and tax invoices; Open on projects, work orders and tickets.
Lead page: Edit beside notes, address and source. Opportunity page: Edit customer, Edit contact, and Edit on deal terms and key dates.
Prospect Pool CSV import has Update existing prospects ticked by default, plus a re-run button for skipped duplicates.
Platform
No migration. The deals and contacts lists also return the Google place id of the account, for the verified badge.
Version 1.8.198
Hotfix: dialogs no longer vanish when you choose keep editing
Fixes a regression where closing certain dialogs with X, Escape or a click outside, then answering Discard changes with keep editing, made the dialog disappear while your typed edits were stuck behind it and it could not be reopened.
Fixes
Dialogs now stay open when you answer Discard changes with keep editing. Fixed on eight dialogs across five screens: the Quote Engine component library editor, the industry pack governance panel and Apply form, vendor bills Record payment and Capitalize, CRM Quick Lead, and CRM ticket Dispatch and Edit details.
No migration and no API change.
Version 1.8.197
Party Directory lists real customers; mark as existing customer and move back; simple or full CRM menu
The Party Directory now lists real customers by default, you can mark leads, opportunities and prospects as existing customers, move a party back to Lead, Opportunity or the Prospect Pool, and choose a simple or full CRM menu. The search bar gains Edit, Call and Create.
CRM
The Party Directory shows real customers by default: a party with a proforma invoice and a recorded payment, a posted invoice, a SaaS tenant, or one declared an existing customer; partners, architects and vendors stay. Parties without that evidence are hidden until someone marks them as existing customers. A Show leads and prospects too button restores the full list.
Mark as existing customer on Leads, Opportunities (More menu) and Prospect Pool records converts older customers imported from the previous CRM; a reason is required.
Move back on Party Directory rows and Party 360 sends a party back to Lead, Opportunity or the Prospect Pool. It is refused when a payment, posted invoice or SaaS tenant is behind the party.
The search bar (Ctrl+K) gains Edit (Ctrl+E), Call (Ctrl+Enter), a Create group and vendors; Call opens the calling screen with the number to dial. The governed calling flow is unchanged and still off.
A Simple menu or Full menu button in the CRM tab row lets each user choose the short daily row or the full row, saved per user and device; everything stays reachable under More.
Platform
No migration. New fields are additive: an existing-customer declaration on accounts and a returned-to-pool marker on prospects.
Version 1.8.196
Edit buttons across CRM, quotations that say Not priced, Library parity, Purchase and Quote Engine clarity
Party Directory rows and the Lead, Contact, Party 360 and Deal pages gain Edit buttons. Quotation documents say Not priced instead of failing when a quote has not been costed. The Product Library and Panel Library match the approved designs, and Purchase and Quote Engine screens ask before consequential actions and protect unsaved work.
CRM
Edit buttons on Party Directory rows and on the Lead, Contact, Party 360 and Deal pages; Companies and Contacts open their editor and return to the page you came from on Save or Cancel.
Quote Engine and Estimation
Quotation documents render Not priced when a quote has not been costed, instead of failing with a calculation error; wardrobe shows why a governed thickness is read-only.
Product Library and Panel Library match the approved designs: Production Config tabs, footer and sheets cards, the management overview, output state tiles, phone layouts, validation panels, the shutter costs three-pane view, and a Kerf and End allowance split on handle profiles. An evidence panel that reloaded endlessly is fixed.
Quote Engine and Estimation screens ask before issuing, approving, publishing or converting; rate cards refuse a blank amount instead of saving zero; agreements use name pickers; permission checks on these screens match the server's.
Purchase
Names instead of ids, rupee signs, larger touch targets and labelled fields across Purchase screens; unsaved-work prompts on about 40 more screens.
Platform
No migration and no API change.
Version 1.8.195
Prospect Pool update-existing import, Verify with Google on Lead/Deal/Party, Module Library family imports
The Prospect Pool CSV import can update existing prospects, the Pool hides contacts that have already become a Lead, Opportunity or Party, and Lead, Deal and Party Account pages gain Verify with Google. The Quote Engine Module Library can import kitchen, wardrobe and home review candidates. Also ships the phone-only verification from 1.8.194.
CRM
CSV import has an Update existing prospects option: it fills blank fields only (mobile, personal email, organization name) on matched contacts and organizations, never overwrites, keeps going past bad rows and reports updated and unchanged counts.
The Prospect Pool hides organizations whose contacts have all become a Lead, Opportunity, Prospect or Party; the lead, opportunity and quote KPIs were removed from it.
Verify with Google is available on the Lead page, the Party 360 page and the Deal More menu, reusing the existing prospect verification permissions.
A shared Google profile is stored on Prospect, Lead and Party Account and carries over when a prospect becomes a lead or a party. Lead gains website, address line and postal code fields.
Prospect verification looks up phone-only prospects by phone number (cut as 1.8.194 and deployed together with this release).
Quote Engine
Module Library, Seed review: a new Import kitchen, wardrobe & home candidates button reads the already-seeded product-library templates and the latest dry-home and bathroom definitions and creates review candidates. Nothing is invented: unresolved facts become blockers, it is safe to press twice, and nothing is published.
After deploy, someone with Module Library update permission needs to press the button once on each environment; nothing runs on its own.
Platform
No migration.
Version 1.8.194
Prospect Pool: verify prospects that only have a phone number
Verifying a Prospect Pool record that has no company name or location now looks it up on Google Places by its phone number, and falls back to the phone when a name search finds nothing. Searching the list also matches phone numbers.
CRM
Prospect verification looks a prospect up by phone number (India country code assumed) when it has no name or location, and retries by phone when a name search returns nothing; contact phone numbers are included.
The Prospect Pool list search now also matches phone numbers.
No migration and no schema change.
Version 1.8.193
Design workspace gets more canvas; CRM command center and territory map fixed for older MongoDB
The Design engine workspace gives the canvas the 73px the footer used to take. The CRM command center and territory opportunity map use query forms that production's MongoDB accepts. WhatsApp inline-template creation gains test coverage.
Design
Design engine workspace: the page footer yields its 73px to the canvas on that route, so the canvas is taller at 1280 x 720.
CRM
The CRM command center's contacted count and the territory opportunity map now use query forms that older MongoDB servers accept (lookup with a pipeline and arrayElemAt in place of first and the local-field pipeline lookup), so they no longer fail on production's database version.
Platform
WhatsApp inline template creation: API and frontend test coverage added.
No migration and no API-contract change.
Version 1.8.192
Google Places verification works with newer keys; Prospect Pool edit (ships 1.8.191)
Test connection and Verify Details on Google Places Verification now fall back to Places API (New) when Google refuses the key on the legacy API, and enrichment sends the key the way Google expects. Also ships the Prospect Pool edit button and Add prospect label first cut as 1.8.191.
CRM
Google Places: Test connection and Verify Details fall back to Places API (New) when the legacy API is not enabled for the key's project; when both refuse the key, the message shows Google's own reason with the key redacted.
Prospect enrichment sends the key in the X-Goog-Api-Key header (it was sent as a Bearer token, which Google rejects) and uses the key saved in Application Settings.
Prospect Pool: every row has an Edit button that reopens the quick prospect form pre-filled; the header button reads Add prospect; the duplicate check no longer flags the record being edited (this was cut as 1.8.191 and deployed together with this release).
No migration. After deploy, press Test connection on Google Places Verification, then activate it.
Version 1.8.191
Prospect Pool: edit a prospect from the list, clearer Add prospect button
Every Prospect Pool row now has a visible Edit button that reopens the quick prospect form pre-filled, and the header button reads Add prospect.
CRM
Prospect Pool: every row has an Edit button (shown to people who can update contacts) that reopens the quick prospect form with the company and primary contact filled in, and saves both.
The header button now reads Add prospect.
The duplicate check no longer flags the record you are editing as a duplicate of itself.
No API, migration or schema change.
Version 1.8.190
Prospect Pool: delete is now easy to find
Selecting prospects now shows a bar above the table with the selection count, Clear selection and Delete selected; the row action reads Delete prospect. Behaviour and permissions are unchanged.
CRM
Prospect Pool: a selection bar above the table shows how many prospects are selected, with Clear selection and Delete selected.
The row action is now labelled Delete prospect (it was Remove duplicate / test record inside the More menu); the footer button is renamed Delete selected.
Deleting still needs the same permission as before. No API, migration or schema change.
Version 1.8.189
Prospect Pool CSV import fixed; vendor-bills and recruitment unsaved-work follow-ups
The Prospect Pool CSV import no longer crashes on load, shows its result after an import, files territories under the right code, and no longer leaves an empty organization behind when a contact is a duplicate. Vendor-bills Close and the recruitment footer badges now respect unsaved edits.
CRM
Prospect Pool import: the preview step now returns the row count and sample rows the import window needs, so the window opens instead of crashing; the result step shows imported and skipped rows.
Territory names such as Delhi-NCR now map to the master territory code (DELHI_NCR); unknown territories are held back as skipped rows instead of being stored as typed.
A row whose contact already exists now imports nothing — it no longer leaves an empty organization behind.
Platform
Vendor-bills header Close now asks before discarding unsaved edits; the recruitment footer badges (assessments, candidates, requisitions) read the same unsaved-changes source as the guard.
Lands the audited ZCode HRMS (batches 1-3), Sales (batch 2) and Purchase (batch 1) UI programmes: typed work is protected on the purchase routes and ~40 HR routes, raw ids no longer show where a name belongs, consequential writes ask before they happen, and Purchase write buttons now respect permissions on the handler as well as the screen. Audit repairs keep the build green and the guards from misfiring.
Purchase
Purchase orders, indents, vendor bills, vendors and the goods-receipt control workspace now warn before discarding typed work; cancel buttons confirm when the form is dirty.
Vendor bills: posting, cancelling, paying and creating are permission-checked in the handler as well as hidden in the screen; paying a bill confirms the vendor, amount and bill number first; the payment and capitalization forms moved from side drawers to centered dialogs; Total and Due columns carry the rupee sign.
Vendors: deactivate/reactivate confirms with the vendor named; bulk CSV import and export are shown only to holders of those permissions; an unknown approval status no longer displays as approved.
Sales
Document label helpers (invoices, credit notes, debit notes, delivery challans) show a dash instead of a raw id when a reference is unpopulated; open-invoice and open-bill pickers show a clear error with Retry instead of failing silently.
Quotation detail: duplicate header buttons removed, approval status shown in plain words, money cells normalised to rupees, form fields labelled for assistive technology.
HR
Unsaved-work protection on about 40 HR routes; names instead of ids across 19 surfaces; weekly-off settlement and salary-advance disbursement now confirm with their consequences before they run.
Rupee signs and 44px targets on payroll, goals, onboarding and attendance; capped counts show N+ when the data window fills; the reports picker is a horizontal tab strip.
Platform
Audit repairs: duplicate guard members in leave requests (build error) removed; policy-packs keeps its workspace-aware guard; stale dirty flags that made cancel prompts misfire fixed in vendors, purchase orders, indents, vendor bills, statutory masters and goods receipts.
No migration and no API change.
Version 1.8.187
Guard-programme package reconciled + Chart of Accounts add-ledger fix
Lands the audited 73-host unsaved-changes guard package under its merge condition — the wave-skipped hosts now guarded, four save-then-nag defect fixes, main's richer guards kept on every shared host — plus the Chart of Accounts add-ledger fix (legalEntity stamped server-side, duplicate codes 409 with the code named), and the honest repair of what the package landing had broken: 40 duplicate guard members that broke the build, 27 dropped route wirings, and the Sales-owned billing-settings host.
Platform
Unsaved-changes guard package (73 host+route pairs) reconciled: ~23 additive hosts guarded (training suite, P2 lists, todo, leave-requests, journals, vendor-bills, delivery-challans, payment-allocation, eway, item-groups/categories, cms tail); four defect fixes (vendor-bills saveDetail, delivery-challans saveDetail + saveInstallationCompletion, email-templates save() markAsPristine); 40 duplicate guard blocks resolved in favour of main's richer snapshot guards; 27 dropped route wirings restored (canDeactivate 253→280); accounts/settings ceded to the Sales workTemplateUnsavedGuard mechanism with the Discard confirm; coverage-spec allowlist registration landed with the file; library command-center route pins re-pointed.
Landing-repair disclosure: the package had been landed on main without gates — the build was broken since (TS duplicate members). All repairs gated: build exit 0; test:frontend 712 bundles / 8,765 specs / 0 failures.
Accounts (api)
Chart of Accounts manual add never worked: beforePersist now stamps the Organization's legalEntity on create AND update; compound-index duplicates answer 409 naming the code; regression suite 3/3. No migration, no API-contract change beyond the COA error shape.
Version 1.8.186
Unsaved-changes wave 2 (the remaining ~50 P1 hosts) and CRM-2 polish
Completes the platform-wide unsaved-changes programme: every remaining real-gap host from the Phase-0 verified list now carries the shared guard and answers it truthfully — manufacturing, HR, billing/accounts, work-management, CMS/knowledge-base, inventory, library, communication-integrations (typed credential rows guarded by snapshot drift), and the quote-engine shared-projects four-form workspace. Hosts with state beyond reactive forms guard by JSON-snapshot drift or check every bound form. Also lands the CRM-2 polish slice (contact-base regression coverage, toast/analytics/caption fixes) and repairs two route lines the wave-2 wiring had corrupted. No migration.
Platform
Unsaved-changes wave 2 — ~50 hosts, 52 routes: manufacturing (tools, inspection plans, finish specifications, BOMs, work orders, capa, ncr, packages, loading plans with POD-row snapshots, snags, subcontract orders, production pilots, plants, work centres, capabilities, operations); HR (leave requests, TA bills, assets, fleet, job descriptions, offer-letter templates, disciplinary cases, employment documents, statutory masters); billing/accounts (vendors, purchase orders, billing settings' seven always-rendered forms, ledger settings' ten flag-gated forms); work-management (state machines, approvals, stage-gate policies, project detail, documents, programs, portfolios); CMS/KB (forms, navigation, content snippets, KB articles and categories, library pack detail); inventory/platform (warehouses, UoMs, projects list and time entries, performance targets, communication integrations with credential-row snapshots); and the quote-engine shared-projects workspace (four bound forms, three routes).
A 53-assertion coverage contract pins every route+host pair plus the snapshot mechanisms; four stale exact-line pins updated; the release ledger's 1.8.184 entry deduplicated to the stood-down-train record.
CRM
CRM-2 polish: contact-base regression coverage (2/2 against the main-side implementation), toast, analytics and caption fixes.
Fixes
Two route lines (accounts/settings, accounts/ledger/settings) repaired after the wave-2 wiring placed the guard outside the route object with eaten commas — text specs had passed while the app build failed.
Version 1.8.185
Unsaved-changes guards on the Phase-0 Tier A + heavy hosts, CRM batches 4–5, and the pilot-audit P1 fixes
The platform-wide unsaved-changes coverage audit's first fix wave: thirteen routes and thirteen hosts wired with truthful guards — the six salary-structure hosts, payroll policy-packs' 28-control version workspace, machines, the roles permission editor (baseline-compare on the permission set), price-lists, routings' steps editor (snapshot-drift), automations, and purchase indents — each with the beforeunload pair and a 17-assertion coverage contract. Also lands the CRM programme's batches 4–5 (quick-company inline workspace, lead slim-down, form sectioning, label/for sweep across 19 templates with the shared phone-input labelForId), the pilot-audit P1 API fix (lead sub-document stripping order), and two one-character regex repairs that had left the spec runner unparseable. No migration.
Platform
Unsaved-changes guards, Tier A + heavy P1 hosts: hr salary-structure (grades, designations, pay-bands, salary-components, salary-templates, revisions), policy-packs, manufacturing machines and routings, roles, inventory price-lists, work-management automations, and purchase indents — thirteen routes carry the shared guard, thirteen hosts answer truthfully (array editors ride form.dirty; the roles editor compares permission-set drift against an open-snapshot baseline; the routings steps editor against a JSON snapshot; policy-packs' guard is workspace-aware).
Two repointed phone-input regex pins repaired (unterminated literals) and the spec runner parseable again.
CRM
Batch 4: quick-company inline workspace in both lead hosts, qualify panel, quick-lead slim-down, form sectioning, chart-token accents.
Batch 5: label/for associations across 19 CRM templates via the shared phone-input labelForId, with pins re-pointed to attribute-tolerant matching.
Fixes
Pilot-audit P1: lead sub-document values are now stripped before the deep ObjectId/enum strip, so hydrated defaults can no longer store an empty attribution.
Version 1.8.184
Not shipped — the number was consumed by a train that stood down
This number was reserved for the CRM-batches-4+5 release train that stood down mid-cut when a parallel session took the deploy; every change it would have carried (CRM UI batches 4 and 5, the pilot P1 fixes, module-library and email/files work in flight) shipped in 1.8.185 instead. No build with this version number was deployed to any environment.
Note
Recorded so the release history stays contiguous — the version-number gap, not a hidden release.
Version 1.8.183
Module library: the Overview and 2D & 3D views use the design interface's real 3D viewer
The owner's follow-up on the module library's still-grey Overview: both the Overview illustration slot and the 2D & 3D tab now render the quote-engine planning (design) screen's own interactive 3D box viewer — the same component, the same drag-to-turn / scroll-to-zoom / right-drag-to-pan interaction — at the module's stated envelope. Nothing is drawn from unstated facts: a generic type-A sample carcass (18 mm board, grooved back, one shelf, no front) is built at the stated width/depth/height, with captions disclosing that the module's own construction, finishes and hardware are not modelled; unstated sizes keep the 2D illustration and a state-the-sizes pointer. Client-side only; no API, RBAC, route or migration change.
Quote Engine
Module library detail — Overview tab: the flat grey configuration illustration is replaced by the interactive 3D sample carcass whenever all three envelope sizes are stated; the old illustration remains as the fallback with a state-the-sizes hint.
Module library detail — 2D & 3D tab: a 3D view card above the existing 2D views, using planning's own QuoteEngineBox3dComponent (rev 1's settings-cockpit wrapper removed). The viewer's input is memoised per module+sizes so the scene is not rebuilt on every change-detection cycle; three.js stays lazily loaded behind the view.
Three workstreams land together: the CRM module's owner-approved UI programme completes — unsaved-work protection on 21 routes, RBAC-honest action gates, humans-not-ids rendering, and a shared friendly-error mapper swept across 318 call sites; the ERP Sales Quotations direction-D redesign ships as flag-gated shells (detail journey spine, list KPIs, editor wizard, approval decision cards) behind a fail-closed kill switch pre-seeded off; and every page header that lacked a back button gets the shared one (87 templates), with Product Engine's origin-aware back deliberately preserved. No migration.
CRM
Batch 1 — data-loss protection: the unsaved-changes guard on 21 routes / 24 hosts (lead and deal editors, communications, templates, territories, sequences, agents and more), with truthful hasUnsavedChanges() per host.
Batch 2 — RBAC gates and humans-not-ids: actions that would 403 render only with the grant; resolved names everywhere a raw id used to leak.
Batch 3 — friendly errors everywhere: shared friendlyHttpError mapper (connectivity and auth get fixed sentences, the server's own message otherwise, the caller's fallback verbatim) swept across the module, loading states on three lists, surfaced webhook load errors with an accessible retry, 18 aria-labels on icon-only buttons and role=alert banners.
ERP Sales Quotations
Workspace v2 shells behind quotation_workspace_v2_enabled (pre-seeded OFF, fail-closed): detail journey spine over the ten-status lifecycle, list KPI strip computed client-side from the loaded page, three-step editor wizard with control parity between arms, approval-inbox decision cards with ageing and threshold-vs-actual bars — legacy arms byte-identical until the owner flips the flag.
Platform
Back-button parity: 87 page headers that had none now carry the shared app-back-button (browser-history back that preserves filters and scroll); the 24 Product Engine screens keep their origin-aware back by pinned contract; BackButtonComponent is standalone so module-scoped and standalone templates resolve it identically.
Version 1.8.181
The definition libraries become reachable: Module, Dry Home and Bathroom Library join the Quote Engine menu
The three governed definition libraries were live-routed with no navigation entry anywhere — the Module Library was reachable only through contextual links inside family configure screens, and the Dry Home and Bathroom libraries only by typing their URLs. All three now sit beside Panel Library in the Quote Engine menu, each gated on its own read permission. No migration; data unchanged — the seeded definition rows simply become findable.
Quote Engine
Module Library, Dry Home Library and Bathroom Library are first-class Quote Engine menu entries (beside Panel Library), each behind its own read grant — the same own-permission rule the Doors & Millwork rows use, so a quotes-only holder is not shown a library where every request would 403.
Navigation order, count and permission pins in the three nav specs were updated intentionally; every sidebar icon is verified registered.
Version 1.8.180
Application Settings form-safety programme — labels, confirms, guards, and integration test buttons
The owner-approved Application Settings audit fix across four batches: form labels and feedback semantics module-wide, destructive-action confirmations, unsaved-changes guards, per-page refinements including the email placeholder caret fix and the roles keyboard reorder, and three new saved-credential test buttons (SMTP, AI key, GST lookup) with audited, secret-free probe endpoints. No migration; no permission or payload changes outside the new probes.
Application Settings
Batch 1 — form-safety contracts: label/for associations across ~12 screens (ng-select via labelForId, checkbox groups via role=group), role=status/alert banner semantics, 10 destructive actions confirmed through the shared dialog (cancel never calls the API), and unsaved-changes guards on the settings routes; Branding & Theme aggregates all three embedded children and a dirty tab switch confirms before discarding.
Batch 2 — per-page refinements: roles reorder by keyboard sharing drag's persistence, entity-code read-only lock with an explaining banner, release-detail inline errors plus a hotfix-parent picker over the existing releases list, email-template placeholder chips insert at the caret (rich text via a new kit-level insertAtCursor; HTML mode never inserts after closing tags), setup-center scoped step errors and a confirmed danger purge, preview-studio hex validation, connection-checks retry and configure links, and the template-studio version history as a shared modal drawer.
Batch 3 — residuals: base currency is a picker over ISO-4217 codes, business-unit GSTIN/IFSC/MICR optional format validators with uppercase-as-you-type, regional defaults load independently (a country-list failure no longer blocks the saved settings), content-snippet markup warnings, loading states, and an accessibility pass. Browser verification in light/dark at 375px and desktop was performed against a local build.
Batch 4 — integration test buttons (owner-authorized API scope): Test SMTP connection (transport verify, no email sent), per-provider Test key on AI Providers (a free models-list call — nothing is billed, the key is never returned), and a live GSTIN test lookup on GST Verification, each permission-gated to its tier and audit-logged.
Version 1.8.179
B2B workspace v2 shell (flag off), library seeds, and the module library's real 3D tab
Ships the B2B quote workspace v2 journey shell behind a kill switch pre-seeded off, the shared stepper-badge and QR-label kit it needs, dry-home and bathroom reference-library seeds, and the module library's 2D & 3D tab rebuilt on the settings cockpit's own interactive 3D figure. No migration; the one new flag seeds disabled.
Quote Engine
B2B workspace v2, Phases 0–2: a journey spine over the existing tab-and-view URL contract behind the new b2b_workspace_v2_enabled flag. The flag is fail-closed on read (a missing row reads off) and pre-seeded disabled, so every environment keeps the legacy workspace until it is deliberately flipped; the frozen rendered spec passes byte-identical.
Shared kit for the v2 line: ui-stepper gains an optional per-step badge pill, and a new ui-qr-label renders scannable inline-SVG QR codes (qrcode dependency, lazy, MIT).
Dry-home and bathroom reference libraries seed one draft per subtype (seed packs 468/469, insert-only).
The module library's 2D & 3D tab shows the SAME interactive figure Production Configuration shows in settings — drag to turn, scroll to zoom, right-drag to pan, plus an exploded view — built from the module's stated envelope by the standards' own preview builder. Any unstated side keeps the state-the-sizes prompt; the caption says the module's own construction, finishes and hardware are not modelled; the 2D views remain beneath.
Version 1.8.178
+ New offers the ERP quotation editor beside the Quote Engine
The global + New menu's single Quotation item always opened the Quote Engine's furniture workspace for anyone with Quote Engine create rights, so a general (non-furniture) quotation had no top-nav entry. A second item, ERP Quotation, now opens the existing commercial quotation editor and is gated on the same permission trio the ERP list's own New Quotation button checks plus estimation_quotation_v1_enabled — the flag the destination route's guard reads — so it hides rather than bounces wherever the commercial workspace is disabled.
Navigation
The + New menu gains an ERP Quotation item (shortcut E) opening /platform/estimation-quotation/quotations/new for general quotes, beside the existing Quotation item (re-hinted as the furniture Quote Engine flow).
The furniture Quotation item keeps its Sales-estimate fallback for billing-only users; the new item needs quotations create/update/recalculate and hides while estimation_quotation_v1_enabled is off.
Repairs the quick-new spec line left red by 2d497eea6 (Lead route pin still expected /crm/leads/new after the ?quick=1 repoint).
Version 1.8.177
Component-library blind-corner axonometric follows the KC-01 correction
The component library's axonometric view of blind-corner items drew the pre-correction construction (a partial-height blind patch, an open carcass, no filler or door). It now draws the corrected KC-01 construction: a full-height blind panel, the filler, and one door, matching the owner's 2026-10-04 correction to the module image.
Quote Engine
The component library's axonometric drawing of blind-corner items follows the KC-01 correction: full-height blind panel, filler and one door, instead of the pre-correction partial-height patch on an open carcass.
Ships the audited agent-work integration of 2026-10-04: the W3 line's production-configuration and module-library drawings measured onto their approved previews, the design workspace v2 shell behind a kill switch seeded off, panel nesting that resolves material names to PlatformMaterial ids and never nests what it cannot resolve, sales-invoice GST heads written by the model, and the audit's own fixes (a build-blocking palette reference, test-fixture pollution of the public release history, and spec syncs for the redrawn figures).
Quote Engine
Production Configuration illustrations rebuilt to the approved previews: the plinth section and leg layout measured off IMG-00235/00236 (vertical to scale, the set-back axis at the image's own scale, the sample leg where the image places it), the Minifix joint as 064-PC02, the hinged door as 069-PC08, edge-pull options as 031-production, hinge boring as 027-production.
Module Library drawings redrawn to their references (06-upholstery-construction, 07-material-recipe, 16-module-detail, P06-loose-upholstered): the cutaway with its exploded stack and the reference's own tones, the cover layout's chevroned grain arrows, the pedestal's drawer fronts with bar handles, lock and glides, the front elevation's numbered callouts and green cutaway webbing.
The 4x6 package label sizes its injected QR svg itself (the 4x2 fix carried across).
KC-01 blind corner module image corrected to its straight-box construction.
Design Engine
A design workspace v2 shell (Horizon-2 layout: top bar, docked library, object inspector) is served only while the design_workspace_v2_enabled feature flag reads ON. The flag is fail-closed on read and pre-seeded disabled, so every environment keeps the v1 workspace until it is deliberately flipped.
Calculation output checksums record their scheme: new runs hash each part's material, thickness, grain, edge banding and hardware SKU (scheme 2), and historical runs verify under the scheme they were written with.
Panel nesting resolves part material names to PlatformMaterial ids at the boundary and refuses to nest a piece whose material cannot be resolved — reported with the reason instead of cut from whichever board matches its thickness. Guillotine nesting treats material as a hard constraint, never relaxed to thickness alone.
A room type with no finer taxonomy word opens on wall assemblies rather than storage.
Accounts
Sales invoices write each line's CGST/SGST/IGST heads on save, from the document's resolved supply type, so an invoice created by any writer reads back its tax split instead of zeros under a total that includes tax.
Audit fixes (this release's own gate work)
Fixed a build-blocking palette reference in the plinth cabinet illustration (a gradient defined for a palette that never carried its colours; defined but never used, so no pixel changed).
Restored the public release history after a test run bypassing the isolation preload wrote four fixture versions into the tracked file.
Synced the W3 specs to the redrawn figures (plinth section and leg plan, illustration kit, module library) so the suite pins the measured drawings.
Made the merged screens compliant with the UI gates: the workspace v2 and family-stage view switches carry the shared platform icon (the v1 idiom), a raw h-9 input sized h-10, a stale drawer exemption retired (Record receipt is an in-page form now), and the compact tab rails documented as the workspace family's established compact-editor-control pattern. The merge now adds zero new findings to the tab and view-switcher audits.
Aligned three backend tests with merged behaviour: the FnP settlement journey pays through a second actor (the segregation-of-duties guard), the documents marker follows the renamed Identity & compliance heading, and the compliance collector fixture is back-dated so it does not expire with the wall clock.
Version 1.8.175
Purchase, stock and work order fixes
Fixes found walking a purchase from request to production: goods receipts and bills for orders with service lines, blocked stock, closed orders, held work orders, opening stock and plant shift timing.
Purchase
A purchase order that includes a service line, such as board processing from a Quote Engine quote, can now be received and billed.
A closed purchase order can no longer be cancelled.
On your own purchase request, Approve and Reject show as unavailable with the reason, since someone else must decide it.
Inventory
Stock marked blocked can no longer be issued to a work order or transferred out.
Opening stock typed into an existing item now reaches the stock ledger.
The opening stock page no longer says receipts will post in a later step.
Manufacturing
A work order on quality hold cannot be completed past the hold, and a closed work order cannot be reopened.
Shift hours in scheduling follow the plant's own time zone.
Version 1.8.174
Quote to sales order, working invoices and accounts, and steadier Design workspace
Turns an accepted Quote Engine quote into a sales order with an advance request, fixes the blockers found walking a sale from estimate to posted invoice, adds a clearer deal page, and fixes room creation and size checks in the Design workspace.
Sales and Accounts
An accepted Quote Engine quote can be turned into a sales order and a draft advance request in one step, from the quote or from the deal.
A goods invoice with no project now posts, a sales order can be confirmed with its tax details, and a credit note reverses into the right accounts.
An invoice paid by advance now prints as paid, and an unbalanced journal says why instead of failing.
The trial balance shows one net balance per account, the month-end checklist starts with standard items, and bank reconciliation only matches the same account and amount.
The GST Returns period opens on the right date, and a receipt email without mail set up gives a clear message.
CRM deal page
The deal page shows what blocks a quotation, such as missing customer GST status, with a button to fix it.
Log a call, WhatsApp, note, site visit or email from the deal and set the next follow-up date in one place.
Customer card with Call and WhatsApp buttons, and a Still to do list.
Quote Engine
Shutter and carcass boards added to a quote are now counted for the cut list, so parts are no longer left unplaced.
B2B quotes can edit customer type, GST status and your company details while a draft is open.
Drawing labels fit in DXF and PDF exports, and part labels print on one page.
Design workspace
Creating a room no longer shows a false failure.
A cabinet size outside the library's range is refused with the allowed range shown.
Check design runs every check and the header says Not checked until it has, and a door overlapping a cabinet is reported.
Developer wording is hidden from normal users.
WhatsApp support
The WhatsApp workspace fills the page, and Open in WhatsApp opens the installed Desktop app, with WhatsApp Web as a fallback.
Version 1.8.173
Sales Today page, simpler deals, opportunity flow by type and quotes you can issue
Adds a Today page and a global New button for sales, a table-first Deals list with saved views and bulk actions, a deal page that follows the opportunity type, a compact process-flow band across the app, forgot-password on the login page, and fixes that let a Quote Engine quote be issued and printed cleanly.
Sales and CRM
A new Today page lists what needs you now: overdue follow-ups, appointments, demos, quotes awaiting a reply and your pipeline, with one-tap call, WhatsApp, done and snooze.
A global New button creates a lead, deal, follow-up, quotation or customer from anywhere, with keyboard shortcuts.
Sales users see a shorter CRM tab row: Today, Leads, Deals, Follow-ups, Quotations and Customers, with the rest under More. Other roles see the same tabs as before.
The Deals list leads with the table: saved views (My open deals, Stuck over 7 days, Quotes sent, Won), filter chips, a Log action on each row and bulk assign, change stage and follow-up.
The deal page shows the stages for its opportunity type. A B2B cabinetry deal goes Enquiry, Quotation sent, Negotiation, Order confirmed, with no Demo or Trial.
The deal page offers one clear next action, such as creating the customer or issuing a quotation, and lists quotes raised for the deal.
Follow-ups, Appointments and Scheduled Demos are in the main CRM tab row.
Quote Engine
Saving a quote no longer fails on a retired markup setting.
A quote can be issued from the screen: set the customer type and GST status and your company details on the quote.
The proposal PDF has correct page numbers and no blank page, a proper title, and readable labels on elevation drawings.
Quotes created from a deal remember which deal they came from.
Across the app
Process flows share one compact band that matches the Prospect Pool look.
Every create and edit form uses the main header and footer and opens inline.
The login page offers Forgot password for active accounts and asks whether to send the link to your work or personal email.
Pages behind a switched-off feature now say so instead of sending you Home silently.
Back returns to the dashboard when a page was opened directly.
Purchase orders and tax exceptions explain why you cannot approve something you submitted.
Entity Code Settings opens quickly instead of freezing the page.
Version 1.8.172
Wave 3 screen parity, Product Library second wave and Price Master import
Rebuilds many Quote Engine, Design Engine, Product Library and Amendment 03 delivery screens to their approved images, adds the Price Master workbook import and compact engine navigation, and fixes a set of phone layout and pricing-display issues.
Quote Engine
Production Configuration lift-fittings method tables, the dry-home definition editor, finishes and catalogue imports, the CNC handle library, B2B quick order and the quote journey gateway follow their approved screens more closely.
Office and loose-furniture configuration, the office drawing package and the furniture review table are rebuilt to the reference layouts, including drawing sheets, schedules and a review PDF.
Configure door set now leads with the Opening and leaf drawing card, as the approved image shows.
Price Master workbooks can be imported through a governed import with review before anything is applied.
The engine navigation is more compact, and the hardware and shade libraries are searchable.
Unpriced lines and libraries now read 'Not priced' instead of showing a fabricated 0.00.
Design Engine
The workspace Furniture screen shows the home stage the reference draws: room view, layer checklist and a furniture palette along the bottom.
The workspace presentation layer and the whole-home furniture stage were rebuilt toward the approved concepts.
Product Library
Second-wave screens for overview, product tabs, categories, attributes, recipes, duplicate review and supplier offers.
Components can show a read-only verification of their computed attributes; a value that cannot be computed says so instead of showing zero.
Attribute definitions can carry a stated default value.
Manufacturing and delivery
Release readiness, production package handoff, work order (including a phone view with the assigned team and the work centre's safety brief), dispatch and loading, production closure, customer acceptance, installation and warranty screens follow the Amendment 03 references.
Platform
Phone layout fixes: CRM menus stay on screen, tables and chips no longer clip, empty selects show their placeholder.
Inviting a staff member to the customer portal no longer fails with a server error.
Test uploads no longer land inside the application source.
Version 1.8.171
Manufacturing record links, Hettich hinge photos and test-gate fixes
Adds one-click record and manifest views to the Manufacturing lists, shows recorded proofs of delivery on a loading plan, seeds product photos for a first batch of Hettich concealed hinges, and fixes a Files switch that was never created on a fresh install.
Manufacturing
Nonconformance and corrective-action lists now have a Record button, and the Packages list has a Manifest button. Each opens the stored record or manifest in a preview window without changing anything.
A loading plan now lists its recorded proofs of delivery, and each one opens its delivery record.
Quote Engine
A first batch of 28 Hettich concealed hinges now carries real product photos, in both the inventory item picker and customer documents. Photos are only added where none exists, so an image you have changed or retired is never put back.
Platform
The Files on/off switch is now created (switched off) when the system starts, instead of being missing on installs that never ran the extra seeding step. Where the switch was missing, Files will be switched off at the next start until it is turned on deliberately.
A duplicate-shortcut error when saving a WhatsApp reply template now shows the server's real message instead of a generic one.
Version 1.8.170
Shade library search, hardware fitting families and Quote Engine hardening
Adds the shade library editor and search, hardware fitting families and a batch of Design Engine drawing fixes. Panel-definition and rate-builder inputs are now read strictly so a blank is never priced as zero, the personal light or dark choice made in the Design workspace now carries over to the rest of the app, and several tab and control layouts were brought in line with the shared design rules.
Design Engine
Drawing workspace fixes: corner-return faces, wardrobe key heights, the drawer datum, front operations, dimension labels, the drawing-entity inventory and site projection.
Switching between light and dark in the Design workspace now updates the rest of the app straight away, and a late response from the server can no longer switch the theme back over a choice you have just made.
Quote Engine
Shade library: a shade editor and a search over shades, backed by a governed shade taxonomy.
Hardware fitting families and their dimension attributes can now be linked to library hardware.
Panel definition and rate builder inputs are read strictly: a blank wastage, processing rate, allowance, sheet cost or markup is treated as not stated instead of being priced as a real zero. The Panel Library wizard no longer lets you skip past incomplete steps, and the Columns menu no longer keeps a stale heading after the Type filter is cleared.
Sharing a panel price list now checks the link lifetime before creating the file, so an out-of-range lifetime is refused cleanly instead of failing after the file was created.
Quote tabs across the furniture families now carry icons, and the Pricing view, Drawer configuration, Sliding door configuration and Shade library section tabs use the same tab behaviour as the rest of the app.
CRM
The exception-queue tiles on the CRM Overview now open the matching lead list instead of returning to the home page.
Manufacturing
The Priority choice when simulating a work order's capacity plan is now a standard dropdown.
Version 1.8.169
Wall Panelling form, dry-home catalogue entry and more audit fixes
Adds the Wall Panelling configure form as the sixth saved-but-unpriced family, restores the dry-home family to the product library so the library seed and its test suites run again, and lands further independent-audit fixes to family settings, saved-family lists and drawer and lift fittings input handling.
Quote Engine
New Wall Panelling configure form on a quote: project objects, a five-layer wall finish zone, finish, backing and batten properties, panelization and cutouts. It is saved but not priced, like the other newer families. Calculate is disabled with its reason, and the CAD planning and Drawing review tabs are shown as planned.
A saved family list that is not actually a list (a string, number or object) used to read as no items, so the family vanished from the quote and from the issue check. It is now refused when the quote is created or saved, flagged in the calculation and blocked at issue.
Drawer and lift fittings input is checked properly: blank or non-numeric values are no longer stored as 0, an unknown profile kind or lift type is no longer silently replaced by a default, and a lift chosen for a non-numeric weight is refused instead of appearing fitted.
Product library
The Dry Home Storage family now has a visibly planned placeholder entry in the product library catalogue. It carries no configuration, rate or dimension and is not operational. Without it the library seed refused to run, because the family was declared but absent.
Manufacturing
Installation and handover records read more safely: malformed ids, refused handovers and cancelled visits no longer produce a false warranty start or installation status, and an empty issued-item list no longer passes the installation gate.
Acceptance evidence for the production-dispatch phase was corrected to match the code.
Version 1.8.168
Whole-home family completion, audit-found fixes and a repaired build
Completes the whole-home family bands (office, bathroom, doorsets, uPVC), closes the A03 manufacturing report set, and lands the fixes an independent audit found in the Quote Engine library, import and shade modules. Main's front-end build, which had been failing to compile since 23 September, builds again.
Build and checkpoint
The front-end build compiles again. Duplicated code blocks pasted into the Design Engine service and workspace, and a duplicate identifier in the Doors & Millwork BOM view, had stopped every front-end spec and build.
New end-to-end checkpoint test for the Quote Engine library: discovery, create, price, import rates, reopen and refusal paths across the accepted modules.
Whole-home families
Office accessories and quantity basis, bathroom placement and quote acceptance, doorset quote outputs, and uPVC system facts, placement, fabrication rules and acceptance. Every family still refuses to quote until qualified manufacturer data exists.
Products & Fittings hub gains the configuration navigation groups.
Regenerated the family-reprint goldens and wired per-collection carcass board formats, which the carcass branch had silently dropped.
Fixes found by the independent audit
A profile door with an unstated glass insertion or clearance was sized as if it were a stated zero, which fed real quote prices. It now reports the gap.
Library import no longer re-kinds or re-activates existing items, or accepts wrongly typed fields. Panel CSV import refuses unreadable numbers, repeated codes and malformed files instead of silently applying them.
Fabric and leather yield rules are now detected by meaning rather than three literal spellings. New quotes can no longer carry a forged dimension approval.
Shade library: malformed references, unsourced exact matches and bad costs no longer verify; a blank profile member fact is no longer stored as 0 mm; concurrent first saves no longer fail with a server error.
uPVC family reconciliation partitions records by the catalogue's own phase tag instead of matching text.
Custom material and upholstery registers now recognise phrasing such as "No frame specified" as a missing fact.
Manufacturing
Acceptance evidence record for the A03-03 production-dispatch phase.
Version 1.8.167
Door Sets and five new furniture families in the Quote Engine
The Quote Engine can now save Door Sets and five furniture families that were not buildable before: Bathroom furniture, Beds, Office workstations, Loose furniture and uPVC openings. Each has its own form opened from the quote's Doorsets tab. These items are saved with their stated sizes and options but are not priced yet, and the quote says so plainly; a quote holding unpriced family items cannot be issued until they are priced or removed. The B2B quote footer now shows the five approved cost buckets and the Production details panel has Cut list, Board plan and Analytics tabs. The planner shows a slope's net and blank front-profile area. Panel CSV import now refuses unreadable numbers, duplicate codes and malformed files.
Added
Door Set configure form (Product, Dimensions & frame, Finishes, Hardware, Pricing, Assets) opened from the Doorsets tab.
Save-now forms for Bathroom furniture, Beds, Office workstations, Loose furniture and uPVC openings; unstated numbers stay blank rather than zero and each family reports that it is not yet quotable.
Furniture families card on the Doorsets tab with Add, Configure and Remove.
Slope front-profile net and blank area readout in the planner.
B2B quote footer buckets and Production details tabs (Cut list, Board plan, Analytics).
Changed
Issuing a quote is refused while it holds unpriced family items, with a message naming them.
Panel CSV import refuses unreadable numbers, duplicate codes and malformed files instead of importing them.
Version 1.8.166
HR module dropdown and breadcrumb fixes
A full click-through of every HR screen found that filter and "select an employee/department/etc." dropdowns across roughly two dozen HR pages were rendering blank with a stray clear icon instead of their placeholder text ("All statuses", "Select a department..."), because the dropdown's starting value didn't match anything in its own list. Every one of those dropdowns is fixed. A few page breadcrumbs that read "Hr" instead of "HR", and garbled initials on the Organization Chart for names ending in "(Test)", are fixed as well.
Fixed
Dozens of filter and picker dropdowns across HR now show their placeholder ("All statuses", "Filter by employee...", "Select a department...", etc.) instead of a blank box with a stray clear icon — affected screens include Leave Requests, Payroll, Attendance, Employee Operations (salary advances, RACI, access control), Recruitment (Requisitions, Interviews, Pipeline, Assessments, Job Postings, Candidates), Benefits, Bonuses, Increments, Timesheets, Resignations, TA Bills, Onboarding, Offer Letters, Employment Documents, Disciplinary Cases, Move-Out Requests, Temporary Move-Outs, Attendance Regularizations, Fleet Tracker, and Performance (Cycles, Goals, Reviews, Appraisals).
TA Bills and Employee Operations now show "HR" correctly in their breadcrumb trail instead of "Hr"; the Offer Letter print page now shows a full breadcrumb trail instead of none.
Organization Chart avatar initials no longer garble for names ending in "(Test)" (e.g. showed "A(" instead of "AT").
Version 1.8.165
Catch-up release: whole-home family slices (G01/G03.x/OD-13) + two audit-found fixes
A batch of 47 commits landed directly on main over the prior day without going through the normal audit-before-merge pipeline (no PR, no independent review, no release cut). This release is the catch-up: every commit has now been independently re-audited retroactively, two real defects were found and fixed, and one infrastructure blocker was cleared.
Whole-home family and vocabulary work (independently re-audited)
G01-S26 checkpoint slice and the OD-13 foundational vocabulary, both re-verified sound (G01-S26's own commit proactively fixed a MongoDB-5.0-only query form the pilot host's older MongoDB can't run).
Dry-home family continuation (G03.1-S03/S04) — re-verified sound; S03 shipped with two extra guards beyond its own frozen draft.
Bathroom/utility family extension (G03.2-S02) — re-verified sound; its union onto the shared canonical-library file confirmed purely additive.
Office/retail family extension (G03.3-S02/S04) — re-verified sound; confirmed no collision with OD-13's shared vocabulary file.
Beds family (G03.4-S02/S03/S04) — re-verified sound; S03/S04 shipped as genuine rewrites that closed real gaps a draft version had (invalid fixtures could have been placed; a mesh-reuse check across fixtures was missing).
Doorsets family (G03.5-S02/S03) — re-verified sound; pricing-preservation and fitting-schedule claims independently re-derived from source data, not just re-run.
Loose/upholstered furniture family (G03.6-S02/S03/S04/S05/S06) — re-verified; see defects below.
Defects found during the retroactive audit and fixed
Custom timber/metal material register (looseCustomMaterials.js): a negation-detection gap let prose like "No species specified." be misread as stating a positive fact, so a record where nothing was known about a required material fact could be reconciled as fully qualified instead of held. Fixed and covered by a new regression test.
The identical copy-pasted gap in the upholstery material register (looseUpholstery.js), found via the first fix's own follow-up flag and fixed the same way, with its own regression test.
Infrastructure
Fixed the frontend test runner (node scripts/test-frontend.js), which an unrelated commit had left completely unable to start because a new spec file wasn't registered in its accounting list.
Version 1.8.164
NCR/CAPA record seams (A03-R07, G04-S03 r8) — last A03-03 report exposure
Two thin, read-only HTTP seams wiring the already-merged NCR/CAPA renderer (G04-S03 r5, 1.8.161) to routes: GET /nonconformance-reports/:id/record and GET /corrective-actions/:id/record. Each route checks its own surface's read permission. This is the last A03-03 report exposure — every A03-03 report now has an endpoint (R06 stays deliberately gated by design; R07/R08/R09 are all now exposed). Audit independently re-verified the centerpiece claim — that the CAPA integrity-warning path (closed without effectiveness evidence) survives the HTTP boundary byte-identical to the underlying renderer's own output — with an adversarial fixture distinct from the shipped test, plus a negative control confirming the warning is not always-on. No code defects found.
Manufacturing
New: GET /nonconformance-reports/:id/record (permission platform_manufacturing.nonconformance_reports.read) returns the NCR record HTML from the already-merged a03NcrCapaRecordReport.service.js#renderNcrRecord (1.8.161) verbatim via res.type('text/html').send(out.html) — no re-wrapping or re-escaping. Status prints as the recorded service state, never inferred from closedAt.
New: GET /corrective-actions/:id/record (permission platform_manufacturing.corrective_actions.read) returns the CAPA record HTML from a03NcrCapaRecordReport.service.js#renderCapaRecord (1.8.161), same raw-passthrough pattern — the integrity-warning path travels intact over HTTP.
Both handlers named recordReport in their respective controller object literals, applying the G04-S03-r6 name-collision lesson proactively (that slice's own audit found a handler named record silently overriding an existing key in the same object literal). Independently re-parsed both touched object literals (nonconformanceReports: 7 keys, correctiveActions: 12 keys) for duplicate top-level keys after the diff: none found. recordReport now occurs 3 times repo-wide (proofOfDelivery's from r6/1.8.162, plus these two) — grepped and confirmed; no other short/generic name collision found in either object.
Cross-permission isolation, both directions, independently re-verified with a fresh adversarial script (separate from the shipped test): an NCR-only reader gets 403 on the CAPA record endpoint and a CAPA-only reader gets 403 on the NCR record endpoint, using freshly created users/roles/tokens, not the shipped fixtures.
**The centerpiece claim — the CAPA integrity-warning path survives the HTTP boundary intact — independently and adversarially re-verified beyond the shipped test.** Built an independent closed-without-effectiveness-evidence CAPA fixture with different title/problem text than the shipped test, hit the real HTTP endpoint, and confirmed both the INTEGRITY WARNING text and the 'no effectiveness review' text are present. Went further than presence: asserted the HTTP response body is byte-identical to calling the underlying renderer service directly (only the render-time 'Generated ...' timestamp footer excluded from the comparison), proving the seam does not re-wrap, truncate, double-escape or otherwise soften the renderer's own output. Added a negative control absent from the shipped test — a closed CAPA WITH effectiveness evidence — and confirmed it does NOT show the integrity warning, ruling out an always-on warning that would trivially pass the positive assertion.
Read-only/no-side-effects (byte-stable documents across GETs) and 404-by-statusCode for unknown ids re-confirmed over real HTTP on both seams with fresh random ObjectIds, independent of the shipped fixtures.
Confirmed GET-only wiring: each new path has exactly one route (GET), grepped for POST/PUT/PATCH/DELETE on both paths — none found. Confirmed the diff is exactly the claimed shape: 2 files, 15 lines (11 controller + 4 routes), no existing key touched, no migration needed or added (pure route/controller wiring over an already-audited, already-merged renderer).
Fresh verification, ported to a dedicated worktree off the true origin/main tip (node_modules reused via directory junction from the audited source worktree — package-lock.json and package.json byte-identical): shipped test 6/6 pass; the six-suite battery (a03-ncr-capa-seams-http, a03-ncr-capa-record, a03-closure-seams-http, a03-pod-record, a03-package-manifest, mp06-quality-ncr) 54/54 pass, 0 fail; `npm run lint` — Syntax OK (5657 files).
No code defects found. G04-S03 is now complete for Tasks 1, 2 and 4 — only Task 3 (evidence JSON, acceptance-time) and Task 5 (PC-01..13 UI surface links to these records) remain open, both already disclosed as deliberately deferred scope, not defects.
Version 1.8.163
Production-closure panel in work-order detail (A03-03 Task 2, G04-S03 r7)
A new read-only "Production closure" card in the work-order detail surface, below the existing Factory-handoff card, consuming the already-merged GET /work-orders/:id/closure projection (G04-S03 r1+r6). Shows the closure-four rows (quality/packages/delivery/actualCost) verbatim from the reconciliation chain with icon+text+colour, a whole-chain reconciled/mismatch banner that teaches the statuses-vs-reconciled distinction explicitly, and a footer distinguishing pending (mid-flight) from not-applicable/not-linked (statements, never passes). Applies the G04-S02-r7 permission-gate lesson structurally: the card frame and the computed denial line render ungated; only the data section branches on load state. Audit independently re-verified every claim live in a dedicated API+Angular instance (including an adversarial mutation test and a direct DOM-state simulation of the restricted-permission path) and found no code defects.
Manufacturing
New: "Production closure" card in PlatformWorkOrderDetailComponent, reading GET /work-orders/:id/closure (already live since 1.8.162/G04-S03 r6). Pure read, no lifecycle actions on the card (zero (click) handlers in its template subtree, grepped and confirmed).
The closure-four rows (Quality/NCRs, Packages, Delivery, Actual cost) render status verbatim from the reconciliation chain's own vocabulary (ok/mismatch/pending/not_applicable/not_linked), each with a distinct icon, label and colour — not_applicable and not_linked are rendered as neutral/muted statements, never with the same green treatment as ok. Verified live with a real not_applicable actualCost row (no stock-controlled components): rendered with a distinct info icon and muted-grey "Not applicable" label beside the green "OK" rows.
The statuses-vs-reconciled distinction — the semantic the G04-S03 r1 backend audit established (that all four visible rows reading clean does not imply the whole chain reconciles, since `reconciled` also covers design links, labels and routing) — is stated on the card itself via a green/warning banner keyed strictly off `closure.reconciled`, never off the four visible rows. Verified live with a purpose-built fixture where quality/packages/delivery/actualCost all read "OK" but the chain does not reconcile (an unlabelled package breaks the `labels` link, which is outside the closure-four): the card correctly shows the warning banner ("The chain reports mismatches..."), not the green one.
Permission-gate lesson (G04-S02-r7) applied structurally: read the shipped template directly and confirmed no `@if (closureVisible)` wraps the card frame anywhere — only the data section (rows/banners/footer) branches on load state; the card heading, description and the computed denial line ("Production-closure status is not visible to you.") always have a template path. Verified two ways beyond source review: (1) an adversarial mutation test — temporarily re-wrapped the card in `@if (closureVisible)` and confirmed the shipped closure-ui.contract.spec.ts spec fails exactly as the HANDOFF predicted, proving the spec has real teeth; (2) a live DOM-state simulation (Angular's `ng.getComponent`/`ng.applyChanges` devtools API) reproducing the exact state `loadClosure()` sets when the permission check fails, confirmed the card frame and denial line render correctly, not an empty gap. (A true restricted-user browser session could not independently exercise this path, because the backend gates GET /work-orders/:id/closure on the identical permission — platform_manufacturing.work_orders.read — as the base work-order record fetch itself, so a user lacking it never reaches the page at all; this mirrors the already-audited r1/r6 backend contract and is not a defect in this slice.)
Footer states chain-complete/not-complete plus link count, with explicit copy distinguishing pending (mid-flight, not broken) from not-applicable/not-linked (statements, never passes) — verified live, exact text match.
Load-failure isolation: `closureError` renders in its own `role="alert"` element; the error handler in `loadClosure()` touches only closureLoading/closureError/closure, never the page's own loading/loadError/workOrder state, matching the same isolation pattern already verified for the sibling Factory-handoff card.
One disclosed build-time fix, independently confirmed not to paper over a real type mismatch: `counts?.['total']` uses bracket-notation index-signature access (ClosureProjection.counts is `Record<string, number>`) — `ng build platform` compiles clean (EXIT 0); the only related diagnostic is a cosmetic NG8107 redundant-optional-chaining warning, not a type error.
Full FE gate (`node scripts/test-frontend.js`) re-run fresh on a clean port of this slice onto the true `origin/main` tip: exactly the same 3 pre-existing failures already independently corroborated by two prior audits today (a release-history version-window assertion and two Panel Library S08-P0-08 field checks), none attributable to this change. No migration needed (pure frontend UI consuming an already-wired endpoint).
Three thin, read-only HTTP seams wiring already-merged, already-audited services to routes: GET /work-orders/:id/closure (JSON closure-four projection, the Task 2 closure panel's future data source), GET /packages/:id/manifest (A03-R08 manifest HTML), GET /proof-of-delivery/:id/record (A03-R09 POD record HTML). Each route checks its own surface's read permission, deliberately not a shared dashboard permission. Audit independently completed the 3x3 cross-permission matrix (the shipped suite covered 3 of 6 cross pairs) and confirmed all 9 cells behave correctly. No code defects found.
Manufacturing
New: GET /work-orders/:id/closure (permission platform_manufacturing.work_orders.read) returns the closure-four projection (quality/packages/delivery/actualCost + reconciled/chainComplete/counts) from the already-merged productionClosureProjection.service.js#closureProjection (1.8.156). Pure read, JSON response.
New: GET /packages/:id/manifest (permission platform_manufacturing.packages.read) returns the A03-R08 manifest HTML from the already-merged a03PackageManifestReport.service.js#renderPackageManifest (1.8.159), sent verbatim via res.type('text/html').send(out.html) with no re-wrapping or re-escaping.
New: GET /proof-of-delivery/:id/record (permission platform_manufacturing.proof_of_delivery.read) returns the A03-R09 POD record HTML from the already-merged a03PodRecordReport.service.js#renderPodRecord (1.8.160), same raw-passthrough pattern. Named recordReport in the controller object literal because the existing key record is the POST-create handler for proof-of-delivery — the shipped code already applied this lesson (a same-key collision caught during the slice's own development, disclosed in its HANDOFF); independently re-parsed the controller's three touched object literals (workOrders/packages/proofOfDelivery, 13+9+4=26 top-level keys) and confirmed no other key collision is lurking.
Independently re-verified beyond the shipped 7-test suite, over real HTTP (loopback-bound server, not app-level supertest): the FULL 3x3 cross-permission matrix. The shipped test covered only 3 of the 6 cross pairs (wo-reader on manifest, pkg-reader on closure, pkg-reader on POD); added and confirmed the missing 3 (pod-reader on closure, pod-reader on manifest, wo-reader on POD) — all 403, and re-confirmed all 3 own-key pairs still 200. These 3 assertions were folded into the shipped test file itself (a03-closure-seams-http.test.js) rather than kept as a separate audit-only script, closing the gap the HANDOFF explicitly flagged ('verify one more pair of your own if you want the matrix complete') for any future run of this suite.
Independently re-verified 404-not-500 on unknown ids for all three routes directly over real HTTP (the r1 lesson: a plain Error falls through the global handler to 500; all three underlying services already throw ApiError(404, ...) and express-async-handler correctly propagates it to the error middleware, which maps .statusCode to the response — confirmed end to end, not assumed from the service code alone).
Independently re-verified read-only/no-side-effects via double/triple GET against all three surfaces (WorkOrder, Package, POD) — the shipped test checked WorkOrder and Package only; added a POD updatedAt-stability + document-count assertion (folded into the shipped test's read-only subtest) since the shipped suite had not exercised POD's own read-only stability.
Confirmed GET-only wiring (grepped the routes file for all three new paths: zero POST/PUT/PATCH/DELETE) and confirmed the diff is exactly the manifest's claimed shape: 2 files, 25 lines (18 controller + 7 routes), nothing else touched. No migration needed or added (pure route/controller wiring; `git ls-tree` confirms the true next-free migration number is unaffected).
Version 1.8.161
NCR/CAPA record renderer (A03-R07, G04-S03 r5)
A pure, read-only HTML renderer over the real NonconformanceReport and PlatformCorrectiveActionReport documents implementing REPORT-CONTRACTS.md §A03-R07. Status prints as the recorded service state, never inferred from closedAt. A CAPA whose status says closed while carrying zero effectiveness reviews renders a loud INTEGRITY WARNING instead of silently choosing a side; open actions on an otherwise-closed CAPA are counted and shown, not hidden. Cost fields are omitted with 'cost not recorded' rather than printing a fabricated zero. Closes out Task 4's full report set (R06 stays deliberately gated).
Manufacturing
New: a03NcrCapaRecordReport.service.js#renderNcrRecord(ncrId)/renderCapaRecord(capaId) (A03-R07, G04-S03 r5) — the NCR half prints stage/description/containment verbatim, disposition with approving authority and notes, remake batch and affected orders, root cause ('— not analysed yet' when absent) and responsibility, status as the recorded service state (never inferred from closedAt), cost omitted as 'cost not recorded' when the model-default zero holds, and linked CAPAs. The CAPA half prints problem statement, root-cause analysis and category, actions with owner/due/status, effectiveness reviews (verdict verbatim, 'recurrence OBSERVED/NOT observed', before/after NCR counts), and linked NCRs (the many-to-one the model exists for, printed both directions). A CAPA whose status says closed with zero effectiveness reviews renders an explicit INTEGRITY WARNING reporting the disagreement rather than resolving it either way; an open action on a closed CAPA is counted and shown. Unknown id throws ApiError(404) by statusCode (the G04-S03-r1 audit lesson). Independently re-verified beyond the shipped 11-test suite: a third NCR status ('dispositioned'/'contained', not just 'open') with closedAt set stays unclosed on paper; a closed CAPA with a not_effective review (evidence present but unfavourable) does not spuriously fire the integrity warning; an in_progress (not just 'open') action on a closed CAPA is counted; materialCost/labourCost schema paths default to 0 with no null sentinel, so a genuinely-recorded zero is bit-for-bit indistinguishable from the unset default — confirmed directly against the schema rather than assumed. Mechanically confirmed read-only (14-verb scan) and unwired (no route/controller). Backend service only; no route, controller or UI in this release.
Version 1.8.160
Proof-of-delivery record renderer (A03-R09, G04-S03 r4)
A pure, read-only HTML renderer for the signed PlatformProofOfDelivery record (REPORT-CONTRACTS.md A03-R09): every field verbatim, the recorded outcome never recomputed, the delivery challan a link only (never a substitute for POD detail), evidence rows by reference only, and a banner stating a correction is a new POD, never an edit. Unknown id throws ApiError(404). No route or UI ships in this release.
Manufacturing
New: a03PodRecordReport.service.js#renderPodRecord(podId) — a pure HTML render over the real PlatformProofOfDelivery document (A03-R09, G04-S03 Task 4). Every field prints verbatim; line conditions (ok/damaged/missing/short) print with expected/received quantities and notes — the discrepancy is the finding, never smoothed. The outcome prints as the recorded, service-derived value and is never recomputed by the render (independently re-verified beyond the shipped suite with an outcome='failed' fixture whose lines are all 'ok': the render still prints 'failed' verbatim, never upgrades to 'complete' or infers 'ok'). The delivery challan prints as a reference/link only — confirmed the renderer never populates or displays challan line/quantity data itself — with explicit text stating challan acceptance is not a substitute for POD detail, since the two are deliberately allowed to disagree. Evidence rows print kind/reference/captured-at/notes (storage references only; confirmed no base64/buffer/binary handling in the module). Unknown id throws ApiError(404), asserted by both instanceof ApiError and statusCode === 404. Double- and triple-read fixtures confirm the underlying document's updatedAt stays byte-stable (no side effects). Mechanically confirmed read-only against the hardened 14-verb list, and confirmed not imported by any route or controller (route + dispatch-surface link deliberately deferred). HTML-escaping independently re-verified across every user-sourced field (recipient name/relationship/contact, package number, line notes, evidence kind/reference/notes, discrepancy notes), not only the shipped suite's single discrepancyNotes case. Backend service only; no route, controller or UI in this release.
Version 1.8.159
Package manifest renderer (A03-R08, G04-S03 r3)
A pure, read-only HTML renderer over the real PlatformPackage document implementing the A03-R08 package manifest contract. Only verified package content lines render as manifest content; unverified lines are named and excluded, never printed as if shipped. A package with zero verified content renders as a package RECORD carrying a "NOT A DISPATCHABLE MANIFEST" banner. Dimensions and weight print only when actually recorded, distinguishing a genuinely recorded zero from an unset field. The package number carries an explicit identity note stating it is not an SSCC and naming the GS1 Company Prefix / allocation requirement this system does not have. No route or UI ships in this release.
Manufacturing
New: a03PackageManifestReport.service.js#renderPackageManifest(packageId) — a pure HTML renderer over the real PlatformPackage document implementing REPORT-CONTRACTS.md §A03-R08 (A03-03 Task 4). Verified content lines print as manifest content (description/type/qty/verified-at); unverified lines are named and excluded ("N line(s) UNVERIFIED — excluded from the manifest"). A package with zero verified content renders as a RECORD with a not-a-manifest banner. Custody events print verbatim; fragility/orientation/protection/crate identity print when meaningful; loading sequence and challan linkage print only when actually present; packing instructions and every user-sourced field are HTML-escaped. The package number carries an explicit "not an SSCC" note naming the GS1 Company Prefix/allocation-and-check-digit process this system does not have — no SSCC digits or GS1 fields anywhere in the output. An unknown package id throws ApiError(404). Mechanically confirmed write-free (14-verb scan) and unwired from any route — the HTTP seam is deferred to a later revision, matching the established pattern for this report band.
Version 1.8.158
Inspection-candidate dry-run planner (A03-03 Task 4 first half, G04-S03 r2)
A pure, read-only planner returning the three draft-only inspection candidates (incoming/in-process/final) with every required characteristic fact (method, target, tolerance, sample policy, instrument, responsible role) left null/unresolved and named in a per-candidate unresolved list. No InspectionPlan document is ever created, and the advisory qualityTrigger evaluator is untouched (complete non-interference). No route or UI ships in this release.
Manufacturing
New: a03InspectionCandidatePlan.service.js#planInspectionCandidates() — a dry-run planner over frozen planning data implementing the InspectionCandidate contract (A03-03 Task 4, first half): three draft-only candidates A03-QA-INCOMING/A03-QA-INPROCESS/A03-QA-FINAL at stages incoming/in_process/final, each with characteristics whose method/target/tolerance are always null and an unresolved array naming every owner fact still pending (method, target/tolerance, sample policy, instrument, responsible role). status is structurally always 'draft' — the planner has no branch that can emit anything else. Mechanically confirmed read-only (no write-verb calls) and confirmed to create zero InspectionPlan documents across repeated runs, both before the first call and after each of several repeated calls. No executable reference to the advisory qualityTrigger evaluator anywhere in the module (preserved by non-interference, not just by convention). Backend service only; no route, controller or UI in this release. One editorial choice — the three per-stage characteristic-name sets — is this slice's own framing and is called out for owner confirmation, not resolved here.
Version 1.8.157
Factory-handoff cross-link in work-order detail (A03-02 Task 5, G04-S02 r7)
A read-only "Factory handoff" card in the Work Order detail screen: which immutable design release the order's BOM traces to (recorded vs reconstructed vs unlinked), BOM coverage, the pinned routing revision, label status, live readiness, and a "Route traveller" button that previews the already-merged A03-R05 route traveller in the app's own preview modal. Consumes only already-merged endpoints; no new backend behaviour ships in this release.
Manufacturing
New: a "Factory handoff" card on PlatformWorkOrderDetailComponent (FH-01/FH-05), permission-gated on platform_manufacturing.design_links.read BEFORE the request fires. Shows the design-bridge linkage (reconstructed links visibly warning-tinted, never read as recorded), BOM coverage, the pinned routing revision id, label status from the reconciliation chain's own rule, a readiness summary ("N dimension(s) not assessable — never counted as passing"), and skipped design-line reasons behind a progressive disclosure. Read-only cross-link only — no lifecycle action lives on the card.
New: PlatformManufacturingService#factoryHandoff(workOrderId) and #workOrderTraveller(id), plus the FactoryHandoffProjection type mirroring the audited backend shape (api/src/services/platform/factoryHandoffProjection.service.js, merged 1.8.150).
"Route traveller" previews the A03-R05 traveller (merged 1.8.155) via DocumentPreviewService.previewBlob(..., 'html') — the app's sanctioned in-modal preview path, never window.open/URL.createObjectURL. Live-verified end to end against a seeded work order with a real released routing revision: the traveller HTML renders in the preview modal (200 OK, no console errors). The degraded case (a work order with no routing) renders the traveller's own honest "TRAVELLER UNAVAILABLE" copy in the same modal, never a broken button.
Audit fix: the card's frame — including the permission-denied "not visible to you" line the component already computed — was gated behind the same visibility check as its contents, so a viewer without design_links.read saw no card at all rather than the honest message (the same failure class the linked-records rail's own header comment names: a computed error state that renders nowhere). The frame and its permission message now always render; only the action button and the projection body stay gated. Live-verified with a restricted test role: the honest line renders and zero network requests reach the factory-handoff endpoint.
Live-verified projection-failure isolation: a simulated failure on the factory-handoff endpoint leaves the card showing its own isolated error line while Details, the readiness rail, linked records and Next action keep rendering normally — confirmed via a network-level fault injection, not source review alone.
A read-only, four-fact view of the reconciliation chain (quality, packages, delivery, actual cost) for screens that need exactly those closure facts, without the whole thirteen-link report. Every value is copied verbatim from the existing reconciliation chain, never re-derived, and reads nothing new — no route or UI ships in this release.
Manufacturing
New: productionClosureProjection.service.js#closureProjection(workOrderId) — a pure, read-only projection returning {quality, packages, delivery, actualCost}, each shaped from (never re-derived from) the existing reconciliation chain; a missing chain row reports not_applicable with a named reason rather than being silently omitted. Mechanically confirmed read-only (no write-verb calls) and confirmed byte-stable and side-effect-free across repeated reads. An unknown work order raises a 404-style error. Backend service only; no route, controller or UI in this release.
Version 1.8.155
Work-order route traveller over HTTP (A03-R05, G04-S02 r6)
Exposes the already-merged A03-R05 route traveller renderer (1.8.153) as a real, RBAC-gated GET endpoint on the work order. No renderer logic changed.
Manufacturing
New: GET /api/v1/platform-manufacturing/work-orders/:id/traveller — a thin, GET-only controller wrapper around the merged a03TravellerReport.service renderer, gated by platform_manufacturing.work_orders.read (the work-order surface's own read key). Returns the renderer's HTML with a text/html content type; unknown work order returns 404, never a 500; the endpoint writes nothing.
Version 1.8.154
A03-01 release-control: module guide and acceptance evidence
Developer documentation and an acceptance-evidence record for the release-control work merged across the last several releases (correlation, gates, seed planning, the release packet, and the workspace card). No code changes, no behavior changes.
Documentation
New developer guide for the A03-01 release-control module, and a machine-readable acceptance-evidence record summarising what was built and verified, with any owner decisions still open recorded explicitly rather than silently resolved.
renderWorkOrderTraveller(workOrderId) is a pure HTML render (writes nothing) of the REPORT-CONTRACTS.md #A03-R05 factory-floor route traveller: a full traveller only when the work order's routing carries a PINNED RoutingRevision that resolves, is 'released', and has steps; otherwise a review/unavailable state naming every unmet condition (including a draft revision, which is explicitly not a qualified routing standard) plus source ids, never a fabricated route. A real defect was found and fixed during audit: the renderer's blank-CNC-machine-profile check tested only for object PRESENCE (machine.postProcessorProfile && machine.postProcessorProfile.workingEnvelope), but Machine.model.js schema-defaults both fields to a present-but-empty object for every machine -- so the safety flag never fired for any machine created through the real Mongoose model/API, only for the shipped test's own raw-collection-insert fixture (which happens to omit the field entirely). Fixed by extracting and reusing machineEnvelope.util.js's already-authoritative per-field isDeclared() logic (the module the sibling release-packet/isoGcodePost renderer already relies on) via a new exported hasAnyDeclaredEnvelopeDimension(machine) helper, closing the exact 'independently re-derives a fact another module owns' drift risk this audit was primed to look for.
Manufacturing (work-order route traveller)
New `api/src/services/platform/a03TravellerReport.service.js#renderWorkOrderTraveller()`. Two modes derived, never assumed: `traveller` only when a pinned RoutingRevision resolves, is `released`, and has steps (header shows the pinned revision id/number and the scheduling algorithm version); `review` otherwise, naming every unmet condition (no routing / no pinned revision / unresolvable / draft-not-released / no steps) plus source ids, with zero fabricated rows.
Zero durations render 'not stated', never '0 min' or the phrase 'standard time' (verified by construction with a step carrying genuinely zero/absent setup/run/queue/move times).
A `draft`-status pinned revision correctly triggers `review` mode, not a fabricated traveller (constructed directly, not just read from the shipped test) -- with the caveat noted below about the message wording also being reused verbatim for an `archived` revision.
Unresolved steps disclose with dashes and a flag; no date is auto-promised.
Duplicate route sequence: `RoutingRevision.model.js`'s own `assertUniqueSequence` pre-validate hook was confirmed (by direct read and by a real write attempt) to refuse this at write time as the primary guard; the renderer's own defensive flag was separately confirmed to fire against raw/legacy data that bypasses the hook via a direct collection insert.
Auditor's own two additional constructions, both passing without any code change needed: (1) a released, resolvable, stepped routing whose routing carries NO plannedOperations at all -- every step reads 'not scheduled' with dashes, nothing fabricated; (2) the scheduled-date cross-reference keys on `sequence` (not array position) -- verified sound against non-contiguous, non-1-starting sequence numbers (5 and 10) listed out of order between `steps[]` and `plannedOperations[]`.
`deriveMode` dev-time stub: grepped for and confirmed absent from the shipped file -- no remnant.
Scan-station/operator evidence (MP-02, `PlatformPartScanEvent`): the renderer makes no per-work-order query against this data at all (Task 3's evidence-JSON integration is explicitly out of scope for this slice), so its static footer disclosure is truthful by construction rather than by omission -- it never claims specific evidence that wasn't checked.
Real defect found and fixed during audit
The blank-CNC-machine-profile flag ('machine working envelope undeclared -- fit cannot be certified') was a false negative for every machine created through the real Mongoose model: `Machine.model.js` defaults `postProcessorProfile` AND `postProcessorProfile.workingEnvelope` to a *present* empty sub-document (`default: () => ({})`) with every dimension field defaulting to `null` -- so `!(machine.postProcessorProfile && machine.postProcessorProfile.workingEnvelope)` is false for essentially every real machine record, declared or not. The shipped test's own fixture used a raw `mongoose.connection.collection(...).insertOne(...)` for the machine (which genuinely omits the field), masking the gap. Reproduced directly with `Machine.create({ isCncManaged: true })` and no envelope fields set: the flag did not fire and 'fit cannot be certified' never appeared, exactly the state 'CNC ready' must never be printed for. Fixed by adding `hasAnyDeclaredEnvelopeDimension(machine)` to `machineEnvelope.util.js` (reusing its existing per-field `isDeclared`/`ENVELOPE_DIMENSIONS`, the same logic the sibling release-packet/`isoGcodePost` path already relies on) and switching the traveller to call it instead of its own ad-hoc object-presence check. TDD red->green reproduced by hand: reverting to the original check makes exactly one test fail (and only one); restoring the fix returns the suite to green. A permanent regression test was added to the shipped suite.
Test-harness convergence (found independently, then confirmed as an in-flight coordinated backport)
Independently found the same 'mechanically read-only' source-scan forbidden-verb-list gap the r3 audit (1.8.151) had already found and fixed in its own sibling test file: this slice's shipped test omitted `.insertOne(`, `.replaceOne(`, `.remove(`, `.findOneAndDelete(`, `.findOneAndReplace(`. While reconstructing this slice's manifest-pinned test content byte-for-byte from the authoring session's own edit-artifact trail (needed because the shared source worktree's copy had changed mid-audit), a coordinator update arrived confirming a new slice (G04-S02-r5) had just back-ported the same verb-list hardening across five already-merged sibling test files AND re-pinned this slice's own `SNAPSHOT-MANIFEST.json` hash for `a03-traveller-report.test.js` accordingly. Verified independently rather than trusted: re-read the manifest fresh (now carrying a dated re-pin note and a new hash), diffed the newly-hashed content against the earlier reconstruction, and confirmed exactly one line changed -- the forbidden-verb list, extended with precisely the five verbs this audit had also flagged. Adopted the externally re-pinned, hash-verified content rather than re-applying the same fix a second time.
Owner review point (editorial, not fixed)
The review-mode message 'the pinned RoutingRevision is {status}, not released -- a draft is not a qualified routing standard' is emitted verbatim for BOTH `draft` and `archived` revisions. It is functionally correct (review mode fires either way, nothing is fabricated), but the 'a draft is not...' phrasing is misleading when `status` is actually `archived`. Left as-is (cosmetic wording, not a rendering-correctness defect) but worth the owner's sign-off on whether the archived case deserves its own sentence.
Audit notes
Ported onto a fresh `origin/main` worktree at true tip, fetched and verified with `git rev-parse origin/main` (not a date-sorted log): `e78ac46a4`, confirming r3 (PR #606, 1.8.151) already merged. Only r4's two manifest-declared files were ported.
The shared source worktree `D:/ww-g49` was found to be actively mutating mid-audit: `api/test/manufacturing/a03-traveller-report.test.js`'s on-disk hash changed after the manifest's first-read hash had already been captured and verified. Rather than trust either the stale first-read copy or the newly-drifted copy blindly, the exact manifest-pinned byte sequence was reconstructed independently from the authoring zcode session's own tool-call artifact trail (`C:/Users/bhush/.zcode/cli/artifacts/...`), replaying each recorded edit's `structuredPatch` in order and verifying the final reconstruction's sha256 matched the manifest's originally-declared hash exactly, with every intermediate `beforeContent` matching the running reconstruction at each step -- a full, gapless chain of custody. This later turned out to be a legitimate in-flight coordinated backport (see above), not corruption, but was verified as such rather than assumed.
TDD red->green reproduced directly, twice: (1) the shipped defect fix -- reverting the CNC-envelope check to its original form made exactly the new regression test fail (and only it); restoring the fix returned the suite to green; (2) the pre-existing suite itself re-run fresh at every stage (13/13 on the manifest-pinned content, 16/16 after adding this audit's three new tests).
Version collision, resolved: this was first cut as 1.8.152, but the G04-S02-r5 backport (PR #607) merged with that same number moments earlier. Re-verified `app/package.json` fresh on `origin/main` after the merge (`7c0987c59`), confirmed zero path overlap between r5's changed files and this slice's files, reset onto the new tip, reapplied only this slice's two new files plus the `machineEnvelope.util.js` fix, re-ran the suite (16/16), the seven-suite battery (91/91) and lint fresh on the new base, then re-cut as **1.8.153**.
Version 1.8.152
Read-only scan verb-list back-port to 5 sibling suites (G04-S02 r5)
Test-only follow-up to the G04-S02 r3 audit (1.8.151): the r3 audit hardened a03-routing-candidate-plan.test.js's mechanically-read-only source-scan forbidden-verb list (it was missing .insertOne(, .replaceOne(, .remove(, .findOneAndDelete(, .findOneAndReplace() and flagged the identical gap in five already-merged sibling suites as a coordinated back-port opportunity. This is that back-port: one line changed per file, no production code touched.
Test-harness hardening (back-port, no behavior change)
Replaced the forbidden-verb list in `a03-release-control.test.js`, `a03-release-control-http.test.js`, `a03-operational-seed-plan.test.js`, `a03-release-packet.test.js`, and `a03-factory-handoff.test.js` with the identical 14-verb list already shipped in `a03-routing-candidate-plan.test.js:144` (verified character-for-character against the file currently on main, not merely visually similar).
All five underlying production services these tests scan (`productionReleaseCorrelation.service.js`, `a03OperationalSeedPlan.service.js`, `releasePacketReport.service.js`, `factoryHandoffProjection.service.js`) remain read-only by direct construction; this closes a test-robustness gap, not a live defect.
Audit notes
Ported onto a fresh `origin/main` worktree at true tip, verified with `git rev-parse origin/main` (e78ac46a4), not a date-sorted log. Diff against that tip confirmed exactly five files changed, one line each -- read directly, not taken on the handoff's word.
The applied verb list was diffed against the actual `a03-routing-candidate-plan.test.js` on main and matches exactly: `.save(`, `.create(`, `.insertOne(`, `.insertMany(`, `.replaceOne(`, `.updateOne(`, `.updateMany(`, `.bulkWrite(`, `.remove(`, `.deleteOne(`, `.deleteMany(`, `.findOneAndUpdate(`, `.findOneAndDelete(`, `.findOneAndReplace(`.
Fix demonstrated to have real teeth, not just a cosmetic line change: a synthetic source file using `.insertOne(` was scanned against both the OLD (pre-fix) and NEW (14-verb) lists -- the old list did not flag it, the new list did.
All five hardened suites plus the already-fixed routing-candidate suite re-run fresh, individually, via `node --test`: 61/61 pass, 0 fail, 0 skipped (11+9+10+13+11+7), matching the handoff's claim exactly. `npm run lint` -- Syntax OK (5642 files), also matching exactly.
The slice's disclosed side-effect -- hardening `a03-traveller-report.test.js` in place in the still-pending, unmerged G04-S02-r4 worktree (`D:/ww-g49`) and re-pinning that slice's own `SNAPSHOT-MANIFEST.json` for that file -- was independently checked: the file carries the same 14-verb list, and the manifest's dated re-pin note's sha256/byte-length match the worktree file exactly. r4 has not been merged, so this is a still-in-flight slice's own author touching its own local worktree before hand-off; harmless and accurately disclosed. Not ported or otherwise acted on here -- a separate audit owns that slice.
Version 1.8.151
Routing-candidate dry-run planner (A03-02 Task 4 first half, G04-S02 r3)
planRoutingCandidates() is a pure dry-run planner for the A03-RTG-PANEL/A03-RTG-ASSEMBLY review-candidate routings: no RoutingRevision document is ever created, and the two candidates it returns stay status:'draft' by construction (the field is assigned once, unconditionally -- no code path can emit anything else, so the unresolved.length > 0 => status !== 'released' invariant holds structurally, not just by test coverage). operationIds are resolved against the real A03-OPS-001 operation catalogue using the seeder's own findOne({name}) rule; a missing or inactive named operation is reported in unresolved with what would fix it, never substituted or defaulted. All owner facts (work-centre qualification, times/yield/capabilities/skill/subcontract lead, and the finished item each candidate routes FOR) stay unresolved with a stated reason.
Manufacturing (routing-candidate dry run)
New `api/src/services/platform/a03RoutingCandidatePlan.service.js#planRoutingCandidates()`. Verified by independent construction, not just by reading the shipped test: the full serialized plan was produced and inspected directly against a seeded catalogue -- PANEL resolves 7 real operation ids (Cutting/Nesting -> Edging -> CNC/Boring -> Sanding -> Finishing -> Inspection -> Packing), ASSEMBLY resolves 3 (Assembly -> Inspection -> Packing), both `status:'draft'`, both `primaryWorkCentreId: null`, `liveSeedingAuthorized: false`.
Missing/inactive catalogue handling constructed directly (deactivating `CNC / Boring` and deleting `Finishing` from the catalogue, not just running the shipped fixture): PANEL's operationIds dropped to 5 and both gaps were named in `unresolved` with an explicit fix-it description ('...INACTIVE -- reactivate or re-qualify it...' / '...not in the catalogue -- create it via the existing seeder...') -- never silently substituted or defaulted.
Zero-defaults claim verified by grepping the actual serialized output, not the source comments: `setupTimeMinutes`, `runTimeMinutesPerUnit`, `queueTimeMinutes`, `moveTimeMinutes` are absent from the plan entirely -- not present even as `0`.
Idempotency verified by calling the planner twice against the same seeded catalogue: the two results are deep-equal modulo `plannedAt`, and the operation catalogue's document count is unchanged before and after (10 before, 10 after) -- confirming the planner writes nothing.
The release-blocking invariant confirmed structurally: `status: 'draft'` appears exactly once in the source, assigned unconditionally with no branch, so no code path in this file can ever emit `'released'`.
Read-only claim confirmed by direct code reading (the file's only database interaction is a single `Operation.findOne({ name }).lean()`), independent of the shipped source-scan test.
Test-harness hardening (found and fixed during audit)
The shipped 'mechanically read-only' source-scan test's forbidden-verb list (`.save(`, `.create(`, `.insertMany(`, `.updateOne(`, `.updateMany(`, `.bulkWrite(`, `.deleteOne(`, `.deleteMany(`, `.findOneAndUpdate(`) omitted several real Mongoose/MongoDB write verbs -- confirmed by construction that a hypothetical `mongoose.connection.db.collection('platformmanufacturingoperations').insertOne({...})` call would evade every pattern in the original list. The same list (same gap) is shared verbatim by sibling planner suites already on main (e.g. `a03-operational-seed-plan.test.js`); those files are out of scope for this slice and were left untouched. This slice's own test file was hardened by adding `.insertOne(`, `.replaceOne(`, `.remove(`, `.findOneAndDelete(`, `.findOneAndReplace(` to the forbidden list. The production file has zero write calls of any kind (confirmed by direct reading), so this is a test-robustness fix, not evidence of a live defect -- re-verified 7/7 green after the change.
Owner review point (editorial, not a code defect)
The PANEL/ASSEMBLY operation-list composition (which named A03-OPS-001 identities each candidate chain includes, and in what order) is this slice's own editorial choice -- neither the phase plan (`A03-02-factory-handoff.md` Task 4) nor `seed-requirements.json`'s A03-OPS-005 entry names the exact composition, only that `operationIds` 'must reuse A03-OPS-001 identities.' Note also that A03-OPS-005's own `requiredOwnerFields` list includes 'operation sequence' itself as an item the owner must still resolve before publication -- consistent with the candidates never leaving `draft`, but worth the owner's explicit sign-off on the chosen PANEL (7-step) and ASSEMBLY (3-step) compositions before any future revision moves toward release.
Audit notes
Ported onto a fresh `origin/main` worktree at true tip, fetched and verified with `git rev-parse origin/main` (not a date-sorted log): initially `e31d32ce6`, matching the slice's stated base (`D:/ww-g49` @ `glm-g04-s02-t4`) exactly. Both changed files' sha256 hashes matched `SNAPSHOT-MANIFEST.json` byte-for-byte before porting. The worktree-staleness disclosure was independently verified: `git status --short` in `D:/ww-g49` showed exactly the two declared untracked files, nothing else.
`origin/main` advanced mid-audit -- the sibling revision G04-S02-r2 (audited in parallel) merged as 1.8.150 while this audit was in progress. Diffed the two tips first to confirm zero path overlap with this slice's files, then fast-forwarded the audit worktree cleanly onto the new tip and re-ran the full battery and lint fresh on the updated base before committing.
TDD red->green reproduced directly: temporarily removing the new service file dropped the suite to 0/7 (`Cannot find module`, all 7 subtests fail via `hookFailed`/`testCodeFailure`); restoring it (byte-identical, hash re-verified) returned 7/7.
Seven-suite battery re-run fresh, twice (once on the original tip, once after the fast-forward): `a03-routing-candidate-plan` + `a03-operational-seed-plan` + `a03-factory-handoff` + `design-manufacturing-bridge` + `golden-path-design-to-release` + `mp01-routing-capacity` + `iso-gcode-post` -- **87/87 pass, 0 fail, 0 skipped** both times, exactly matching the author's claim.
`npm run lint` -- **Syntax OK (5642 files)** fresh on the updated base (5641 on the original tip, +1 for r2's new HTTP test file already on main).
Version 1.8.150
Factory-handoff projection over HTTP (A03-02 Task 2, G04-S02 r2)
GET /api/v1/platform-manufacturing/factory-handoff/:workOrderId exposes r1's factoryHandoffProjection(workOrderId) (1.8.148) over real HTTP, gated by platform_manufacturing.design_links.read. The handler adds only request shaping and a 404 translation for an unknown work order; every rule stays in r1's projection service, which this revision does not touch. RBAC proven by construction over real HTTP (real app boot, real PlatformEmployee/Role fixtures, real JWTs, supertest over loopback): unauthenticated to 401, no permissions to 403, and -- the interesting case -- a role holding only design_links.repair (not read) also gets 403, confirmed independently against the permission engine's roleGrants() (exact-key / '*' / 'module.*' / 'module.resource.*' matching only, no action-level implication), not just the shipped test.
Manufacturing (factory-handoff over HTTP)
New `router.get('/factory-handoff/:workOrderId', can('platform_manufacturing.design_links.read'), ctrl.designLinks.factoryHandoff)` in `platformManufacturing.routes.js`, and `factoryHandoff` in `designManufacturingBridge.controller.js` -- a thin GET handler that calls the r1 projection service and translates its 'not found' error to 404. Route-table scan confirms GET only: no post/put/patch/delete registered on `/factory-handoff/`.
Behavioral contract verified over real HTTP, not source text: two authenticated reads deep-equal modulo `generatedAt`/`readiness.assessedAt`; a re-projection of the same (bomVersion, billOfMaterials) pair (Link's own unique-pair-index upsert, via an in-place update) flips coverage 100% -> 60% and the response states the exact '60%' partial-coverage reason and the one named skipped line; two consecutive reads leave the Link count and the work order's `updatedAt` unchanged; an unknown work order returns 404, never a 500.
repair-only-403 verified by construction, independent of the shipped test: read `roleGrants()` in `auth.middleware.js` directly -- it matches only an exact permission key, the global `*`, a module wildcard, or a resource wildcard, with no action-level implication -- so a role holding `design_links.repair` alone cannot satisfy `can('platform_manufacturing.design_links.read')` by design, not by omission.
Audit notes
Ported onto a fresh `origin/main` worktree at true tip (fetched and verified with `git rev-parse origin/main`), which was `e31d32ce6` (PR #604, release 1.8.149). The slice's stated base (`D:/ww-g48` from `origin/main @ 35ecea3da`) has since been surpassed by r1 (PR #603/1.8.148) and G04-S01's remaining revisions -- both already on main -- so only r2's three manifest-declared files were ported; r1's files were left untouched (already on main). All three files' sha256 hashes matched `SNAPSHOT-MANIFEST.json` byte-for-byte before porting; the resulting diff against origin/main was exactly the declared 26-line addition (22 lines in the controller, 5 in the route file, minus 1 removed export line), nothing more.
The r1-audit hazard was specifically re-checked in the same `D:/ww-g48` worktree: two additional untracked files were present (`factoryHandoffProjection.service.js`, `a03-factory-handoff.test.js`) beyond the three the manifest declares. Both were hashed and found byte-identical to what r1 already shipped on main -- stale leftover copies of already-merged content, not new or undeclared drift. Nothing beyond the declared three files was ported.
TDD red->green reproduced directly in the clean worktree: reverting the two modified files to their pre-port (origin/main) state dropped the new suite to 2/7 (5 of the 6 RBAC/behavioral subtests fail on 404 routing / undefined handler); restoring the port returned 7/7.
The resolveUpstream ambiguity the author flagged (an unsorted `findOne({billOfMaterials})` against a Link collection whose unique index is only per (bomVersion, billOfMaterials) pair, so a legacy BOM re-projected to a new bomVersion can leave two link documents with no defined winner) was independently confirmed pre-existing: `git log` on `designManufacturingBridge.service.js` shows exactly one commit in this repository's history -- the original subtree import -- so neither r1 nor r2 (nor anything else in this repo's tracked history) has ever touched `resolveUpstream` or `recordLink`. The committed test's workaround (an in-place update of the single existing (bomVersion, billOfMaterials) pair, rather than inserting a second link document) is sound: it exercises a real re-projection without ever creating the ambiguous two-document state, so `resolveUpstream`'s unsorted query is never exercised by this suite.
Nine-suite battery (both handoff suites + design-manufacturing-bridge + golden-path-design-to-release + both a03-release-control suites + the RBAC/staleness audit harness + a03-release-packet + mp01-routing-capacity) ran 106/106, 0 fail, 0 skipped, fresh in the clean worktree -- matching the author's claim exactly.
Two decisions surfaced for the owner, not silently resolved -- see OWNER-DECISION.md: (1) whether `design_links.repair` should imply `design_links.read` (currently it does not, by design per the RBAC catalog's own comment, and this revision's test pins that as the current behavior); (2) whether `resolveUpstream`'s unsorted `findOne` should gain an explicit tie-break for the (undefined today) case of two link documents against one legacy BOM.
Version 1.8.149
Manufacturing Release Workspace: release-control status and packet preview
The Manufacturing Release Workspace gains a release-control card showing whether a work order's factory release chain is ready, with each gate (quote verification, BOM/product release, design bridge, release approval) named individually rather than blended into one status, plus a button to preview the release packet in-app.
Manufacturing — Release Workspace
New release-control card between Readiness and Issues: a plain ready/blocked summary first, then each gate's own state (pass, blocked, or not assessable — never shown as a pass), then the underlying correlation evidence behind a details disclosure.
A gate marked 'not assessable' is always named and never rendered or counted as passing.
Release packet preview opens in the app's own document viewer, not a new browser tab or popup.
A new read-only service, factoryHandoffProjection(workOrderId), answers one question about a work order in one shape -- linkageKind, coveragePercent, skippedLines, bomId, routingId, labelStatus, readiness, reasons, generatedAt -- composed entirely from four already-existing authorities rather than reimplementing any of their logic: the design<->manufacturing bridge's own resolveForWorkOrder for linkage/coverage/skipped-line/ambiguity facts, the work order's pinned WorkOrderRouting.routingRevision for routingId, productionReconciliation.reconcileWorkOrder's own labels link row for labelStatus, and manufacturingReadiness.assessWorkOrder's own live summary for readiness. It performs no reconstruct/repair/issue/schedule/release call of any kind and writes nothing. This is Task 1 of a five-task phase plan; HTTP wiring, UI surfaces, and the acceptance-time evidence file are explicitly out of scope for this revision and are not present.
Manufacturing (factory-handoff projection)
New `api/src/services/platform/factoryHandoffProjection.service.js#factoryHandoffProjection(workOrderId)` -- a pure read with no `require()` of mongoose write paths and no call to the bridge's own mutating methods (`recordLink`/`reconstructLink`/`attachDesignRevision`). Unimported by any route or controller in this revision -- confirmed by a repo-wide grep -- so this ships with zero runtime behavior change.
The three named acceptance examples verified by construction (not only via the shipped test's fixtures, but independently through the bridge's real `recordLink`/`reconstructLink` write paths): (a) a recorded, 100%-coverage link carries no bridge-related reason at all; (b) a recorded, partial-coverage link retains and states its exact skipped-line reason, never folded into a silent pass; (c) a reconstructed, ambiguous link names both the reconstruction fact and the ambiguity, stays visibly non-equivalent to a recorded link, and is never upgraded to look equivalent on a second read.
The routingId distinction verified by construction: a work order whose routing document's own `_id` differs from its pinned `routingRevision` returns the revision id specifically, never the routing document's own identity.
The labelStatus reuse traced to source and confirmed genuine: the projection calls `productionReconciliation.reconcileWorkOrder` and reads its `labels` link row directly (`chain.links.find((l) => l.link === 'labels')`), which resolves to the same `reconcileLabels()` function every other reconciliation consumer uses -- no parallel label-status logic exists in the new file.
Read-only guarantee pinned twice, both reproduced: a mechanical source scan (absence of `.save(`/`.create(`/`.update(`/`.insert(`/`.delete(`/`.findOneAndUpdate(` and of the bridge's own mutator names `reconstructLink(`/`recordLink(`/`.release(`) and a document-stability double read (two consecutive calls deep-equal modulo timestamps; the underlying work order's `updatedAt` is untouched).
Audit notes
Ported onto a fresh `origin/main` worktree at true tip (fetched and verified with `git rev-parse origin/main`, not a date-sorted log), which was `35ecea3da` (PR #602, release 1.8.147) -- matching the slice's stated base exactly, so no rebase was needed. Both new files verified byte-for-byte against `SNAPSHOT-MANIFEST.json`'s sha256 hashes before porting.
Discrepancy found and NOT ported: the slice's stated base worktree (`D:/ww-g48`) additionally carried uncommitted, undeclared modifications to `designManufacturingBridge.controller.js` and `platformManufacturing.routes.js` wiring a `GET /platform-manufacturing/factory-handoff/:workOrderId` endpoint -- Task 2 work the HANDOFF itself lists as 'Deliberately NOT in r1' and which the manifest does not mention. This contradicts the HANDOFF's own claim that the service is 'unimported by any route/controller in this revision.' Only the two manifest-declared files were ported into the clean worktree; the stray HTTP wiring was left behind. Flagged for the owner as an open question -- see OWNER-DECISION.md.
TDD red->green reproduced directly: removing the new service file dropped `a03-factory-handoff.test.js` to 0/11 (module not found, all 11 subtests failing); restoring it verbatim returned 11/11.
The six-suite battery (factory-handoff + design-manufacturing-bridge + golden-path-design-to-release + a03-release-control + a03-release-packet + mp01-routing-capacity) ran 82/82, 0 fail, 0 skipped, fresh in the clean worktree. `npm run lint` reported 'Syntax OK' across 5639 files.
Independent construction beyond the shipped test: writing a standalone script (not the shipped test file) that drives the real `recordLink`/`reconstructLink` bridge functions -- rather than the shipped test's own raw `collection.insertOne` fixtures -- reproduced all three named examples and the routingId distinction identically. This also surfaced a test-environment-only fragility (not a shipped-code defect): `designManufacturingBridge.service.js`'s `resolveUpstream` populates `designRevision`, which throws `MissingSchemaError` in an from-scratch test process where `PlatformDesignEngineRevision.model.js` was never required -- the shipped test's fixtures happen to avoid this because they omit the `designRevision` field entirely (absent, not explicitly null) rather than going through the real write path. Not a live-server risk (the real Express app registers that model at boot via its route tree), so no source change was made; the independent verification script now requires the model explicitly to mirror that.
A new read-only GET endpoint renders the manufacturing release candidate's seven-section release packet as HTML, gated on stored evidence rather than the state enum alone: a full packet requires the candidate to be released AND its stored assessment to carry zero unoverridden blockers AND recorded source revisions, and anything short of that renders with a visible 'REVIEW COPY — NOT FOR FABRICATION' banner naming the exact unmet conditions. Everything is HTML-escaped; the renderer writes nothing and does not depend on the r1/r2 correlation endpoint (it reads the candidate document directly). One real defect was found and fixed during audit: the approvals section's own staleness check compared each approval's checksum against the wrong stored field, causing it to under-report staleness for any candidate approved without ever calling assess() (a reachable path, since approveState() never touches the stored assessment snapshot) — fixed to use the same field the packet's own header already labels 'Live scope checksum', and pinned with a new regression test.
New `GET /platform-manufacturing/release-candidates/:id/release-packet` (`platform_manufacturing.release_candidates.read` only) -> `releasePacketReport.service.js#renderReleasePacket(candidate)`, a pure function taking the already-loaded candidate document. The controller 404s an unknown id before rendering and passes nothing from `req` into the render path beyond the fetched document.
`derivePacketMode(candidate)` derives the gate honestly from the stored assessment rather than trusting `state` alone: constructed a candidate with `state: 'released'` and a live `blocker` issue still present on `lastAssessment.issues` and confirmed by construction that it renders as a review copy naming the blocker count, never a full packet (the enum-alone trap the slice specifically claims to avoid).
Seven sections rendered honestly by construction, each verified with a purpose-built fixture: never-assessed candidates say so in bold rather than showing an implied pass; the twelve readiness dimensions spell out `NOT ASSESSABLE` rather than folding it into pass; approved exceptions carry original severity, overridden-by and override reason; the A02 qualification line states 'unresolved' (never 'qualified', never a silent zero); HTML-special characters in `candidateCode` are genuinely escaped, not merely claimed to be.
The renderer has zero `require()` calls of any kind — not merely a source-scan pass against a write-verb regex list, but structurally incapable of reaching a raw `mongoose.connection.collection(...)` handle since it never imports mongoose in the first place.
Defect found and fixed during audit
`approvalRows`'s staleness comparison read `candidate.lastAssessment?.scopeChecksum` as its 'live' reference, while the packet's own header labels `candidate.scopeChecksum` (the top-level field) as the 'Live scope checksum' — an internal inconsistency. `assess()` updates both fields together; `approveState()` updates only the top-level field and never touches `lastAssessment`. Constructed side-by-side against the authoritative `describeApprovals()` in `manufacturingRelease.service.js` (always fed a freshly computed live checksum by its real caller): a candidate approved into two states in sequence, with the scope moving between the two `approveState()` calls and `assess()` never run, showed the real algorithm correctly flagging the earlier approval STALE while the packet's original code reported it 'effective' unconditionally (the `liveChecksum && ...` guard short-circuits false whenever `lastAssessment.scopeChecksum` is blank, which it always is when `assess()` was never called). Fixed by reading `candidate.scopeChecksum` instead; a shipped test whose own fixture set `lastAssessment.scopeChecksum` to a value newer than the top-level field (a combination no real service call can produce, only a raw-document test insert) was corrected to a physically-reachable combination, and a new regression test pins the fixed, reachable scenario directly.
Residual, disclosed limitation (not fixed, by design): the renderer is a pure read with no live recompute, so genuine scope drift occurring after the most recent stored snapshot (whichever of `assess()`/`approveState()` ran last) is invisible to it — consistent with every other section of the renderer, which reports only what is recorded rather than recomputing live. Fixing this would require importing the live readiness service, which the renderer deliberately avoids to stay a dependency-free pure render path.
Audit notes
Ported onto a fresh `origin/main` worktree at true tip (fetched and verified with `git rev-parse origin/main`), which was `e28192a64` (PR #601, release 1.8.146 — the just-merged r1-r3 work) — a clean, isolated port of only r4's four changed/new files, each verified byte-for-byte against `SNAPSHOT-MANIFEST.json`'s sha256 hashes before porting.
The nine-suite battery (five a03 files including the r1-r3-shipped RBAC/staleness audit file, plus gcode, envelope, product-engine-manufacturing, quote-engine-production-lifecycle and design-manufacturing-bridge) ran 134/134, 0 fail, 0 skipped, fresh in the clean worktree. `npm run lint` reported 'Syntax OK' across 5637 files.
TDD red->green reproduced directly: removing the new service file dropped `a03-release-packet.test.js` to 0/13 (module not found); restoring it verbatim returned 13/13.
A read-only correlation adapter now answers, for any work order built from a legacy BOM, which production package (if any) it is correlated with through the recorded design-to-manufacturing bridge, naming the exact missing edge whenever it cannot answer 'correlated'. A new GET endpoint projects that correlation into a release-control gate view (quote verification, released BOM/product, recorded/complete design bridge, current release approval) behind a three-permission RBAC AND. A companion dry-run planner reports what a governed operational seed WOULD do for five A03 requirements, never touching a database. Foundation only: nothing here grants a release, seeds anything live, or changes any existing route's behavior.
New `productionReleaseCorrelation.service.js#correlateWorkOrder(workOrderId)` — a pure read tracing WorkOrder.bom -> PlatformDesignManufacturingLink -> PlatformProductionPackage.bomVersion. Every 'unlinked' result names the exact missing edge (no BOM / no bridge link / no issued package); superseded packages never answer as the live one; a 'reconstructed' bridge link is never silently upgraded to 'recorded' on reread; quote-verification status is honest ('not_linked'/'unknown'), never fabricated as 'verified'.
New `GET /platform-manufacturing/release-control/:workOrderId` -> `releaseControlProjection(workOrderId)`, returning `{status: 'ready'|'blocked', correlation, gates: [{key, state, reason}], generatedAt}`. Each of the four named blocking conditions (missing approval, withdrawn BOM, superseded product, reconstructed/partial design bridge) reports under its own gate key while the other gates continue reporting their own independent state.
RBAC: the route requires all three of `platform_manufacturing.release_candidates.read`, `platform_manufacturing.design_links.read` and `platform_product_engine.production_packages.read` (the same chained-`can()` convention already used by `platformCommercial.routes.js`'s related-records endpoint). GET only; no write verb exists on this path.
`quote_verification` reports `not_assessable` and never blocks readiness — an explicit, flagged judgment call (no recorded package-to-quote-library mapping exists yet to assess against), not a silent pass.
New `a03OperationalSeedPlan.service.js#planOperationalSeed()` — a pure dry-run planner returning one `{action: 'reuse'|'create-draft'|'conflict'|'blocked', requirementId, stableId, unresolved[]}` per A03 operational-seed requirement (operation catalogue, CNC machine profile, routing templates, inspection templates, supplier/material identity). `liveSeedingAuthorized` is always `false`; a blank/unqualified CNC machine profile is reported `blocked` by design (qualification is a tenant-owned fact no seed may assert, not an error state).
A new pin test confirms a blank CNC profile's g-code header always reads `ENVELOPE CHECK: NOT ASSESSABLE` (naming the missing machine-master fields) and never `PASS`, with the contrasting case (a fully declared envelope) confirmed to read `PASS`.
Not imported into any authoring/release UI yet; the endpoint and planner are additive reads with zero behavioral change on any existing route.
Audit notes
The read-only guarantee (no `.save`/`.create`/`.insertMany`/`.updateOne`/`.updateMany`/`.bulkWrite`/`.deleteOne`/`.deleteMany`/`.findOneAndUpdate`, and no raw `mongoose.connection.collection(...)` write handle) was independently re-verified by direct source inspection across both new services, not merely by re-running the shipped mechanical-scan tests.
The three-permission RBAC AND was independently verified by construction: four real PlatformEmployee/Role fixtures, each missing exactly one of the three required permissions (plus a fifth holding all three), hit the real route through the real Express app and JWT auth — three real 403s, one real non-403 — closing a gap where the shipped suite only pinned this via a source-text regex against the route file.
The 'never assessed' release-candidate branch (no `lastAssessment` at all) was independently constructed against the real model and confirmed to report the stored approval at face value rather than fabricating a staleness verdict, and to remain read-only on repeat reads.
Version 1.8.145
Loose/upholstered furniture family foundation: one register for four roadmap IDs (G03.6-S01)
The loose-furniture family's product vocabulary is extended from storage-only to the full A02-P06 set (storage, sofa, armchair, dining-chair, coffee-table, side-table, console), and a new reconciliation pass classifies every real catalogue record for this family plus three deliberately cross-referenced upholstered-bed records, with an upholstery/mechanism safeguard: any record naming a lift kit, entrapment control, fabric/foam fact, or a bare stability/structural fact, is held for owner review rather than silently treated as a normal reusable template. The register also carries a purchased-vs-custom identity split (A04-02's bought-out identity vs A04-03/04's custom manufacturing) and names all four original roadmap IDs (A02-P06, A04-02, A04-03, A04-04) on one cross-map. The family stays not delivery-accepted with no planner dispatch.
Quote Engine (foundation, not yet wired to authoring UI)
Loose-furniture family vocabulary extended to 7 product types (storage, sofa, armchair, dining-chair, coffee-table, side-table, console); status stays 'researched' with deliveryAccepted false and planner null — a registry entry, not a working planner.
New library reconciliation classifies the family's 18 real catalogue P06 records plus 3 deliberately cross-referenced beds/P04 records (BD-07, BD-08, BD-11 — upholstered ottoman/sofa beds), partitioned from the catalogue's own authoritative crosswalk phase tag (never guessed from free text); records naming an upholstery/mechanism concern (lift, entrapment, fabric, foam, bare stability/structural) are held for review, never silently qualified.
The register carries an explicit purchased-vs-custom identity split (A04-02 bought-out vs A04-03/04 custom manufacturing) — every record lands on exactly one side, verified against the real 21-record scope.
A02-P06 and A04-02/A04-03/A04-04 cross-map recorded on the reconciliation output — one implementation for four original roadmap IDs.
The `tv_media` alias (pre-existing) now resolves to the family's grown value set as a mechanical consequence of the vocabulary extension, verified directly against the alias-resolution code and the drift-guard test — not a hand-coded special case.
Not yet reachable from any authoring screen — foundation for a follow-up release.
Version 1.8.144
uPVC systems family foundation: registry + honest library reconciliation (G03.7-S01, the last A02 family)
The upvc-doors-windows family's product vocabulary is extended from empty to the A02-P07 set (casement window, sliding window, uPVC door), and a new reconciliation pass classifies all 17 real catalogue P07 records. P07 is the sharpest boundary of any family so far: uPVC is system-led (manufacturer profile/reinforcement/glazing/hardware facts, never defaulted) and structurally independent from the furniture aluminium/profile solver — verified by construction, not just documented, by showing the planning product-list accessor (calc/planning/productLists.js) recognises only families with a non-null planner (kitchen, wardrobe, b2b-cabinetry), so no container exists for a uPVC product to reach the assembly/layout pipeline. An audit defect in the manufacturer-system-qualification hold regex (6 of 17 records, 35%, escaping owner review) was found and fixed before this release. This closes the G03 whole-home family-foundations band: all seven A02 families now have their registry vocabulary, settings-readiness contract and reconciliation register.
Quote Engine (foundation, not yet wired to authoring UI)
uPVC family vocabulary extended to 3 product types (casement-window, sliding-window, upvc-door); status stays 'researched' with deliveryAccepted false and planner null — no qualified manufacturer-system adapter exists yet, so nothing can dispatch.
New library reconciliation classifies all 17 real catalogue P07 records, partitioned by the module's own regex and independently cross-checked against the catalogue's authoritative crosswalk[].phase === 'P07' tag: exact match, zero false positives, zero false negatives.
THE INDEPENDENCE RULE verified by construction: uPVC's planner stays null, so families.planningLists() (and therefore calc/planning/productLists.js's LIST_KEYS, which the assembly/layout/panel-definition pipeline reads exclusively) never contains a uPVC-shaped list — there is no container a uPVC product could ever be placed into to reach the furniture aluminium/profile shutter solver.
A02-P07 cross-map (system-led) recorded on the reconciliation output, now covered by a real assertion (was previously set but never asserted on).
Not yet reachable from any authoring screen — foundation for a follow-up release.
Version 1.8.143
Doorsets/panelling/partitions family foundation: registry + honest library reconciliation (G03.5-S01)
The door-sets family's product vocabulary is extended from empty to the full A02-P05 set (doorset, partition, wall-panelling), and a new reconciliation pass classifies every real catalogue record for this family with an installation-interface safeguard: any record naming a survey opening, handing, gap, approved joint detail, substrate condition or fire/acoustic performance concern is held for owner review rather than silently treated as a normal reusable template. Door Sets already has real, working quoting on main (specProductType 'doorset'); this slice adds a library-identity layer alongside it without touching, wrapping or replacing that pricing path, and the family stays not delivery-accepted with no planner dispatch.
Quote Engine (foundation, not yet wired to authoring UI)
Door-sets family vocabulary extended to 3 product types (doorset, partition, wall-panelling); status stays 'active' with deliveryAccepted false and planner null — a registry entry, not a working planner, despite the family's existing quoting.
New library reconciliation classifies the family's 29 real catalogue P05 records, partitioned from the catalogue's own authoritative crosswalk phase tag (never guessed from free text); records naming an opening/substrate/installation-interface concern (survey opening, handing, gaps, approved joint details, fire, acoustic) are held for review, never silently qualified.
The existing doorset pricing is named as the commercial owner on the register's return and is untouched by this slice: zero files in the existing calculation path (calc/doorset.js, calc/index.js, calc/rules.js) are modified.
A02-P05 and A04-01 cross-map recorded on the reconciliation output.
Not yet reachable from any authoring screen — foundation for a follow-up release.
Version 1.8.142
Beds/bedroom family foundation: registry + honest library reconciliation (G03.4-S01)
The beds family's product vocabulary is extended from empty to the full A02-P04 set (bed-frame, storage-bed, headboard, bedside-table), and a new reconciliation pass classifies every real catalogue record for this family with a load-path/mechanism safeguard: any record naming a mattress load-path, lift/gas-strut mechanism, bracing, joint, structural member, support schedule, stability or actuator concern is held for owner review rather than silently treated as a normal reusable template. One implementation discharges both A02-P04 and the A04-R01 bed-rendering scope (cross-map carried on the reconciliation output).
Quote Engine (foundation, not yet wired to authoring UI)
Beds family vocabulary extended to 4 product types (bed-frame, storage-bed, headboard, bedside-table); still status 'researched' — a registry entry, not a working planner.
New library reconciliation classifies the family's 18 real catalogue P04 records, partitioned from the catalogue's own authoritative crosswalk phase tag (never guessed from free text); records naming a load-path/mechanism concern (mattress load path, lift/gas-strut mechanisms, bracing, joints, structural members, support schedules, stability, actuators) are held for review, never silently qualified.
A02-P04 and A04-R01 (bed rendering) cross-map: one canonical beds implementation evidences both roadmap IDs.
Not yet reachable from any authoring screen — foundation for a follow-up release.
Version 1.8.141
Office/retail family foundation: registry + honest library reconciliation (G03.3-S01)
The office-furniture family's product vocabulary is extended from empty to the full office/retail P03 set (desk, pedestal, office-storage, meeting-table, reception, retail-counter), and a new reconciliation pass classifies every real catalogue record for this family with a structural/load safeguard: any record naming a worksurface-load, support-span, clear-knee-space or stability concern is held for owner review rather than silently treated as a normal reusable template. One implementation discharges both A02-P03 and A04-01 (cross-map carried on the reconciliation output).
Quote Engine (foundation, not yet wired to authoring UI)
Office-furniture family vocabulary extended to 6 product types (desk, pedestal, office-storage, meeting-table, reception, retail-counter); still status 'researched' — a registry entry, not a working planner.
New library reconciliation classifies the family's 18 real catalogue P03 records; records naming a structural/load concern (worksurface load, support span, clear knee space, stability) are held for review, never silently qualified.
A02-P03 and A04-01 cross-map: one canonical office/retail implementation evidences both original roadmap IDs.
Not yet reachable from any authoring screen — foundation for a follow-up release.
Version 1.8.140
Bathroom/utility family foundation: registry + honest library reconciliation
The bathroom-furniture family's product vocabulary is extended from vanity-only to the full bathroom/utility set (vanity, mirror-storage, utility-cabinet, laundry-unit, wc-overhead), and a new reconciliation pass classifies every real catalogue record for this family with a wet-interface safeguard: any record naming a moisture/plumbing/wet-zone concern is held for owner review rather than silently treated as a normal reusable template.
Quote Engine (foundation, not yet wired to authoring UI)
Bathroom/utility family vocabulary extended to 5 product types; still status 'researched' — a registry entry, not a working planner.
New library reconciliation classifies the family's 21 real catalogue records; records naming a wet-interface concern (moisture, plumbing, trap, service access, wet-zone/wet-area) are held for review, never silently qualified.
Not yet reachable from any authoring screen — foundation for a follow-up release.
Version 1.8.139
Dry-home library reconciliation (A02-P01): pure classifier, partition-boundary defect found and fixed (G03.1-S02)
Rebased onto 1.8.138 (G03.1-S01, the dry-home family registry, PR #592, merged during this audit) after an identical-version collision -- re-cut from 1.8.138 to 1.8.139, same content otherwise. Adds api/src/services/quoteEngine/calc/dryHomeLibraryReconciliation.js, a pure module that reads the A02 seed-catalogue (370 sourceRecords, an untracked shared-checkout file) and classifies its P01 (dry-home) records into reuse-inherited / extend-reviewed-record / new-template / planned-separate-system / hold-owner, each with a reason quoting the record's own qualification/configuration text. No DB writes, no seed application, no library rows. Audited on a clean worktree off origin/main (base worktree D:/ww-g38 was still present; both changed files verified byte-exact by sha256 against the slice's SNAPSHOT-MANIFEST.json before porting). The audit found and fixed a severe defect in the P01 partition boundary: the original code identified 'P01 dry-home records' with a regex over each record's free-text name/browsePath/group (matching words like storage, study, TV), and on the real catalogue that pulled in 25 records the catalogue's own crosswalk[].phase tags as P02 (bathroom-furniture), P03 (office-furniture), P04 (beds) and P06 (loose-furniture) -- e.g. a 'Bathroom tall storage unit' and a 'Drawer-storage bed' matched on the word 'storage' -- while missing all 14 genuine P01 BC-xx trade-pack records outright. The claimed 33-record / 14-extend / 11-reuse breakdown was internally consistent but computed against the wrong record set; independently re-deriving the true P01 set from the catalogue's own authoritative crosswalk[].phase field gives 22 records (14 BC-xx + 8 TV-xx), of which today only 1 (TV-01) holds (owner-gated split supply) and the remaining 21 fall to planned-separate-system -- zero reuse-inherited, zero extend-reviewed-record, zero new-template, because the real P00 ancestor pool has no record of a matching kind (supply-package / panel-component-template) anywhere in the catalogue yet. Fixed by reading crosswalk[].phase directly rather than re-deriving phase membership from prose; every other part of the classifier (ancestor-priority guard, hold-pattern matching, blocker surfacing) was independently verified correct and left unchanged. Also fixed: summary.complete was a hardcoded constant (always false) despite HANDOFF documentation describing it as conditional on blocker resolution -- it could never become true even once every blocker resolved and every row settled. Replaced with a derived fact (no blockers AND no row left in hold-owner/planned-separate-system), verified with a synthetic fixture to actually flip true when warranted while still reading false on today's real, still-unsettled data. TDD: 8/8 (the original suite's ancestor-inheritance assertion was softened to match honest real-data behavior -- today's real P01 set has no ancestors to honour yet -- and two new synthetic-fixture tests were added: the UNIQUE-LIBRARY-POLICY trap (a record with a real P00 ancestor and a new-template-hinting name must never disposition to new-template, verified against both the trapped case and a genuinely-new-template control case with no ancestor) and the complete-flag derivation (flips true only once every row is settled and every blocker is resolved). Both new tests were confirmed RED against the original code and GREEN against the fix. Fresh lint: Syntax OK (5615 files). Data-provenance note: the real catalogue is read from an untracked, session-local shared-checkout path (default D:/projects/woodworkingERP, overridable via A02_SHARED_CHECKOUT) with no digest or count pinning -- six of the eight tests depend on whatever that shared file currently contains, so a concurrent session editing it could change those tests' pass/fail independent of any code change; the three ID/count assertions in the first test were made self-consistent (deriving expected values from the same catalogue at test time) but hardcoded IDs (TV-01, SH-01) still assume specific records persist. Not imported anywhere yet (confirmed by a repo-wide grep of api/ and app/); this release carries zero behavioral change on any running path.
New api/src/services/quoteEngine/calc/dryHomeLibraryReconciliation.js: reconcile(cataloguePath) reads the A02 seed-catalogue and, for each P01 (dry-home) sourceRecord, emits exactly one disposition -- reuse-inherited / extend-reviewed-record / new-template / planned-separate-system / hold-owner -- with a reason quoting the record's own qualification/configuration text, never a bare label.
P01 membership is read from the catalogue's own crosswalk[].phase tag, not guessed from name/browsePath/group text.
A record with a real P00 ancestor of matching kind can never disposition to new-template, regardless of its name or qualification wording (the UNIQUE-LIBRARY-POLICY trap); a record whose qualification names separate supply/certification/specialist ownership (e.g. TV-01's 'TV, mounting frame and hardware have explicit separate supply ownership') dispositions hold-owner via genuine pattern matching on that text, not a hardcoded record-ID list.
summary.complete is a derived fact -- true only when every qualification blocker is resolved AND no row remains hold-owner/planned-separate-system -- never a hardcoded constant.
Audit defect found and fixed: the original P01 partition (a regex over free text) pulled 25 records belonging to other catalogue phases (bathroom-furniture, office-furniture, beds, loose-furniture) into the 'dry-home' worklist while missing all 14 genuine P01 trade-pack records, invalidating the originally-claimed 33-record / 14-extend / 11-reuse breakdown. Re-derived from the catalogue's own crosswalk[].phase field, the honest current P01 set is 22 records: 1 hold-owner (TV-01) and 21 planned-separate-system -- zero reuse-inherited, zero extend-reviewed-record, zero new-template, because no P00 record anywhere in the catalogue currently shares a matching kind with any real P01 record.
Audit defect found and fixed: summary.complete was hardcoded false unconditionally, which could never reflect the module's own documented 'complete once every blocker resolves' contract. Replaced with a derivation from blockers and settled/unsettled dispositions, confirmed by synthetic fixture to flip true when genuinely warranted.
TDD 8/8, including two new synthetic-fixture tests (the ancestor trap, and complete-flag derivation) confirmed RED against the pre-fix code and GREEN after. Fresh lint: Syntax OK (5615 files).
Data-provenance: the catalogue is read from an untracked, session-local, shared-checkout path with no digest/count pinning at read time -- flagged for the owner as an open operational question, not fixed in this release.
Confirmed by repo-wide grep of api/ and app/: this module has zero importers other than its own test file, so this release carries no runtime behavior change on any path.
Adds the 'dry-home' row to the Quote Engine's single-source-of-truth family registry (api/src/services/quoteEngine/calc/families.js) -- label 'Dry Home Storage', status 'researched', deliveryAccepted false, planner null -- covering the A02-P01 storage vocabulary (TV/media, shoe, crockery, display, pooja, study, dressing-table, storage-cabinet units), with read-time aliases home-storage/dry-storage. Every downstream projection (ProductTemplate's PRODUCT_FAMILIES/schema enum, PRODUCT_WORKSPACES menu order at position 9 with uPVC renumbered to 10, QuoteEngineLibraryItem's stored FAMILIES/schema enum, calc SCOPE_TYPES) is a live require()-time projection of this one table, so the row change alone propagates everywhere except the Angular component library's own familyOptions copy, which was updated to match and is pinned by a golden regression test. Adds familySettingsReadiness.js: a pure, derived contract giving data/calculation/price/2D/3D/manufacturing/release readiness as seven separate facts (never one blanket 'supported' bit), each defaulting NOT ready with null evidence for a researched family, each carrying its own owning role, and deriving real (true) readiness for delivery-accepted families (kitchen, wardrobe) from the existing modules -- verified directly, not just asserted. Audited independently on a clean worktree off origin/main (base worktree D:/ww-g36 was still present, so the true source was recovered directly rather than via the zcode CLI artifact store); all six changed/added files verified byte-exact (sha256) against the slice's SNAPSHOT-MANIFEST.json before porting. The two most safety-critical claims were verified by construction, not by reading code: (1) dispatch gating -- planningLists()/productLists.LIST_KEYS genuinely exclude 'dry-home' (its planner is null), productLists.descriptor('dry-home') throws 'Unknown planning product list: dry-home', and a planning block carrying a stray 'dry-home' array is silently ignored by products()/cabinetOwners() -- there is no generic-cabinet fallback because the calculation/planning engine is keyed structurally on the kitchens/wardrobes/cabinetries/frameUnits list names, and QuoteEngineProductTemplate rows (where 'dry-home' is now a valid productFamily) are catalogue/review records that no calculation path reads, by the service's own documented contract; (2) the drift guard -- temporarily broke the Angular familyOptions array (removed one option) and confirmed the registry test's 'drift guard' subtest genuinely fails, then restored it and reverified byte-exact; separately reproduced the exact workspace-order collision (dry-home at order 5, colliding with beds) the slice's HANDOFF says its own TDD loop caught, confirming the golden PRODUCT_WORKSPACES test genuinely fails on that collision. Alias resolution (home-storage/dry-storage -> dry-home) was verified end-to-end through the real quoteEngineLibraryItem.service.js libraryFilter(), and confirmed that unrelated garbage family names ('dryhome', 'DRY-HOME', 'random-garbage-family') are never coerced to dry-home. Audit defect found and fixed: familySettingsReadiness.js's derived facts were only Object.freeze()'d, so the claimed 'writes throw' contract silently failed to hold for any caller module that does not itself carry 'use strict' -- constructed a genuinely sloppy-mode write (via the Function constructor, which is not lexically strict) and confirmed the pre-fix code let it through as a silent no-op (Object.freeze under sloppy-mode assignment does not throw; it just doesn't apply). Fixed by wrapping every derived fact and the readiness record itself in a Proxy whose set/defineProperty/deleteProperty/setPrototypeOf traps throw unconditionally, independent of the caller's strict mode; added a new regression test (readiness facts refuse a write even from a genuinely sloppy-mode caller) that reproduces the gap and is confirmed failing against the pre-fix code and passing after. Confirmed workspace order has no other collisions across the full eleven-family list (orders 0-10, all unique). Full suites run fresh in the ported worktree: dry-home registry test 8/8 (7 original + 1 new regression), family-registry golden suite 14/14, FE component-library view-model spec 13/13 (via app/scripts/run-specs-bounded.cjs), ng build platform exit 0 with zero errors or warnings on the touched component, backend lint Syntax OK (5615 files, +2 for the two new test/source files added by this slice). This is registry identity plus an honest readiness vocabulary only -- no dry-home settings editors, seeds, planning dispatch, or previews exist yet, matching the slice's own stated scope.
Quote Engine — Dry Home Storage family registry row (A02-P01 foundation, not yet activated)
New family row in api/src/services/quoteEngine/calc/families.js: key 'dry-home', label 'Dry Home Storage', status 'researched', deliveryAccepted false, planner null, workspace order 9 (uPVC Doors & Windows renumbered to order 10). Library vocabulary: tv-unit, shoe-rack, crockery-unit, display-unit, pooja-unit, study-unit, dressing-table, storage-cabinet. Read-time aliases: home-storage, dry-storage.
Every downstream projection (ProductTemplate.PRODUCT_FAMILIES/ACTIVE_DELIVERY_FAMILIES and its schema enum, PRODUCT_WORKSPACES, QuoteEngineLibraryItem.FAMILIES and its schema enum, calc PRODUCT_TYPES / quote SCOPE_TYPES) derives from this single table at require() time -- confirmed by reading each consumer file, not assumed.
New api/src/services/quoteEngine/calc/familySettingsReadiness.js: a pure, derived contract exposing seven independent readiness facts per family (data/calculation/price/twoD/threeD/manufacturing/release), each { ready, owner, evidence }, defaulting NOT ready with evidence null for researched families and deriving real true readiness for delivery-accepted families (kitchen, wardrobe) from existing modules. No blanket 'supported' bit exists anywhere in the shape.
Angular quote-engine-component-library.component.ts familyOptions extended with the eight dry-home library values, kept in parity with the registry by the pre-existing golden drift-guard test (quote-engine-family-registry.test.js), which was verified to genuinely fail when the two are made to diverge.
Verification beyond the slice's own claims
Constructed dispatch-gating proof: productLists.LIST_KEYS excludes 'dry-home'; productLists.descriptor('dry-home') throws; a planning block with a stray 'dry-home' array is never read by products()/cabinetOwners(); QuoteEngineProductTemplate rows (where dry-home is now a valid productFamily enum value) are catalogue/review records with no calculation path reading them, per the service module's own documented contract -- there is no generic-cabinet fallback.
Constructed alias-resolution proof through the real quoteEngineLibraryItem.service.js libraryFilter(): 'home-storage' and 'dry-storage' both resolve to the dry-home family's eight stored library values; unrelated garbage names ('dryhome', 'DRY-HOME', 'random-garbage-family') are never coerced to dry-home.
Constructed drift-guard proof: temporarily removed one Angular familyOptions entry and confirmed the golden registry test's drift-guard subtest genuinely fails, then restored and reverified byte-exact against the manifest; separately reproduced the workspace-order collision (dry-home at order 5, colliding with beds) the HANDOFF says its own TDD loop caught, and confirmed the PRODUCT_WORKSPACES golden test genuinely fails on it.
Audit defect found and fixed: familySettingsReadiness.js's derived facts relied on Object.freeze alone, so a write from a caller module without its own 'use strict' silently no-opped instead of throwing -- verified with a genuinely sloppy-mode write via the Function constructor. Fixed with a Proxy wrapper whose mutation traps throw unconditionally regardless of caller strict mode; added a regression test that fails against the pre-fix code and passes after.
Adds api/src/services/quoteEngine/calc/mepServicePoints.js, a pure calc module coordinating electrical/plumbing/technology service points (room/host, position with an explicit datum, direction, responsibility, confidence, access envelope) across plan/elevation/3D/schedule views bound by one canonical digest. Coordination only: sizing facts a caller sends (loadAmpere, pipeDiameterMm, circuitBreakerAmpere, wireCrossSectionMm2) are dropped, not modelled, and certification is always null. Reproduces and never repeats the 'y || default zero-height' suspicion -- an unstated height carries heightUnstated: true with y staying null, while a genuinely-stated 0 is a real fact and is not flagged. Audited independently on a clean worktree off origin/main (base worktree D:/ww-g35 was still present, so the true source was recovered directly rather than via the zcode CLI artifact store); both changed files verified byte-exact (sha256) against the slice's SNAPSHOT-MANIFEST.json before porting. Audit found and fixed one real defect before release: the responsibility field (builder/electrician/plumber/technology-contractor/other) was never actually checked against its own exported enum the way kind and confidence are -- an unrecognised responsibility value was silently accepted (ok: true) with the point's responsibility field literally set to the string 'INVALID', flowing straight into the schedule output with no error and no review flag. Fixed by adding the missing enum-membership check, mirroring the kind/confidence pattern exactly; a RED-first regression test was added and confirmed to fail before the fix and pass after. This module is not imported anywhere yet (confirmed by a repo-wide grep of api/ and app/); shipping it is zero behavioral change on any running path.
New api/src/services/quoteEngine/calc/mepServicePoints.js: coordinate(points) validates and normalises electrical/plumbing/technology service points -- id, kind (electrical/plumbing/technology), room/host, position {xMm, yMm, zMm, datum}, direction, responsibility, confidence (surveyed/as-drawn/assumed), access envelope, and an explicit billable flag with its own note.
A coordinate without a named datum is refused outright ('a coordinate without one is not a coordinate') rather than silently defaulting a datum.
The null-vs-zero height distinction is enforced both ways, verified directly by construction: an omitted, undefined, null, or NaN yMm all resolve identically to heightUnstated: true with position.yMm staying null (never silently 0) and a named entry in needsReview; a yMm explicitly stated as 0 (or the numeric string "0") resolves to heightUnstated: false with position.yMm === 0, and is not flagged.
Coordination, not engineering (MEP-02's boundary): sizing facts a caller sends (loadAmpere, pipeDiameterMm, circuitBreakerAmpere, wireCrossSectionMm2) are genuinely absent from the output point object -- verified with Object.prototype.hasOwnProperty, not merely undefined-on-read -- and produce a needsReview note instead. certification is hardcoded null on every evaluation regardless of input, including a constructed attempt to spoof certification: 'approved' on an input point.
Billability is strictly billable === true (a truthy-but-not-boolean value such as "yes" does not flip it, and no responsibility value implicitly grants billability); billNote is only ever populated alongside an explicit billable: true.
One canonical digest (SHA-256 over a key-sorted deterministic serialisation) binds the plan/elevation/3D/schedule views of the same evaluation. Verified directly: two logically-identical points built with differently-ordered object keys produce an identical digest, and a genuinely different point produces a different one.
Audit defect found and fixed: responsibility was exported as an enum (RESPONSIBILITIES) and used to compute the output field, but -- unlike kind and confidence -- no code path ever pushed a refusal when it held an unrecognised value; the point simply carried the literal string 'INVALID' with ok: true. Added the missing `if (raw.responsibility != null && !RESPONSIBILITIES.includes(raw.responsibility)) errors.push(...)` check so an unknown responsibility now refuses the whole evaluation exactly like kind and confidence do. A RED-first regression test (quote-engine-mep-service-points.test.js, test 8) reproduces the gap and is now green.
Confirmed by repo-wide grep of api/ and app/: this module has zero importers other than its own test file, so this release carries no runtime behavior change on any path.
A new pure calculation module represents a wall-hosted dado band as its own object, with variable per-span heights (no universal default), typed cut-outs that only deduct when policy says so, and a disclosed reconciliation with the countertop upstand so an overlapping region is never double-charged. Not yet wired into any quote or extras flow.
Quote Engine (foundation, not yet wired)
New dado-band calculation: per-span heights vary independently (no hardcoded universal height), named returns, and cut-outs that deduct from area only when the stated policy calls for it — a non-deducted cut-out is still reported, never silently subtracted.
Where a dado band coexists with a countertop upstand, the overlapping region is excluded from the dado area and the exclusion amount is disclosed, so it is modelled once and charged once.
Not yet imported or called anywhere in the running application — a foundation piece for a follow-up release that wires it into a quote's extras line.
Version 1.8.135
Migration 086: Profile System (code, version) unique index (NOT YET APPLIED to any host)
Adds api/src/migrations/086_quote_engine_profile_system_code_version_unique.js, the follow-up G01-S06 flagged: the (code, version) unique index the publish-race fix relies on only gets created automatically where Mongoose autoIndex is on (tests) -- pilot and production run with autoIndex off, so the index, and the duplicate-key-catch race guard that depends on it, do not exist on either host yet. This migration creates it explicitly, first refusing loudly (naming every conflicting row) if any legacy duplicate (code, version) pair already exists, so duplicates are resolved by human review rather than silently skipped or partially indexed. This release ships the migration FILE only. It has not been run against pilot, production, or any real database of any kind -- applying it to a host is a separate, owner-gated step per this repo's standing migration rules, to be done only after `node scripts/migrate.js --status` is checked on that host.
Quote Engine — Profile System publish-race guard (migration, unapplied)
New migration 086 creates the unique index qe_profile_system_code_version_unique on {code, version} in the quoteprofilesystems collection -- the exact name and key shape QuoteEngineProfileSystem.model.js already declares, so a later autoIndex-driven build and this migration are recognized as the same index, never duplicated.
up() aggregates for legacy duplicate (code, version) groups first and refuses to create the index if any exist, naming each duplicate group and its row ids so they can be resolved by review (keep one row, renumber the other) instead of the migration guessing or silently dropping data.
down() drops exactly this index and is idempotent (safe to run when the index was never created).
NOT applied to any host by this release. Both pilot and production currently read applied-through-053 and are unrelated to this migration's number; applying 086 anywhere is a separate, owner-gated step.
Verified only against an isolated in-memory MongoDB (mongodb-memory-server) in this migration's own test suite -- no real database connection was made at any point while preparing this release.
Version 1.8.134
Stone countertop run: net, purchasable and chargeable area kept distinct (foundation)
A new pure calculation module represents a stone countertop run as its own quoted object, keeping net geometric area, whole-slab purchasable area and the seller's chargeable basis as three genuinely distinct facts instead of one blended number, with joints adding no phantom material and no invented rates. Not yet wired into any quote or extras flow.
Quote Engine (foundation, not yet wired)
New countertop-run calculation: net area is geometric truth (only explicitly-marked openings are deducted; an L-corner overlap is charged exactly once), purchasable area follows whole-slab yield as a stated supplier fact, and the chargeable amount follows the seller's named basis — never a guessed rate.
Not yet imported or called anywhere in the running application — this is a foundation piece for a follow-up release that wires it into a quote's extras line.
Version 1.8.133
RND-01 bounded core: named compatible surface slots for finish attachment (G02-S06 r1)
A new pure module, finishSurfaceSlots.js, gives the finish-asset system a named slot vocabulary (front-face, body-face, back-face, edge, elevation-view), each declaring which asset types (sample/elevation/render) may legally occupy it. An attachment {slot, finishCode, assetType, assetSha256} pins the selected asset version by digest, never by a mutable pointer. Preview -> Discard/Apply: a preview never touches applied state, only one preview exists at a time, and Apply is the only writer. renderSignature(state) folds every APPLIED attachment through canonical key-sorted serialization so any applied change invalidates the render while a preview never does. Cost-ready/verified stay read-only derived facts, recomputed from caller-supplied evidence, never stored on the attachment. Zero importers by construction -- no regression surface.
Quote Engine — finish surface slots (RND-01)
SURFACE_SLOTS: front-face, body-face, back-face, edge, elevation-view -- each names its compatible asset types (the compatibility matrix); elevation-view is elevation-only.
validateAttachment({slot, finishCode, assetType, assetSha256}) refuses an incompatible occupancy naming the offending slot, refuses an unnamed slot, and refuses a missing or malformed sha256 digest.
preview()/discard()/apply(): preview() and discard() never produce a new applied object (verified by reference identity, not just deep-equality); apply() is the only function that writes a new applied state. A second preview replaces the first -- one preview at a time, no queue.
renderSignature(state) is insensitive to attachment key-insertion order and to slot application order (sorted before hashing), changes when any applied attachment genuinely differs, and is provably unchanged by the mere existence of a preview.
derivedFacts(state, {hasCost, verified}) is recomputed fresh from caller-supplied evidence on every call; the stored attachment object carries only {slot, finishCode, assetType, assetSha256} -- no cost-ready/verified field anywhere in state.
Explicitly out of scope (recorded, not resolved here): Design Engine renderer consumption of these slots, manufacturing grain locks, RND-02 upholstery mesh slots, and STONE/DADO/MEP (G02-S07's band).
Version 1.8.132
CNC-01: the Machining Design registry (G02-S05 r1)
A new, bounded-core data contract and service for machining designs (decorative-front and cnc-handle purposes, filtered from ONE append-only versioned registry, never two collections): draft -> technically-complete -> published -> revoked, with a Production-Manager digest-confirmation gate. Additive only, zero importers anywhere in the app or API (grep-confirmed) -- no regression surface by construction. An audit fix closes a real self-confirmation gap in the confirmation gate before release.
QuoteEngineMachiningDesign model: (key, version) unique, append-only; statuses draft -> technically-complete -> published -> revoked; purpose is decorative-front XOR cnc-handle, enforced both in the service's normalise/validate and again by the schema's own enum.
quoteEngineMachiningDesign.service: create() drafts version 1 with a digest; save() always creates the NEXT immutable version (a saved row never changes) and a revision re-enters the chain from draft; confirm() is the Production-Manager digest gate (library.verify permission, exact current digest or a 409); publish() only from technically-complete; revoke() is append-only -- a new version row carrying the reason, never a rewrite of the published row it supersedes; list({purpose}) returns latest-per-key, purpose-filtered.
Digest uses canonical recursive key-sorted stringification (the same fix an earlier audit found and fixed in G01-S24-r1's checksum utility) so the digest is over facts, not insertion order.
Audit fix (self-confirmation gap, found and fixed before release). confirm() checked only the library.verify permission string; it never compared the confirming actor's identity against the design's creator. A production-manager role that also holds create/save rights on this registry could self-confirm their own draft, defeating the stated 'the maker cannot self-confirm' design intent -- and unlike the sibling reference this slice explicitly claims to mirror (quoteEngineInlayHandleProfiles.service.js's confirm(), which layers an explicit maker-identity check on top of the route-level permission grant), no such identity check existed here at all. Reproduced directly: an actor who both created a design and was granted library.verify could confirm their own work. Fixed by adding an explicit createdBy-vs-actorId check (MACHINING_DESIGN_CONFIRM_SELF_FORBIDDEN, 403) alongside the existing permission gate. Also removed a dead, unused, misleadingly-named placeholder constant (VERIFY_PERMISSION, pointing at the wrong permission string) left over from drafting.
Independently verified beyond the slice's own suite, against a live MongoDB memory server: (1) append-only revoke -- constructed create -> save x2 -> confirm -> publish -> revoke, then read the published row's raw document directly and confirmed it is byte-identical (including updatedAt) before and after revoke, with exactly 4 rows on the key; (2) digest canonicalisation both directions -- same key, same facts, differently-ordered nested object keys produces the SAME digest, and a genuinely different geometry value on the same key produces a DIFFERENT digest; (3) the fixed self-confirm gate -- a maker holding library.verify is now blocked from confirming their own draft; (4) wrong-digest refusal -- a single-bit-flipped digest is refused (409) with no state corruption, and the correct digest still succeeds afterward; (5) purpose XOR -- both an invalid/typo'd purpose value and a missing purpose are refused.
Zero importers anywhere in api/ or app/ (grep-confirmed on the clean release worktree) -- inert until a follow-up slice wires routes/controllers/UI. CNC-02 (PU/veneer build-up costing), CNC-05 (pickers + wardrobe-bay refusal), CNC-06 (design inner pages), CNC-08 (reference sheets) and CNC-10 (M1/M2/M3 machine adapters) remain tracked follow-ups on this registry.
Version 1.8.131
Tall-front split datum, alignment and preset gate (G02-S04 r1)
A tall cabinet's front-row split now records who authored it: splitDatum labels each row as 'stated' or 'derived-fill', frontAlignment persists an alignment to a verified wall/appliance reference (a bare offset with no reference does not persist), and frontSplitPreset persists an owner-approved preset key verbatim. The preset registry is empty by design; an unknown preset key is refused rather than guessed into dimensions.
frontRows[].splitDatum: 'stated' | 'derived-fill' — additive labelling only; existing heights, bottoms and digests of stated inputs are unchanged.
cabinet.frontAlignment: {reference, offsetMm} — an alignment to a verified wall/appliance reference, stable through re-normalise. A bare offset with no reference does not persist (offsetMm alone means nothing).
cabinet.frontSplitPreset — an owner-approved preset key persists verbatim for review. TALL_FRONT_PRESETS is empty by design; no preset values are invented ahead of owner approval.
Audit fix: the preset registry, as ported, was checked only at the cabinetry.add seam. A cabinet can also arrive via kitchen.add/wardrobe.add's initial cabinets/modules list or via cabinet.add placing a single cabinet directly, and all three bypassed the check entirely — layout.js's normaliser persists any non-empty frontSplitPreset string verbatim with no validation of its own. Confirmed by constructing an unknown-preset input against each of the three seams before fixing. Fixed by sharing one guard (unapprovedFrontSplitPreset) across cabinetry.add, kitchen.add/wardrobe.add and cabinet.add; a new regression test reproduced red against the unfixed, ported code and green after the fix.
The pre-existing frontRows 8-row contract, kind vocabulary and overfill reporting are untouched — confirmed by diffing the touched files against origin/main: only additive lines were introduced.
Verified directly (not just via the slice's own tests): cross-slice coexistence in commands.js's cabinetry.add handler with G02-S02's already-merged mixed-mode leaf-size check — both checks are separate, sequential, non-overlapping guards; neither shadows the other.
Version 1.8.130
B2B-04: edge-tape BOM follows the supply scope (G02-S03 r1)
The edge-tape bill of materials now scopes by the revision's supply scope (complete/cabinets/shutters-only), matching the commercial total, cut list and panel schedule, which were already scope-correct. Audit found and fixed three real defects beyond the slice's own claims: the scoped ORDER length (not just net length) silently reverted to the unscoped total whenever a tape-order purchase allowance was configured; the per-collection shade attribution misattributed metres between collections on a partial-scope order; and every decorative drawer front was misclassified as carcass instead of shutter tape because the split read the wrong internal role variable.
Quote Engine — B2B-04 edge-tape scope
edgeTaping.applyEdgeStandards splits every tape need by the contributing part's selling role (front / drawer-front / cover = shutter, everything else = carcass — the same SHUTTER_ROLES commercial.js already scopes by), adding shutterLengthMm/carcassLengthMm alongside the unchanged lengthMm total. Cut sizes, edge flags and the calculation digest are untouched; the split is additive reporting, verified structurally (not just by hash) by diffing the full resolvePlanning and calculateQuoteRevision results before/after across five wardrobe fixtures: only the two new leaf fields differ anywhere.
buildMaterialList reads the revision's supplyScope (from result.planning.commercial, the same source the panel schedule uses) and scopes the edge-band BOM: net and order length follow scope, a fully-excluded tape produces no zero-metre line, a partially-excluded tape discloses scopeExcludedLengthMm. Complete-scope orders are behaviour-identical.
Audit fix 1 (severe, undisclosed): the ORDER length must scope too, not just the net length. The ported diff read result.planning.edgeTapes[].orderLengthMm unconditionally whenever a tape-order purchase allowance was configured (edges.tapeOrder.endAllowanceMm/wastePercent — a real, confirmable production parameter, exercised by quote-engine-edge-taping-drawers.test.js:261), bypassing the whole scope split: netMetres/orderMetres/amount came out IDENTICAL across complete/shutters/cabinets, silently re-buying the excluded side's tape — reproduced directly before fixing. edgeTaping.js's orderQuantity now also returns shutterOrderLengthMm/carcassOrderLengthMm (the same allowance applied to the scoped length and edge-run count), and materialList.js reads the scope-appropriate one.
Audit fix 2 (severe, undisclosed): drawer fronts were misclassified as carcass tape, unconditionally, on every quote using the modern (schema-19) configuration. The role passed to the shutter/carcass split was edgeTaping's own internal edge-table lookup key (roleOfPart(), used for table[role]/FRONT_LIKE checks — a different vocabulary), not the part's actual selling role (part.role, the field commercial.js's SHUTTER_ROLES and panelSchedule.js check). Schema 19 maps drawer_front to the lookup key 'drawerFront' (camelCase) while the part's real role is 'drawer-front' (hyphenated) — the two never match, so every decorative drawer front's tape landed on the carcass side of the split regardless of true scope. Fixed by classifying from part.role instead; reproduced with a direct repro before fixing and confirmed against the existing edge-taping-drawers regression suite (a shutter leaf + drawer front split evenly 1544/1544 shutter/carcass before the fix; both correctly shutter-scope after).
Audit fix 3 (net-vs-order regression, undisclosed): the ported diff also collapsed materialList.js's existing net-vs-order distinction — netLengthMm accumulated the order-preferring (waste/allowance-inflated) length instead of the scoped net length, for every scope including 'complete'. Restored: netMetres now stays the physical net (scoped only, never allowance-inflated); neededMetres/orderMetres/amount stay the order-preferring figure. Caught by an existing, unrelated pin (quote-engine-material-list.test.js: netMetres 61 vs neededMetres 64 for a 61000/64000 mm need) that the slice's own regression run never exercised.
Flagged-but-not-fixed item verified: the byCollectionMm shade split previously ratio-scaled the combined (role-unsplit) per-collection map across every collection uniformly — this DOES misattribute shade metres whenever two different collections (different shades) contribute to the same tape spec under a partial scope (reproduced: a shutters-only order attributed 0.29 m of a fully-excluded carcass collection's shade, none of it real). Fixed alongside the other two: applyEdgeStandards now also splits byCollection by role (byCollectionShutterMm/byCollectionCarcassMm), and materialList.js reads the scope-appropriate map directly instead of ratio-scaling.
Five existing tests updated to reflect the new (correct) additive shape/values, with each divergence individually verified as expected rather than silenced: three shape/value pins in quote-engine-edge-taping-drawers.test.js (the new shutterLengthMm/carcassLengthMm fields), and five golden resolvePlanning/calculation digests in quote-engine-wardrobe-bottom-thickness.test.js (regenerated after a structural diff confirmed only the two new additive fields moved, nothing else).
A shutter leaf can now state a finished size directly (gaps already adjusted) as a second, explicitly persisted input mode alongside the existing cabinet/opening-derived width. The two modes are mutually exclusive per leaf and refused loudly, before the layout changes, wherever a leaf is written.
Quote Engine — B2B-02 shutter leaf sizing
leafSpecs[].finishedMm: {widthMm, heightMm} — "Finished shutter size (gaps already adjusted)", normalised in normaliseLeafSpecs as all-or-nothing: both axes must be a positive number or the mode voids to null, never a silently halved size. Stable through normalise -> serialise -> normalise, and the pre-gap widthMm is never fabricated in finished mode.
isDerivedLeafList now treats a stated finishedMm as authorship, so a finished-mode leaf is never silently re-derived out from under it.
The two size input modes (cabinet-derived vs. finished-size) are mutually exclusive per leaf, refused before the layout changes at BOTH command seams that can write a leaf — cabinetry.add and cabinet.update — naming the offending leaf in the refusal message.
Audit fix: the cabinet.update seam's mixed-mode check, as authored, was unreachable (pasted after an unconditional return inside the leaf shape-validation block), so that seam silently accepted a contradictory leaf despite the slice's own claim both seams refuse it. Moved to a sibling block that runs whenever leafSpecs is a valid array; a new regression test pins the fix and a red run against the unfixed code confirmed it would have caught the gap.
API-first: the workspace UI picker for the two modes, front-count/unequal-leaf arrangement overlays, and resolved finished-vs-machining-blank reporting remain follow-up scope (B2B-02's remainder) — not part of this release.
Version 1.8.128
Profile System master: memberProfiles and stileDeductionMm now persist (SYS-04)
The Profile System master's save path silently dropped two fields the profile-shutter calculation actually reads (per-member handle/hinge-stile/rail profile facts, and the rail-deduction fallback), so authored values could never reach the calc regardless of what an operator entered. Both now persist through create and every subsequent version. Also closes a related gap: a door-system hardware preset could not be saved at all because its family was missing from the model's enum.
Quote Engine — Profile System master
memberProfiles (handleStile / hingeStile / rails — profileCode, faceWidthMm, depthMm, kgPerMetre, stockLengthMm, handleProjectionMm, glassDeductionMm) and stileDeductionMm now persist on create and save; previously pickBody dropped both, so they could never reach calc/features/profileShutter.js or profileShutterProduction.js regardless of what was authored.
Sparse by design: only facts an operator actually states are stored; absent stays absent, never defaulted or invented.
QuoteEngineHardwarePreset's FAMILIES enum now includes door-system, matching the hardware registry that already serves that family — a door-system preset previously failed validation outright.
API-first: the Profile System editor UI does not yet expose these two fields; that is a tracked follow-up, not part of this release.
Version 1.8.127
Dimension constraint resolver: a single, shared evaluator (foundation)
A new pure, dependency-free evaluator (evaluateDimensionConstraints, classifySelectionMm, separateDimensionFacts) implements the dimension-constraint contract from DIMENSION-CONSTRAINT-PLAN.md, so the Design Library resolver, the quote-local dimension-selection service and the definition validator will all share one answer instead of independently re-implementing the rules. This release adds only the evaluator itself — nothing in the running app calls it yet, so there is no user-visible or behavioral change.
Design Engine (foundation, not yet wired)
New dimension-constraint evaluator: exact-value membership for 'in' constraints (never coerces or rounds — a 250mm request never matches a constraint requiring 240mm), and exact-triple qualified-profile matching (a width/height/depth combination is checked as one whole triple, never as three independent per-axis memberships).
Not yet imported or called anywhere in the running application — this is a foundation piece for a follow-up release that wires it into the Design Library model, controller and publish-time validation.
Version 1.8.126
Engine Configuration Cockpit: a real settings directory for Design/Quote Engine setup
A new read-only directory screen at Application Settings > Engine Configuration gives admins one place to see setup status, jump to configuration areas, and check import/activity surfaces for the Design and Quote Engines — discoverable from the Application Settings hub, which previously had no such link wired to render.
Application Settings — Engine Configuration
New Overview, Setup checklist, Configuration, Imports and Activity tabs at /platform/engine-configuration.
Overview shows real setup-checklist KPIs (no invented blended readiness percentage); Configuration lists real routes/permissions per area; Imports lists only the import surfaces that exist today.
Fixed: the Application Settings hub's link to this screen is now actually visible and permission-gated in the running app (previously wired only into a config array the settings page's own grouping logic did not render).
Version 1.8.125
Panel Library: five recorded contract gaps closed
Five previously-recorded Panel Library contract gaps, each re-audited against current code before being credited: two processing-rate field mismatches that made a save fail, a handle-profile Save/Adopt permission gate that relied on a raw 403, and a profile-system publish race that could silently write two rows for the same version. A fifth recorded gap (an AIR-pocket location hint) was found already resolved by concurrent work and closed as a recheck, not a re-fix.
Panel Library — Processing rates
The master editor's "Gross / cut area" option now sends the model's real value (gross-part), which could never save before.
Decimal places is capped at 3 (was 0-6), matching the model, with a relabelled field and hint stating the cap.
Panel Library — Handle profiles
Save and Adopt now disable, with a visible reason, for a user without Production Configuration update access — the same grant the backend already requires. Previously both rendered enabled and a 403 was the only signal.
Panel Library — Profile systems
Publishing a change to a profile system now states the version it was loaded from; a concurrent save is refused and named (current version vs. the version edited), instead of silently stacking on top.
A genuinely concurrent duplicate write is refused by the database itself, not by a check-then-write that can race.
Version 1.8.124
Design Library: two construction-system fields can no longer be edited on a published system
Two persisted, whitelisted Design Library construction-system fields (Edge treatment policy and Calculation strategy key) could be silently changed on a published construction system via a direct API call, bypassing the version-on-publish rule every other field already enforces. Both are now visible in the editor and locked exactly like the rest of the form once published.
Design Engine — Library Admin
Construction systems gain two labelled fields: Edge treatment policy and Calculation strategy key, with help text, styled like the rest of the form.
Both are editable on a draft and locked once the system is published, the same as every other field on this form.
A direct edit to either field on an already-published system is refused, the same way every other locked field already is.
Version 1.8.122
Panel Library: Columns menu matches rendered thickness heading
The Columns menu's thickness entry now says "Finished" exactly when the rendered table heading does, and a load-sequencing token closes a stale-response race on rapid archived-status toggles.
Quote Engine — Panel Library
The Columns menu's thickness entry now reads "Finished" exactly when the rendered table heading does (shutter and profile-glass Type filters), instead of always "Body / back" — a reader toggling column visibility under a shutter filter no longer sees a menu entry naming a column the table isn't showing.
A monotonic load-sequence token closes a latent stale-response race: a superseded list-load response (from a rapid includeArchived toggle) can no longer overwrite state written by a newer one.
Verified bullet-by-bullet against the binding PL-01..04 content spec (file:line evidence in output/amendments-02-03-04-execution/slices/G01-S02-r1/PARITY-PL01-04.md); the five-tab shell and matrix/inspector were already implemented on main.
Version 1.8.121
Panel Library: sheet material picker shows only eligible board SKUs
Picking the material a panel's body, back or panel sheet is cut from now shows only eligible board SKUs, instead of an arbitrary first catalog page. The same eligibility is enforced on save.
Quote Engine — Panel Library
The Body and Back sheet-material picker now shows only board SKUs from the categories Production Configuration's Materials & consumables rules map to a panel sheet, instead of the catalog's first page (which could include paints, laminates or glass).
Saving a panel definition with a sheet material outside those categories is refused, naming the exact field.
When Materials & consumables maps nothing yet, the picker says "Configuration needed" instead of showing an unfiltered or empty list.
Version 1.8.120
Quote Engine rebuilt to the approved screens and quotation documents
Parity 2, drop 2 of 2. The Quote Engine screens (form previews, the approved Phase 2 screens, bundle visuals) and the customer quotation documents now follow the approved references: the Quote Engine's own side menu, the kitchen and B2B tab layouts, the quotation letterhead and layout, and per-component pricing. Issued quotations from before this release still print exactly as issued.
Quote Engine — navigation and screens
Inside the Quote Engine, its own side menu replaces the main menu, as in the approved screens: Command Center, Process Flow, Projects, Quotes, a Workspaces group, Panel Library, Products & Fittings, Pricing, Production Configuration, Assets and Settings. Phones and the top-navigation layout keep their usual navigation.
Kitchen configure has the approved tabs: Layout, Components, Materials & finishes, Fittings, Pricing, Assets. Collections and Assignments moved under Materials & finishes; Internals moved under Components. Old links to those screens still work.
The B2B quote's tabs follow the approved screen: Project setup, Blocks & elevations, Cabinet lines, Production, Commercial, Documents. Labels & packaging now lives inside Production.
Kitchen cabinets can now choose how an exposed side is finished (a cover panel or a replacement side), the same way B2B cabinets already could.
Command Center and Process Flow are rebuilt. A new page shows an OEM drawer's cutting profile in detail. Stage indicators show their status as a word, not only a colour.
Fixed a pricing bug: some cabinet body (carcass) lines were being counted as "Other lines" instead of their own line.
Quotation documents
The quotations we issue to trade partners (concise and detailed) carry our company letterhead. The optimizer report and the retail presentation stay unbranded, for partners to pass on to their own customers.
Quotations print the pricing basis by name only, with no rates or internal figures.
The detailed quotation shows a price for each component, based on its share of the area's cost.
Two new fields, Included scope and Assumptions, can be set once in Production Configuration and adjusted per quote.
Quotations issued before this release print exactly as they did before; nothing about an already-issued document changes.
Version 1.8.119
Doors & Millwork in the Quote Engine
A new Doors & Millwork workspace in the Quote Engine takes a door or millwork job from site measurement to production. Frames, leaves, architraves, glazing, sliding and entrance doors, trims and panelling are engineered from one calculation, which produces the drawings, cutting lists, stock plans, BOM, release, labels and packing.
Jobs and measurement
An overview and a jobs register, with readiness, attention items and quick filters.
Opening schedule, site measurement (mm, inches or feet and inches), evidence records with discrepancy review, and a phone-sized survey screen.
Create a job from a quotation, or start without one and link it later.
Engineering
Editors for frames, leaves, architraves, faces and finishes, hardware, glass and inserts, sliding doors, entrance assemblies, trims and mouldings, and panelling.
A construction and profile library with versioned recipes, tests before publishing, and read-only published versions.
Every dimension comes from the calculation, and every member shows how its length was worked out.
Outputs and production
Drawings, cutting list, linear stock plan with remnants, BOM and purchasing view.
Release review by scope (frame, leaf, architrave), with blockers listed. An issued revision is fixed; later changes go through a new revision, and pieces already cut need a recorded decision.
Production work package, quality and installation inspection, reports, labels and packing, and a part lookup that warns when a label is out of date.
Panel nesting, stock reservation and photo uploads are shown but not active yet.
Version 1.8.118
Design Engine rebuilt to the approved screens and proposal drawings
Parity 2, drop 1. The Design Engine workspace and its proposal drawing sheets now follow the approved concept screens and the proposal PDF: its own side menu, the 3D workspace with labels, fitting callouts and an exploded view, per-unit notes, and proposal sheets laid out like the approved pages. The Quote Engine rebuild follows in the next release.
Design Engine — workspace
Inside the Design Engine, its own side menu (Home, Quote, Design, Files, Settings, New design, Overview) replaces the main menu, as in the approved screens. Phones keep their usual navigation.
3D: unit, beam and column labels, numbered fitting callouts with a matching list, front colours from the chosen finish, an exploded view, a brighter daylight scene, and the selected unit outlined in blue.
Wardrobes: Location, Module type and Loft doors in the inspector, using the existing move and configure commands.
Each placed unit has a Notes field (up to 500 characters, with undo and redo). Notes print on proposal sheets.
A unit whose drawers replace its doors now says so in the inspector instead of listing shutters it does not have.
Files opens the drawing list for the open revision.
Design Engine — proposal drawings
The Drawings tab shows the drawing package for review: the chosen sheet as a real PDF preview, the standard sheet list, and one-click download of the whole proposal PDF.
Proposal sheets follow the approved pages: an identity band, the plan filling the sheet at 1:25, one run chain with fillers and clear space, the beam drawn as an overhead outline with its underside level, column blocks, the worktop line, elevation and section markers, door swings, and legend, view-pairing and unit-notes panels.
Elevations use one clean dimension chain. Internal elevations draw beams and columns and tag shelves, drawers and rails with their heights. A composite run section is added, and schedules are laid out like the approved schedule pages.
Production sheets are unchanged.
Application settings
An "Outbound email sending" switch under Transactional Email can pause every outbound email, reminders included, without touching the mail server settings. It is on by default.
Version 1.8.117
Design Engine drawings and fittings; Quote Engine wardrobe, panel and output upgrades
Amendment 01. The Design Engine gets focused-room editing, a top band with the four design outcomes, true drawer positions, site and corner detail, door operation notation, a technical 3D mode, fitting picks from the hardware library, and complete drawing sheets with schedules. The Quote Engine gets a separate wardrobe bottom panel, sliding track lengths, OEM documents, handle finish, profile + glass shutters priced per door, and richer optimizer and retail quotation output.
Design Engine — workspace
A top band shows the project, revision and real status, the four outcomes (Set up room, Place furniture, Check design, Share & produce) with progress, and a room picker.
Everything follows the room in focus: the tree, plan framing, walls, elevations and site lists. Picking a wall in another room moves the focus there. Rooms drawn only by walls now show their walls.
Beams and pillars can be edited. Site items show on a wall only where they touch it, and unsupported shapes are listed instead of hidden.
Technical 3D mode: labelled layers (fronts, guides, interiors, fittings, beams, pillars), an open-angle slider, a legend, and a note that guides are not collision proof or drilling locations. Doors open outward; sliding and roller doors slide or roll.
Fittings: magic corner, bottle pull-out, dish rack, roller shutter, sliding doors, loft hardware and locks can be picked per unit from the hardware library, plus a Gola C/J type. A fitting is re-checked when the unit is resized.
Wardrobes show key heights: floor to storage, loft height and beam clearance.
Drawers on base units are measured from the top of the toe-kick.
Design Engine — drawings
Drawing sets refuse a calculation run that no longer matches the design, and report when room, wall or fitting edits have changed the drawing context.
Custom drawer fronts are drawn at their real positions; overlaps and out-of-bounds drawers are reported. Each unit and each wall gets a fronts-removed internal elevation.
Base, overhead and loft plans appear only when that tier has units. Every page has a title block with revision and page numbers.
Wall elevations show fronts and opening guides. The BC-2 corner shows its return on both elevations and is counted once; the dashed X appears only where a marker states that convention.
A separate Schedules PDF starts with a drawing index and lists units, fronts, fittings and site items, with no costs. PDF and DXF match view by view; dimension labels no longer overlap.
Quote Engine
Wardrobes can state their own bottom-panel thickness, priced from the carcass collection's board of that thickness (or shown as a gap).
Sliding track lengths are calculated from the sliding system, with a "Use current library values" refresh. OEM documents (PDF, DWG, ZIP up to 50 MB) can be uploaded and downloaded on the cutting profile.
Handle finish (matches shutter / different finish) per box on kitchen, wardrobe and planner screens.
Profile + glass shutters are priced per door at their own size from their parts: frame wastage only, no glass wastage, assembly separate. Cabinets inherit the profile, glass and finish from the panel definition unless overridden.
Panel Library: profile shutter build-up card, revision cost comparison, "which quotes use this panel", optional moisture-resistance and applications fields.
CAD planning: opening head level, rear-column and rear-beam figures, a rejected-placement strip with a correction hint, and wardrobe alerts kept to their own wardrobe. New B2B cabinets take their block's collections.
Optimizer print pack shows job facts, KPIs, material summary and remnants. Newly issued retail quotations show cleared finish sample photos and the project's own proposal brief; earlier quotations reprint unchanged.
Version 1.8.116
Forms use the main header and footer; Gmail-style Email
Every full-page form now puts its title in the app's main header and its Save/Cancel in the main footer, the Email screen gets the approved Gmail-style layout on top of all its phase 1–5 features, and the Quote Engine gains shade pickers on the wardrobe and B2B screens, the full Ebco price list and working part-rule functions.
Across the app
While a form is open, its title and breadcrumb sit in the main header and Save/Cancel sit in the main footer, with an "Unsaved changes" warning — now on 128 forms (settings pages, record editors and list-and-form screens).
Save stays on the page when a screen is opened inside the HR Setup Wizard.
Several settings pages no longer keep showing "Unsaved changes" after a successful save.
Email
Gmail-style mailbox: Inbox, Starred, Sent and Drafts first, then More; a rounded message list; threads with sender avatars; a floating compose window you can minimise.
Clear "Folders unavailable" and "Couldn't load messages" states with Retry, and a slow reply can no longer overwrite the message you just opened.
Quote Engine
Shade pickers on the wardrobe Panels & thickness tab and on B2B Quick Quote collections.
Part rules can use if, min, max and round.
Production configuration links to the Shade library; cabinet-library verification states show coloured badges.
Price lists and setup data
The full Ebco MRP June 2026 price list (2,982 items).
The shade library and the Inox 2026-27 price list load automatically on a new installation.
Version 1.8.115
Main and the production release line reunited; Hardware Library search
Production's release line (1.8.109–1.8.112) and main are one line again, so nothing live is lost: the opportunity detail redesign, email phases 1–5, honest margin figures, CRM single create, the scoped reporting period and payslip PDFs stay, and main's work since 1.8.108 arrives with them — the Hardware Library search workspace, Files (behind its flag), WhatsApp support, Meet links for CRM and the contract-audit fixes.
Quote Engine
Hardware Library: one search over SKUs, makers' systems and presets, with suggestions, filters (brand, series, family, stock, verification) and a details panel.
Compare SKUs, use a SKU or a preset in a draft quote, collections, CSV export, and draft review with maker-checker.
Boards & laminates have their own search page.
Kept from the live release line
Opportunity detail redesign; one primary create action on Leads and Contacts.
Margins are shown only where a cost was captured; the reporting period appears only where it applies.
Payslip PDF downloads (printing another employee's payslip needs permission to view compensation).
Also arriving from main
Files application (off until enabled); the File Manager stays at the same place until then.
WhatsApp client-support workspace; Meet links on CRM appointments and demos.
Contract-audit fixes across Sales, Purchase, HR, CRM and Files.
Version 1.8.114
Quote Engine hardware priced from the Item library, Phase 2 B2B cabinetry, Files, Email and WhatsApp
Quote Engine hardware (Gola, door systems, straighteners, profile doors) now prices from the maker price lists in the Item library; Phase 2 B2B cabinetry and the editable hardware library land; Files, the Gmail-style Email workspace, WhatsApp support and Meet links for CRM arrive; contract-audit fixes across Sales, Purchase, HR, CRM and Files.
Quote Engine
Hardware is priced from the Item library by the maker's article number: Gola caps, connectors and bars, door straighteners, pocket and folding door kits, and profile doors. Prices are frozen on each revision, and issued quotes do not change.
Häfele, Hettich, Ebco and Higold price lists are loaded into the Item library.
Profile-glass doors are priced at the shutter definition's rate per sq ft, or from their parts and the glass master when no rate is stated. A missing price is shown, never treated as free.
Editable hardware library with maker-checker verification; OEM-seeded hinges, Gola profiles (including LED-ready Häfele Déco), straighteners, frame profiles and floor-to-ceiling pocket and folding doors.
Phase 2 B2B cabinetry: per-edge banding, processing, PU, glass and profile masters, wall-run cabinets in project areas, and the B2B quick quote.
Production Configuration lets the owner apply the 24 September construction and hinge decisions to a draft and publish them.
Panel definitions: price-list PDF and Excel/CSV import-export; Coverage lists every capability the engine declares unsupported.
CRM: create, join and cancel Google Meet links on appointments and demos; WhatsApp templates re-check consent at send time.
Contract-audit fixes across Sales, Purchase, HR, CRM and Files (money, authorisation and correctness).
Version 1.8.112
Honest figures, simpler creating, and a tidier top bar
Numbers nobody measured are no longer shown as facts, creating a lead or contact takes one button and fewer fields, and the reporting period only appears on screens that use it.
Quotes and estimates
Margin now shows a dash, not "100%", on estimates where no cost was ever captured — the old figure was arithmetic on a missing number, not a measurement.
Customer 360 and the quotation screen follow the same rule, so one quote reads the same everywhere.
Board and processing costs are hidden from people without permission to see cost, matching how the rest of the quote already behaved.
Creating records
Leads and Contacts now have a single "New lead" / "New contact" button instead of two competing ones, matching every other list.
The quick contact form asks for the details it needs rather than around eighteen, with the full form one click away.
Everywhere
The reporting period picker appears only on screens that actually use it, instead of sitting in the top bar marked "not used here".
Buttons and expanders on the opportunity page are large enough to tap reliably on a phone.
Training dashboard opens instead of failing for organisations whose employee records store a department differently.
Version 1.8.113
B2B cabinetry, processing costs and a large batch of fixes
The Quote Engine's B2B cabinetry work arrives in full, processing is priced instead of silently costing nothing, and a backlog of stock, manufacturing and sign-in fixes lands with it.
Quote Engine
B2B cabinetry: projects and cabinet lines, panel construction, the component library, the optimizer, labels and packing, factory order sheets and the three quotation formats.
Processing is now priced. The rate master was empty and nothing fed it into a quote, so every quote costed processing at nothing; it now carries the factory's rates, and says so plainly when none are set up.
A fascia rate can be entered on any carcass definition, not only on ones priced by fascia area.
Board and processing costs are hidden from people without permission to see cost.
Stock and manufacturing
Stock held for one order can no longer be consumed by another.
Duplicate part scans are rejected by the database rather than by timing, and reversals are guarded.
Delivery challan confirmation and reservation claims are safe when two people act at once.
Searching stock with special characters no longer misbehaves.
Elsewhere
Employee records whose department was stored in the wrong format are repaired, so the training dashboard opens.
Sign-in: an account is locked after repeated failures, and addresses stored in the older format still work.
Two-factor confirmation accepts a code that has just rolled over, as the other screens already did.
Emails with non-English filenames download instead of failing.
The opportunity page shows each fact once, only what someone actually entered, and one clear next action. Email gains privacy-safe images, real conversation threads, folders, sorting and keyboard shortcuts. Dashboard figures read correctly.
CRM opportunities
One header with the deal's stage, owner, value and expected close — each shown once.
Values nobody has entered are shown as "Not set" instead of system defaults (no more 20% probability on a ₹0 deal).
One main button that suggests the next step: add a next step, log what happened, plan a survey or create an estimate.
A To-do list with a button for each missing item, and fewer tabs: Overview, Activity, Documents, and After the sale once the deal is won.
Plain wording everywhere instead of internal codes; removing a competitor or stakeholder asks first.
Email
Images from outside senders stay hidden until you choose Show images; embedded images display.
Conversations include your own replies from Sent.
Create, rename and delete folders; move messages to any folder.
Sort by date, sender, subject or size; keyboard shortcuts (press ? to see them).
A wrong mailbox password is reported as a settings problem, not a system error.
Dashboards
Rupee amounts show as ₹21,600 with Indian digit grouping.
Compliance tiles use plain labels and consistent e-invoice counts.
Meet: the reason it is unavailable is shown on the page, not only on hover.
Every tool in the Tools menu is now real: a Files browser with Save to Drive, WhatsApp in the CRM inbox, Meet links on appointments and Website Chat. Email gains search, party search and rich-text compose; To-Do is rebuilt around correct due dates; staff can download payslips.
Tools
Files: one place for your uploads, work documents, HR documents and exports you are allowed to see, with search, filters and download. Save to Drive once Google is connected.
WhatsApp opens the CRM inbox filtered to WhatsApp. Sends use approved message templates, respect each contact's consent and opt-outs, and the settings page can test the connection.
Meet: create a Google Meet link for an appointment or demo and join it from the appointment or the calendar. Needs Google Workspace connected with Calendar.
Website Chat opens the support chat inbox for visitors on your public site.
Google Workspace settings show which permissions were granted and offer a reconnect when one is missing.
Email
Search by sender, recipient, subject, body, date, attachments and folder — or across all folders.
Search by company, contact, lead or deal to see every email with them.
Rich-text compose with your signature, address suggestions from your contacts, and forwards that keep the original attachments.
Undo send for a few seconds after sending.
To-Do
Due dates show on the right day in every time zone, in the list, the calendar and My Day.
Edit tasks, search, filter, sort and page through them — also in Team Tasks.
A failed action now says so instead of silently reverting.
HR and operations
Payslips can be downloaded as PDF from your profile, and by HR with compensation permission.
Stock and dispatch integrity fixes for inventory, manufacturing and fulfilment.
Version 1.8.109
Sign-in, Prospect Pool, email tools and reliability fixes
Staff can sign in with any email address as typed; the Prospect Pool shows only prospects, not existing customers; Email gains print, download, headers and per-message actions; screens that were failing now load; permission and approval checks are tighter.
Sign-in and security
Staff sign-in matches the email address exactly as typed. Addresses with dots or +tags (Gmail, Outlook) no longer get "Invalid email or password" with the right password.
Role and approval changes are checked more strictly against the person making them.
Test-only message providers cannot be used on production.
CRM
Prospect Pool lists prospects only. Organisations already linked to a Party no longer appear there, and opening one takes you to its Party record.
The CRM Reports export button no longer stays on "Exporting…" after a failed export.
Kanban boards say when they are showing the first 200 of a larger set.
Prospect Intelligence and CRM Command Center views load reliably.
Email
An opened email shows the sender's address next to their name, and CC recipients.
Print, Download .eml and View headers on every message; Archive, Trash, Spam, Restore and Star on the message and in bulk.
Sent messages always carry their full text in both formats (previously a saved signature could replace the body in some mail apps).
Connection problems now say what went wrong: wrong password, untrusted certificate, server not found, or timeout.
Downloads of messages and attachments with non-English names work.
Platform
Screens for switched-off modules say the module is switched off instead of showing an error with a Retry button.
Linked settings links on module configuration pages open reliably.
Error messages across about 60 screens now show the server's explanation.
The Training dashboard, Role views and Support overview load again.
HR: employee pickers page through the full roster; bonus exports respect compensation permissions.
Version 1.8.108
Update banner clarity and deploy build fix
The app update strip names version and build and links to Version & changelog; CRM prospect verification settings compile for pilot/production builds.
Platform
PWA update banner shows version and build stamp with a link to /platform/release-notes.
CRM prospect verification operations panel: social provider row typing fix for Angular production builds.
Version 1.8.107
CRM Settings tab hash sync
Same-path ?tab= navigation reloads the route; CRM Settings reads tab from hash when router query lags.
CRM
navigateRouteTarget uses onSameUrlNavigation reload for query-only hash changes.
Platform CRM Settings syncs activeTab from router and window.location.hash.
Version 1.8.106
Linked settings router sync
Business module Linked settings use erpHashLink so the Angular router runs the destination, not only a hash URL change.
Application Settings
Linked settings Open links use erpHashLink (followRouteTarget + router confirm fallback).
confirmRouteTargetNavigation re-navigates via the router when a hash-only assign left the old view visible.
Version 1.8.105
CRM settings hash links with query-aware fallback
CRM Settings cards, picklist tabs, and the CRM header Settings menu use erpHashLink so native hash navigation is confirmed including ?tab= switches; hard assign runs when the hash did not change.
CRM
confirmRouteTargetNavigation compares the full hash (path + query), not just the path segment.
Shared erpHashLink directive on CRM settings destination cards and workspace tabs.
Version 1.8.104
Linked settings match Run setup wizard
Open links use routerLink + queryParams like the working wizard control, with confirmRouteTargetNavigation hard fallback after SW mismatch.
confirmRouteTargetNavigation assigns full hash URL if navigation did not stick.
Version 1.8.103
Native hash href for Linked settings
Open links rely on native hash navigation instead of click handlers that blocked the browser when the router silently no-opped.
Application Settings
Removed openLinkedSetting preventDefault from Linked settings anchors.
navigateRouteTarget verifies hash after navigateByUrl.
Version 1.8.102
Hard hash navigation fallback for SW mismatch
Linked settings fall back to location.assign when the router refuses navigation after a service-worker chunk mismatch.
Application Settings
navigateRouteTarget uses hardHashNavigate when navigateByUrl fails.
Version 1.8.101
Explicit hash navigation for Linked settings
Open links call navigateByUrl with a location.hash fallback instead of relying on routerLink under the service worker.
Application Settings
followRouteTarget / navigateRouteTarget in route-target.util.
Linked settings anchors use hash href + click handler.
Version 1.8.100
Single-path route targets for hash routing
Route targets use one absolute path command so Linked settings Open links navigate under hash routing.
Application Settings
parseRouteTarget emits /platform/... as a single router command.
Linked settings use row.linkPath + row.linkQuery on the anchor.
Version 1.8.99
Linked settings routerLink parity with setup wizard
Linked settings Open links use single-path routerLink commands like Run setup wizard, not hash-only anchors.
Application Settings
linkedSettingCommands() emits one absolute path per Open link with queryParams for returnTo.
Module settings and Manage territories use the same routerLink shape.
Version 1.8.98
Native hash href navigation for settings links
Business Module and CRM settings Open links use hash href anchors only; no routerLink or click interceptors.
Application Settings
Linked settings and module settings are plain hash anchors with returnTo preserved.
Fix actions still use Router.navigate with segmented commands.
CRM
Settings destination cards and Settings menu use hash hrefs.
Version 1.8.97
Hash-routing link navigation repair
Business Module and CRM settings links use routerLink plus Router.navigate with queryParams instead of navigateByUrl on combined URLs.
Application Settings
Linked settings and Open module settings match Run setup wizard routerLink bindings.
Fix actions use Router.navigate with queryParams, not navigateByUrl on serialized query strings.
CRM
Settings destination cards and overflow menu entries navigate with Router.navigate([path], { queryParams }).
Version 1.8.96
Business Module settings link navigation
Linked settings and module settings Open links route reliably under hash routing via navigateByUrl.
Application Settings
Linked settings and Open module settings use hash hrefs with navigateByUrl; fixes 1.8.94 routerLink no-ops.
Module detail Fix actions use the same route-target navigation helper.
Version 1.8.95
CRM module Linked settings hash navigation
Linked settings Open links navigate via hash hrefs; route targets use single-path router commands.
Application Settings
Business Module Linked settings use hash hrefs without a broken click handler; returnTo is preserved.
parseRouteTarget emits one absolute path command for hash routing parity with setup wizard and Fix actions.
Version 1.8.94
CRM module Linked Settings router links
Module detail Linked Settings Open links use Angular router links with query params for reliable tab deep links.
CRM
Linked Settings on Business Module detail pages navigate with routerLink and queryParams instead of hash href workarounds.
Version 1.8.93
Quote Engine P1 integrity and export audit
Lifecycle uniqueness, issue and party/GST guards, decision ledger, export artifact audit trail, and pilot library qualification on the Quote Engine API.
Quote Engine
One draft and one issued revision per quote with compare-and-swap lifecycle writes.
Unified artifact export audit for proposal, proforma, cut-list and drawing outputs.
Pilot qualification metadata on catalogue rows with buildable planning anchors.
Version 1.8.92
CRM settings navigation
CRM Settings cards and sidebar links open the right tab; child settings routes match; Back respects returnTo.
CRM
Settings destination cards and menu links split query params so tab deep links work.
Picklist section tabs are router links; the settings menu navigates without losing the click to a closing details menu.
Lead assignment and other child settings routes no longer collide with the parent settings path.
Platform chrome
Back button uses shared returnTo handling and defers to the layout return bar when returnTo is present.
Version 1.8.91
CRM module settings enforcement
CRM business-module policy fields are editable on Application Settings and enforced on staff lead create and lead conversion.
Application Settings
More CRM settings controls territory scoping, lead-source defaults, manual entry and conversion rules on the module configuration page.
Manage territories links preserve returnTo when opened from module setup.
CRM
Staff lead create applies default source, required source, manual-entry block and territory scoping from module configuration.
Lead conversion honours allow-direct and require-opportunity rules before creating an opportunity.
Version 1.8.90
CRM configuration audit follow-up
Setup wizard and linked settings preserve return navigation; keyboard users can open linked settings with Enter; wizard fix actions match module detail resolution targets.
Application Settings
Run setup wizard from a module passes returnTo through the wizard and essentials territory links.
Linked Settings Open responds to Enter as well as primary click.
Wizard Fix uses the same resolution targets as the module configuration page, including Setup Center with returnTo.
Version 1.8.89
Estimate workspace and CRM configuration readiness
New estimates are built in a dedicated workspace with prospect-scoped CRM data, rich terms and templates; CRM module configuration separates required setup from optional enhancements and names every fix action.
Sales
New Estimate opens a tabbed workspace (customer and dates, line items, terms and document) instead of an inline list form.
Contacts and opportunities load for the selected prospect only; issue date and validity default on create and are snapshotted on the estimate.
Line items use grouped catalog pickers with add-below, duplicate and delete; terms use the rich-text editor, content snippets and published document templates.
Application Settings
CRM module configuration scores required Setup Center steps separately from optional service and portal work.
Blocking issues use named actions and Linked Settings carry return links; destinations show Back to CRM settings.
More CRM settings that are not enforced yet are read-only with stored-value summaries.
Version 1.8.88
Personal email verification works
The link in the personal-email verification email now opens a page that confirms the address.
HR
The Verify your personal email link opens a branded page that confirms the address at once, or explains if the link has expired or was already used. Links sent before this update need to be sent again.
Version 1.8.87
Document previews, redesigned command centers and simpler opportunities
Every report and document can be previewed before downloading, sales documents follow the new professional layouts, command centers and maps match the approved designs, and opportunities move forward from one simple stage bar.
Documents and reports
Preview any sales document, report or HR letter in the app before you download it; downloaded PDFs now always open.
Estimates, proformas, sales orders, delivery challans, receipts, tax invoices and credit notes use the new professional layouts, with customer cards, a clear tax split, totals band and signature block.
Report Format Studio previews no longer fail on long documents, and a failed preview explains why.
Command centers and maps
CRM Leads by Territory is a regional heat map on a world map, ready for markets outside India.
Prospect Companies shows company density across India with territory callouts and expansion markets, and is now in the CRM menu.
Command centers across modules follow the approved layouts.
CRM and sales
Opportunities have one clickable stage bar and a Next step card that says what to do now; mark won or lost from any stage.
Duplicate companies show in Master Data Deduplication, and the quick lead phone field is full width.
New leads load states and cities for India straight away, and a new Lead Assignment page explains who receives website leads.
Settings and integrations
Every integration has a step-by-step setup guide, and IndiaMART, TradeIndia, Justdial, Meta, WhatsApp, Google Maps, LinkedIn, Facebook, Instagram, YouTube and AWS show their own logos.
A module setup wizard walks through the business modules one at a time, and each module's default page is honoured.
Organisation settings use a step-by-step form; the Location Database lists every country; the settings tab is now Communications & File Storage.
HR
Employee addresses use a full address box with tidy country, state, city and postal code fields.
Goals & KPIs line up the performance cycle and employee filters and show governed scorecards.
Version 1.8.86
Application Settings workspace and command-center charts
Application Settings is now a guided settings workspace, command centers show real monthly trends and a shared India map, and Purchase and CRM gain new home views.
Application Settings
A guided workspace for business modules, integrations, access, branding, documents, notifications and audit, with progress read from your live configuration.
Administrators can choose, preview and publish one of six application-navigation layouts; nothing changes for users until it is published.
Command centers
CRM, Purchase, SaaS, Site Survey, Training, Knowledge Base, Library, Marketing, Accounts and Fulfilment homes plot real monthly trends; panels without a trusted source say so instead of showing zeros.
CRM, Prospect Intelligence and Site Survey show activity on a shared India region map.
CRM Command Center offers Daily Operations, Pipeline & Territory and Relationship 360 views; Prospect Intelligence is under CRM More → Insights.
Purchase home is a Purchase Command Center; its Quick Actions open the create form directly.
Everyday fixes
Quick Lead, Quick Contact, Quick Prospect Company, Verify Prospect Details and Link Existing Customer open as centred forms.
Tools → Email reads your mailbox settings correctly, letters and report previews stay white in dark mode, and search boxes no longer overlap their icon.
Version 1.8.85
Email fill, remaining shell icons, Purchase Command Center and print paper
Tools → Email and other tool workspaces fill the routed column, remaining shell chrome uses mapped Material icons with wrapping labels, and Pilot also ships the Purchase Command Center and print-paper tokens already on main.
Shell and tools
Tools → Email fills page-content; an unconfigured mailbox uses the existing RBAC settings getters and a 44px control to Profile → Email.
Community, Support Conversations and To-Do stretch with the shell instead of 100vh caps.
Remaining shell chrome uses mapped Material Design tokens on app-platform-icon, and Tools and rail labels wrap instead of truncating.
Command centers and paper
Purchase home is a Sales-pattern Command Center from ordinary documents, without enabling inventory procurement v1.
Quick Actions menus portal onto document.body. Print-paper tokens stay white in both themes while chrome follows the theme.
Verification
Passes 3,118 frontend specifications plus Support 45/45 and shared UI audits, npx ng build platform, and API syntax lint across 4,497 files. Isolated Puppeteer PDF validation passed with the provisioned Chrome.
Version 1.8.84
HR evidence, search-field alignment and menus that close
Pilot HR onboarding and performance collectors now fail closed on missing evidence, search dropdowns line up with the text boxes beside them, and module More menus close when you click away.
HR and performance measurement
Hardens onboarding sign-off so required uploads and live prerequisites cannot be completed from stale flags.
Activates canonical KPI collectors at calculator v2, including pinned deliverable evidence, configured furniture stages, employee-compliance dates, manufacturing manifest timing, purchase SLA holidays and vendor-bill match snapshots.
Leaves onboarding/probation timing planned and seven composite keys blocked pending definition; existing Pilot sources remain classified and score-ineligible.
Forms and navigation
Search dropdowns keep the typed text, placeholder and loading hourglass on one line, and floating labels no longer collide with the search box.
Dropdowns and text boxes in form and list toolbars share the same 44px height and inner spacing; location pickers open above surrounding panels.
The module More and Settings menus, including the CRM workspace, close on a click outside the menu, on Escape and on navigation.
Verification
Passes focused HR 102/102, API platform 11,163/11,165 (one local pdftotext font-extraction check that needs the provisioned extractor), API syntax lint across 4,491 files, 3,092 frontend specifications with the sizing, drawer, tab and view-switcher audits, and ng build platform. Quote Engine is unchanged.
Version 1.8.83
Match approved command-center icon language
Pilot module homes now use the approved contextual icon treatment across KPI cards, section views and analytics panels instead of generic or text-only card chrome.
Visual fidelity
Adds contextual semantic icon wells to the twenty module homes and their command-center section cards while preserving each approved hierarchy and authoritative data source.
Assigns an explicit relevant icon to every shared KPI card, including Inventory, HR governance, performance and branding-preview cards; generic fallback-only cards are rejected by the regression gate.
Passes 3,091 frontend specifications, Support 45/45, sizing, overlay, tab and view-switcher audits, icon coverage and the production Angular build.
Version 1.8.82
Restore complete overview command centers
Pilot module homes now expose their approved operational hierarchy, certified queues and honest unavailable states instead of sparse, fragmented or duplicate navigation views.
Command-center composition
Restores Finance, Purchase, SaaS, Training, Digital Experience, Work, Manufacturing, Assets, Fulfilment, Projects and Application Settings overview composition.
Uses existing certified queues, site health, search, publication, portfolio, capacity, asset, project and manufacturing aggregates while labeling unsupported series explicitly unavailable.
Removes duplicate local module navigation and obsolete role-tier fragmentation so the shared icon-led module tabs remain the single navigation authority.
Verification
Passes 3,089 frontend specifications, Support 45/45, sizing, overlay, tab and view-switcher audits, the production Angular build and 11 focused backend aggregate tests.
Version 1.8.81
Close authenticated UAT fidelity gaps
Pilot navigation, command centers, governed CRM capture and API request handling now match the approved app-wide UAT contract under sustained authenticated use.
Command centers and navigation
Restores the approved Marketing, HR and Sales panel hierarchy while labeling unsupported trends and activity sources explicitly unavailable.
Removes duplicate Library, Site Survey and Training module tabs, preserves workflow tabs, and assigns Project and Site Survey record routes to their correct shell destinations.
Adds permission-aware launcher fallbacks and exact Marketing, Training and Knowledge Base destination gates so scoped users land on a route they can use.
CRM, accessibility and reliability
Uses the scoped governed territory catalogue in full and Quick Contact capture without requiring Territory administration access.
Makes the Calendar follow-up workspace modal to assistive technology, traps keyboard focus while modal and keeps the desktop read-only popover non-modal.
Removes duplicate global rate-limiter counting for versioned API requests, preventing valid data-heavy ERP sessions from reaching the configured limit at half its intended allowance.
Version 1.8.80
Complete app-wide UAT fidelity
The remaining approved module, CRM, territory, location, return-navigation, report and onboarding requirements are reconciled for Pilot validation.
Module and CRM fidelity
Reconciles all twenty approved launcher homes and their shared inner-page contracts with full-width command centers, icon-led tabs, 44 pixel controls and no module side navigation.
Keeps Karam assigned across all seven active India territories, preserves Nepal and Middle East as planned territories, and stabilizes governed territory selection in Prospect Pool.
Adds authoritative City and State columns to the remaining applicable CRM, Party, vendor, warehouse, plant and business-unit tables.
Connected work and evidence
Restores search, filter, pagination, scroll and local view state when users return from connected Party, Contact and onboarding workspaces.
Extends the approved report contract across Estimate, Proforma, Sales Order, Delivery Challan, Receipt, Credit Note and Tax Invoice, including live side-pane branding preview refresh.
Records email-provider submission, acceptance or rejection evidence for onboarding invitations without persisting provider payloads or message bodies.
Version 1.8.79
Complete module overview command centers
Inventory, Knowledge Base, Library and Site Survey now open dedicated, full-width command centers with authoritative module-wide data and the approved analytical composition.
Overview and analytics
Promotes Inventory Intelligence to the Inventory home while preserving its KPI strip, charts, ABC by FSN matrix, priority actions, working-capital analytics and specialist operational dashboards.
Adds dedicated Knowledge Base and Library command centers with repository-wide lifecycle totals, publication workflow, search or adoption evidence, governed queues and explicit unavailable states for unsupported measures.
Adds a business-unit and permission-scoped Site Survey aggregate with real readiness, exception, portfolio, trend and recent-survey panels while keeping the survey register as a separate workspace.
Navigation and controls
Makes each command center the canonical launcher destination and keeps Articles, Seed Pack Repository, Survey Cases and Item Master as separate icon-led tabs.
Keeps Library and Inventory bounded actions in centered modals with 44 pixel controls and no rendered side drawers.
Preserves semantic tokens, full-width routed canvases, keyboard navigation and light/dark responsive behavior from the approved resource designs.
Version 1.8.78
Complete Week calendar item list
Week view now exposes the same complete, actionable calendar-item treatment as Month and Day, grouped by date without capping or hiding records.
Calendar
Groups the visible week into seven named day lists with item counts, time, title, source, amount and status.
Keeps every item connected to the shared event and follow-up dialog, while each day heading opens its detailed Day ledger.
Stacks the seven groups on mobile and keeps the desktop calendar inside the full-width module canvas without document overflow.
Version 1.8.77
Calendar follow-up completion
CRM day-calendar entries now open the approved communication-notes and next-follow-up form for both lead and deal commitments, closing the final live Pilot mismatch found during the app-wide acceptance replay.
CRM calendar
Makes direct Lead and Deal next-action entries expose the same compact follow-up editor as scheduled CRM activities.
Records the completed communication in the activity timeline and replaces the canonical next action with the selected future date, so the calendar advances instead of retaining the old commitment.
Keeps Edit Lead or Open Source as a separate action and preserves the approved Day ledger, full-width module canvas and shared navigation contract.
Version 1.8.76
Complete approved module UI fidelity
The approved app-wide tabbed interface now reaches the operational pages, calendars, shared quick actions, location-aware CRM records and full-width command centers required for Pilot acceptance.
Navigation and workspaces
Removes the obsolete desktop hamburger and keeps module navigation in icon-led horizontal tabs with authorized Settings actions and no module side drawers.
Makes command centers, overview pages, launcher destinations and Application Settings inner pages use the available routed canvas across the approved modules.
Adds the approved CRM Calendar placement and day-detail controls while retaining the compact notes and next-follow-up action with a separate Edit Lead route.
CRM and connected records
Completes Quick Lead and Quick Contact modal patterns, contextual Back navigation, and shared Party Directory entry points across CRM, Sales, Purchase, Accounts, Inventory and SaaS.
Shows City and State as separate Lead list values and repairs all nine territory definitions using governed country, state and city references.
Adds employee-owned Email with private mailbox settings, sanitized message rendering, owner-scoped drafts and outbox delivery records.
Version 1.8.75
Approved command-center visual fidelity
Operational overviews now match the approved resource hierarchy with centered workspaces, prominent semantic KPI icons, denser ledgers and reliable module-tab ownership.
Command centers
Applies the approved large-icon KPI composition and readable desktop canvas to CRM, Sales, Purchase, Finance, Inventory, Marketing, SaaS, Assets, Fulfilment, Support, Training and Digital Experience.
Matches the approved V2 Projects, Work Management and Manufacturing hierarchy with four execution-status cards, dense task ledgers, icon-led gate readiness and blocking-issue panels.
Keeps unsupported metrics explicitly unavailable and preserves existing routes, permissions, actions and real-data boundaries.
Navigation and settings
Prevents a previous module's tab strip from remaining visible after navigation and assigns control-panel pages to Application Settings consistently.
Updates Application Settings launchers with the approved constrained layout, larger semantic icons, compact card density and responsive summary counters.
Adds icon-led, keyboard-sized Inventory Intelligence tabs while retaining the application-wide no-side-navigation rule.
Version 1.8.74
Simpler module workspaces and resilient CRM reads
Module workspaces now use the approved tabbed navigation and consistent controls, while legacy imported CRM references no longer break sales command-center views.
Navigation and workspaces
Keeps the Sales More menu outside the scrolling tab strip so every destination remains visible and keyboard accessible.
Removes standalone Process Flow launchers and record links while retaining useful progress context inside operational records.
Adds the approved command-center ledgers, settings launchers, icons, contextual Back actions and full-page record patterns across the in-scope modules.
CRM and form reliability
Allows CRM overview, forecast, salesperson-performance and follow-up reads to display imported records with legacy owner or account tokens without an invalid-ID failure.
Continues to resolve valid employee and account references normally and leaves create and update validation unchanged.
Applies the shared 44-pixel control contract to list toolbars and primary forms and narrows the phone country selector to the approved compact width.
Version 1.8.73
Restore Support Chat inboxes on Pilot
Support Chat inbox aggregation now uses the MongoDB stage supported by the deployed Pilot server while preserving the same unread and activity projections.
Support operations
Restores both staff and public chat inbox list endpoints, including full-name search, on the Pilot MongoDB version.
Preserves requester scope, latest-message projection, unread totals, recent-activity ordering and the existing bounded inbox window.
Adds an explicit compatibility regression for both inbox pipelines without changing stored conversations.
Version 1.8.72
Private Vault access for founders and proprietors
Founders and sole proprietors can now use the same isolated, email-verified private Vault as eligible directors without being treated as employee-directors for payroll.
Governed access
Adds a legal governance capacity, effective date, approval reference and server-recorded change history to the employee Account & Access record.
Recognizes a governed Founder / Proprietor capacity while continuing to require a verified corporate work email and a completed email-migration review.
Keeps Vault eligibility separate from job titles, payroll classification and application roles; only the dedicated governance authority can change it, and superadmin or a founder-named role alone still grants no private access.
Pilot data protection
Uses the separate Vault database and encryption-key contract already built into the module; each eligible principal receives an independent private Vault.
Makes guarded cross-module UAT cleanup compatible with the Pilot MongoDB version while retaining exact document and concurrent-change protection.
Version 1.8.71
Correct cross-module Pilot stock balances
The Pilot UAT graph now keeps its opening stock in one warehouse and presents the issue-adjusted ledger balance as the current quantity.
Inventory evidence
Prevents the startup opening-stock migrator from duplicating the synthetic five-unit opening balance into the default warehouse.
Preserves the immutable ledger's append order so opening five, receipt twenty and issue ten resolve to fifteen units in the Gurugram Pilot warehouse.
Exercises the real startup seed and stock-balance service after graph insertion to verify one warehouse, fifteen units and the issue as the latest movement.
Version 1.8.70
Memory-safe cross-module Pilot data protection
Pilot UAT seed snapshots now protect the complete database against drift without loading every business record into memory.
Pilot data safety
Keeps complete before images for every collection the guarded cross-module pack can change, including its ownership manifest.
Fingerprints every Pilot collection so unrelated writes, collection additions, missing scope and tampered snapshot content stop the operation before insertion.
Retains verification support for existing version-one snapshots while issuing bounded-memory version-two snapshots for the CRM-to-accounting UAT graph.
Version 1.8.69
Billing-backed performance and managerial notice correction
Revenue KPIs now rely on posted billing evidence, and managerial employment drafts can be corrected through a crash-safe, Pilot-only policy repair.
Performance evidence
Calculates owned won revenue from posted invoice taxable value less posted credit notes instead of editable CRM opportunity value.
Requires accepted Estimate or Quotation lineage through the Sales Order to an employee-owned won Deal, with governed currency, account and business-unit validation.
Classifies retained Pilot invoices and credit notes as pre-go-live, score-ineligible evidence before operational KPI scoring is enabled.
Employment policy correction
Uses the grade-aware notice-period authority for reconstructed offers and employment documents, giving L4 and higher grades a 60-day default while preserving explicit negotiated terms.
Adds a Pilot-only correction for Rajni Sehgal's untouched draft offer, appointment and confirmation snapshots with journalled before images, compare-and-set writes, resumable recovery and safe rollback.
Pins the operator to the exact Pilot database, environment, host directory and stopped Pilot process, and requires a verified backup before any write.
Version 1.8.68
Auditable HR decisions and governed promotion review
Salary-advance and Fleet decisions now require immutable evidence, and Pilot-to-Production HR conflicts can be resolved only through an exact reviewed, rollback-capable merge plan.
Decision evidence
Records salary-advance approval and rejection with the canonical checker, request identity, status transition and decision reason.
Gives Fleet approval and rejection one stable audit receipt so retries and concurrent requests cannot duplicate the evidence.
Restores a salary advance to pending if its required audit cannot be written; Fleet and TA decisions retain hidden repair authority only inside the configured security-audit retention window, honor legal hold, and leave a PII-free tombstone so expired evidence cannot be recreated by retry.
Production promotion controls
Binds each reviewed merge choice to the exact encrypted artifact, Pilot source, Production target, source row, target row and their full-document digests.
Supports explicit Production reuse, safe rekeyed insert and complete field-by-field HR Settings resolution. Generic Pilot-authoritative replacement requires a future domain-aware workflow.
Rejects stale, partial, ambiguous or conflicting reviews. The composed HR Settings singleton must pass its Mongoose schema and is protected with a before image, compare-and-set apply, resumable journal and compare-and-set rollback. No HR data is promoted until the owner supplies the evidence-backed decisions and separately authorizes the Production operation.
Version 1.8.67
Production launch safety and governed KPI actuals
Managed performance actuals now stay evidence-backed, HR promotion previews verify typed dependencies and role authority, and the Production deploy path has stronger isolation and identity checks.
Performance governance
Blocks direct actual edits for every KPI carrying a managed measurement key across both legacy write endpoints.
Keeps operational reconciliation, independent approval and unmanaged legacy KPI history behavior intact.
Records explicit implementation modes for the Propulsive performance measures so unsupported indicators remain visible without fabricated scores.
HR promotion safety
Adds a checksum-backed schema-v2 reference catalogue for Pilot Role and Tenant dependencies and maps them by reviewed immutable identities.
Compares role permissions and governance flags, models HR Settings as a singleton and prevents an ObjectId in the wrong collection from satisfying a dependency.
Keeps Production import blocked while missing roles, authority drift, employee collisions, keyless KPIs and dependency-aware merge decisions remain unresolved.
Adds a dry-run-first Production promotion operator that binds the encrypted artifact, reviewed plan, target database and protected snapshot, with authenticated journals, exact confirmations, crash recovery and rollback.
Release assurance
Preserves exact Quote Engine Phase 2 ancestry and the approved global UI-kit tab behavior without changing Quote Engine calculations or feature flags.
Protects nested Pilot and Staging web roots during Production backup and extract, restores explicit ownership and verifies the exact full commit in health checks.
Uses local gates and the sanctioned deployment script; Production migration, data promotion and deployment remain separately approval-gated.
Points the employee-retention settings hint to the governed `/legal/privacy` publication route while leaving publication and approval with the authorized policy owner.
Version 1.8.66
Guarded Perfex reminder reconciliation
Pilot can now retire only the exact duplicate reminders left by the legacy Perfex manifest while preserving every business record and retaining complete disposition evidence.
Exact data reconciliation
Verifies the completed checksum-matched Perfex batch, all 5,338 source identities, linked targets, Party activations and proforma payment totals; 1,225 lifecycle links resolve to 1,151 canonical histories through 74 exact Lead and Client shared records.
Retires only 347 legacy reminder rows that have exact authoritative semantic replacements and preserves the remaining 3,686 historical activities.
Preserves and verifies 694 import-lineage and KPI-exclusion references, records a disposition for all 12,950 legacy-owned records and marks the old manifest superseded by the authoritative import.
Pilot safety
Defaults to a read-only preview and requires the exact Pilot database and host identity for every operation.
Apply requires the Pilot process to be stopped, a fresh protected BSON snapshot outside the checkout, its SHA-256 checksum and a maintenance coordination reference.
Uses full-document compare-and-delete checks, blocks external references or drift, supports exact rollback and is idempotent after completion.
Simpler tabbed ERP workspaces and governed CRM data
Commercial modules now use the approved icon-led tab shell, CRM follows the prospect-first lifecycle, locations share one governed authority, and customer reports retain their approved print geometry.
Module navigation and forms
Replaces module-level side navigation with the shared horizontal tab row, grouped More menu and permission-filtered Settings action.
Adds consistent icons, semantic controls, contextual Back navigation, City and State columns, and shared Party Directory access across applicable modules.
Keeps primary records as full pages and quick lead/contact capture as centered modal actions.
CRM, territories and imported records
Preserves Contact to Lead to Opportunity to Prospect to Party boundaries, including direct/reference, upsell and cross-sell flows with Party activation only after payment.
Adds a governed Location Database beside Territories for countries, states, cities, aliases, audit history and dependency-safe duplicate merges.
Corrects the guarded Perfex plan to preserve all 96 estimates, 354 proformas, 282 linked payments and GST registrations with exact totals.
Commercial documents
Aligns estimate, proforma, order and delivery layouts with the approved color and monochrome print skeletons, margins, repeated continuation headers and branding controls.
Places proforma transactions below Amount Payable, hides unused discounts, labels applied coupon discounts and omits the rejected status ribbons.
Validation covers the complete frontend and backend gates, governed UI audits, CRM lifecycle UAT, location authority, report fidelity, data integrity and secret scanning.
Version 1.8.64
Launch-safe HR governance and performance boundaries
Onboarding, employee payments and Propulsive KPI evidence now use one governed launch boundary, with permanent Pilot scoring exclusions and an encrypted HR promotion manifest.
Onboarding and employee payments
Onboarding list, detail and completion now share one live readiness result; stale sign-off cannot conceal missing evidence or incomplete mandatory tasks.
Configured login, shift and asset tasks govern new-hire completion, while historical employee-file onboarding identifies operational steps that do not apply.
A guarded setup can create a credential-free INR employee-payments cash authority and canonical TA expense mapping while preserving valid administrator choices.
Performance and promotion safety
All 60 Propulsive KPI assignments have immutable measurement keys; the managed 2026 authority begins on 1 September and pristine pack-owned targets are prorated to four months.
Existing Pilot attendance, CRM and support source identities can be classified permanently outside KPI scoring before migration, and every current automated collector is covered by a regression guard.
The HR promotion exporter preserves BSON identities in an encrypted, checksum-backed allow-list, excludes known UAT data and reports unresolved Production dependencies before any import is considered.
Shared UI contract
Universal module tabs again use the shared keyboard directive while preserving route activation, responsive overflow and the phone More sheet.
Onboarding refreshes its derived readiness after checklist mutations and labels non-applicable steps and tasks explicitly in both list and detail views.
Version 1.8.63
Guarded standalone pay-band repair
Propulsive's approved L1-L7 pay-band corrections can now be applied safely to Pilot's standalone MongoDB with protected recovery evidence.
Pay-band authority
The Pilot repair requires a stopped application, a fresh protected snapshot, exact database identity, checksum and a matching maintenance reference before it can write.
Standalone changes use full-record compare-and-set checks, verify the complete L1-L7 authority and restore owned writes exactly after handled failures without overwriting an unexpected concurrent change.
The repair preserves every existing absolute salary limit while closing the superseded 2025 L1-L4 rows and aligning the approved 2026 monthly midpoints.
Version 1.8.62
Connected Pilot operations with governed evidence
Employee performance, fleet logging, privacy controls, the Pilot order-to-cash rehearsal and Quote Engine Phase 2 now use clearer workspaces and stronger audit evidence.
Employee and fleet workspaces
Profile now shows each employee's governed KRA and KPI plan separately from monthly operational targets, so a missing collector no longer hides the approved performance framework.
Fleet logging now opens in the full page workspace with responsive filters, unclipped dropdowns, field-level validation, fuel-proof requirements and touch-safe actions.
Attendance actions meet mobile touch-target guidance and shared list import controls align with their neighbouring filters and actions.
Audit and Pilot rehearsal
Employee privacy-retention changes record the linked employee as the canonical actor and roll back when the required immutable audit receipt cannot be stored.
A guarded synthetic Pilot pack links one canonical item and unit across CRM quotation, purchasing, warehouse stock, sales order, delivery, invoice, part payments and balanced accounting entries.
The new Pilot pack defaults to preview, refuses Production, requires a protected snapshot and maintenance window for writes, preserves existing records and blocks cleanup after external references or operator changes.
Quote Engine Phase 2
Projects, Quotes and product workspaces now share responsive lists with KPI summaries, City/State and stage filters, scoped views, quote values and phone record cards.
Universal module tabs support the tab keyboard contract and move overflow destinations into a phone More sheet, while headers wrap their actions at laptop widths.
Quote and revision responses hide cost and margin unless the reader has quotes.view_cost; quote summaries use a dedicated route and proforma tax tails print separate CGST and SGST rows.
Version 1.8.61
Completed connected employee lifecycle safeguards
Onboarding audit rows, attendance provenance, movement locks, privacy retention and final-settlement dues now remain reliable across the complete employee lifecycle.
Onboarding and lifecycle integrity
Onboarding retains and identifies archived employee audit rows, renders a truthful unavailable state for broken references, removes stale expanded actions when a relation changes and keeps archived-list reads from rewriting historical tasks.
A connected synthetic UAT journey now verifies offer approval, candidate consent, onboarding completion, Digital ID issue, resignation, clearance, final settlement, experience-letter issue and post-exit access rejection.
Final settlement includes approved unpaid INR travel and expense reimbursements plus outstanding disbursed advances, rejects claims without governed INR authority or TA bills already owned by reimbursement posting, and atomically consumes every frozen source obligation when payment is recorded.
Attendance, movement and privacy controls
Temporary move-out locks every active device until the employee completes the password-protected return flow; break and move-out starts are serialized, and recovery is restricted to the employee's exact open record.
Manual and CSV-imported attendance provenance is server-owned and cannot be forged or rewritten by an API client, while biometric imports retain their integration source and corrected punch evidence.
Privacy retention now covers security audit, AI audit, employee activity, access-event and ended-session evidence while preserving active sessions and records subject to legal hold.
Version 1.8.60
Restored the live onboarding register
The Onboarding page keeps its shared enterprise table mounted during asynchronous loading so returned employee rows render without waiting for content projection to be recreated.
Onboarding list rendering
The shared data table now uses its built-in keep-while-loading mode, so Angular mounts the employee table projection on the first render and dims it during loading.
The table retains its employee, designation, profile-submission, progress and expandable checklist content when the asynchronous request completes.
The regression check prevents a second data-table projection target from consuming the live row content, and HR Report Format Studio now labels and scopes warning, show-cause and achievement-certificate formats.
Version 1.8.59
Enforced employee access and governed HR records
Attendance breaks, inactivity locks, onboarding, Digital IDs, resignation terms and employee documents now enforce their authority at the API boundary and retain reviewable audit evidence.
Session, break and attendance enforcement
An open tea or lunch break locks every active device at the API boundary; only session inspection, logout, reauthentication, today's attendance and the guarded break-end recovery path remain available.
Ending a break requires a recent password step-up, inactivity uses persisted per-session human-action evidence across tab closure and reopening, and access-policy changes roll back when their required audit record cannot be written.
Staff Attendance expanded rows now show every recorded break punch with its start, end, planned duration and actual duration, while Employee Operations exposes the readable access-event register.
Employee lifecycle integrity
Onboarding cannot accept a missing required upload, approve an incomplete required-document checklist or complete until every required file is present and accepted.
Digital ID issue, reissue, display and QR verification fail closed for departed, deleted or unresolved employment states, even if an earlier revocation side effect was missed.
Resignation freezes the negotiated or grade-based notice-period authority already used by Employment Terms, preserving an explicit zero-day agreement and the managerial default.
Governed documents and performance evidence
Warning, show-cause and achievement-certificate issue now pins the published report definition, version, checksum, immutable compiled HTML and content hash; preview and Chromium PDF replay the same verified output.
Operational performance collection detects Pilot UAT markers in Attendance, CRM, activities and Support, and rejects synthetic facts before they can create an eligible KPI-actual proposal.
Persisted published Estimate and Proforma formats are regression-tested end to end: zero item-discount money hides the Discount column and Itemised Discount row, while positive special-discount money shows only its own summary row.
Version 1.8.58
Governed HR operations and operational KPI actuals
Offer letters, payroll payments, TA reimbursements, RACI, session controls, attendance and operational KPI actuals now share stronger authority, audit and retry guarantees.
Employment and payment authority
Offer preview, candidate preview and PDF now replay one approved Chromium report snapshot with controlled numbering, verified personal email, compensation breakup and employment-policy terms.
Payroll generation, review, approval, accrual posting, salary payout and advance funding use canonical Employee identities while retaining the authenticated login as separate provenance.
Salary payouts and TA reimbursements are idempotent, use governed account mappings and fail closed when legacy authority or required accounting dimensions do not reconcile; salary payout requires dedicated disbursement authority.
Employee operations governance
RACI activation permits one active version, records required audit evidence and displays each employee's active assignments in Profile and Employee 360.
Configurable device limits serialize simultaneous logins and support replace-oldest or block-new behavior, including employee-specific field-work exceptions.
Fleet decisions resume safely after interrupted writes, while strict attendance prevents overlapping breaks and excludes personal movement from working time.
Operational performance and Estimate accuracy
A maker/checker workspace proposes KPI actuals from attendance, CRM, service and support records, revalidates the aggregate source before approval and refreshes Home cards; attendance follows the payroll workday calendar and historical lead qualification respects the stated as-of cutoff.
Synthetic evidence remains visibly score-ineligible and cannot update KPI actuals, appraisals or incentives.
Estimate item and special discounts stay hidden unless positive persisted money exists; stale percentages and coupon codes are cleared when zero-discount records reopen.
Version 1.8.57
Focused CRM primary navigation
CRM now matches the approved compact hierarchy with six direct daily-work tabs and grouped access to every other destination.
Approved primary tabs
The sole primary row now contains Overview, Prospect Pool, Qualification, Assignments, Reports and Party Directory in that order.
Selected pages retain the shared icon, semantic color and underline treatment without a second navigation row or module sidebar.
The row stays horizontally scrollable on smaller screens while More and administrator Settings remain anchored at the right.
Complete route access
All remaining sales, activity, communication, insight, automation, data-quality, service and administration pages are grouped under More.
CRM Settings remains visible only to module administrators and each settings destination keeps its own narrower permission check.
No CRM route, follow-up workflow, contact, lead, opportunity, report or party function was removed.
Version 1.8.56
CRM tabbed workspace navigation
CRM now uses a single icon-led tab workspace across every route, with module administration kept in a permission-gated Settings area at the upper right.
One consistent CRM workspace
Overview, sales work, activities, communications, insights, service, data quality and administration are available through the same two-level tab navigation.
CRM routes no longer render the module side navigation or duplicate page-level CRM tab strips.
The active work area and page stay visibly selected while nested routes retain their existing permissions and route contracts.
Responsive and governed access
CRM Settings appears at the upper right only for users with CRM settings permission, while each settings destination keeps its narrower resource permission.
Tabs retain labels and relevant icons, meet the 44-pixel target rule, scroll safely on smaller screens and use shared light and dark theme tokens.
Mobile CRM navigation uses the app switcher and tab workspace instead of reopening a module side menu.
Version 1.8.55
CRM lifecycle and territory workspace
CRM now supports clean contact-to-customer progression, territory-scoped work, historical prospect qualification, compact capture, and the imported Perfex pilot dataset.
Simpler CRM workspace
Overview, Pipeline, Follow-ups, Leads, Contacts, Prospect Pool, Party Directory, Reports, Calendar and Territories use the shared icon-led tab navigation in desktop, mobile, light and dark themes.
Quick Lead and Quick Contact open as compact centered modals, while full create and edit forms stay in the page workspace.
Lead and contact names are normalized to readable title case, and the shared phone control keeps its country prefix compact.
Governed customer lifecycle
Contacts qualify into Leads, Leads convert into Opportunities, quoted Opportunities become Prospects, and a Party Account activates only after a recorded payment.
Direct-reference, upsell and cross-sell opportunities retain their sales motion without requiring a new lead.
Prospect organizations preserve multiple people, phone numbers, emails, websites and showroom, warehouse or factory locations with duplicate-review evidence.
Territory ownership and continuity
Nine domestic and planned international territories support city coverage and one-to-many telesales assignment.
Employee exit transfer moves owned Leads, Opportunities, Contacts and Party Accounts through an auditable handoff.
Existing-business onboarding
The guarded Perfex importer preserves customer GST registrations, contacts, Leads, items, Estimates, Proforma Invoices, payments and follow-ups with source lineage and replay safety.
Historical company data can enter the Prospect Pool without polluting active Leads or Party Accounts.
Party 360 can start or resend counterparty onboarding for both new and existing accounts.
Version 1.8.54
Auditable salary advance recovery
Salary advances now post from an approved funding account, recover only from available pay, carry unpaid balances forward, and remain traceable through payroll and employee self-service.
Funded and controlled disbursement
Advance disbursement requires a purpose-scoped active INR bank or cash account and creates an idempotent Employee Advances journal before the request becomes disbursed.
The approver cannot record the disbursement, and platform-owned advance and payroll journals cannot be reversed through the generic accounting action.
Legacy advances without posted funding evidence remain visible but cannot enter payroll until accounting reconciliation is complete.
Safe payroll recovery
Payroll allocates the oldest due advance balances only up to available net pay; zero-pay months recover nothing and unpaid balances remain due for a later month.
Each payslip freezes its exact advance, schedule entry, recovered amount and disbursement reference, while the calculation manifest detects later disbursement or schedule changes.
Approval claims are concurrency-safe, interrupted locks reuse the verified posted journal, and retry refuses payroll values that no longer match its posting snapshot.
Payroll visibility
Payroll administrators see salary-advance recovery in run totals, expanded payslip detail, reports and compensation-protected CSV exports.
Employees can expand their own salary slips to review earnings, deductions, net pay and the advance recovery references included in that month.
The advance register shows scheduled, partial and completed instalments with recovered and remaining amounts plus payroll history.
Accounting journal boundary
Manual journal endpoints accept only user-owned accounting fields and reject attempts to supply platform posting identity, control-account authority or internal idempotency values.
Quick post saves one draft and then invokes the separately permissioned posting action with the returned journal identifier.
If posting fails after the draft is saved, the journal remains visible for a safe retry instead of creating a duplicate entry.
Version 1.8.53
Clearer sales and purchase reports
Commercial terms, addresses and payment details are easier to read across sales and purchase documents.
Report formatting
Commercial terms and notes use full-width rows to reduce unnecessary pages.
Customer, Bill To, Ship To, delivery and similar details use aligned rows with hidden table borders.
Proforma invoices have a wider receiving-bank section, payment status below the signature and a payment QR code when valid UPI details are configured.
Continuation pages retain their top margin.
Version 1.8.52
Explicit Estimate discount authoring
Estimate authors now add itemised and special discounts explicitly, while zero-discount records keep those controls and report fields hidden.
Estimate discount controls
New Estimates start without an item-discount column or special-discount fields; each area appears only after its named Add action.
Removing an item or special discount clears the related percentages, amounts and coupon code so hidden values cannot alter the saved total.
Editing a discounted Estimate automatically restores the relevant controls from positive persisted discount values.
Governed PDF configuration
The Estimates toolbar now opens the Report Format Studio used by the live Estimate and Proforma PDF renderer.
The former legacy customizer and block-editor links no longer imply control over generated Estimate PDFs.
Version 1.8.51
Employee salary advances and live access controls
Employees can open a focused salary-advance workspace from their profile, while HR device and inactivity policies now reach already-open sessions safely.
Employee salary advances
The Employee Profile salary-advance card now opens a focused self-service request and tracking workspace.
Employees see only their own advance history, with validated amount, reason, instalment and recovery-period fields.
HR retains the permission-controlled full register, approval and disbursement workflow, and unsupported register scopes are rejected.
Live session governance
Changes to an employee's inactivity and lock policy reach an already-open ERP session within the policy refresh window.
Policy and attendance refreshes do not overlap on slow networks, and a temporary network failure cannot silently clear a known lock.
Signing out resets the local inactivity clock before another employee uses the same browser.
Version 1.8.50
Accurate sales-estimate discounts after navigation
The Sales estimate detail now reloads the selected record on every route change, so itemised and special discounts from a prior estimate cannot remain visible on a zero-discount estimate.
Estimate discount integrity
Changing directly between Sales estimate records clears the previous record while the new estimate loads.
Discount, Itemised Discount and Special Discount visibility is recalculated only from the newly selected estimate.
A slower response from a previously selected Sales estimate cannot overwrite the current record or restore its discount fields.
Version 1.8.49
Reliable estimate-to-estimate navigation
Estimate details now reload the selected record whenever its route changes, preventing commercial columns and totals from a prior estimate from remaining on screen.
Estimate detail integrity
Changing directly between estimate records reloads the new estimate instead of retaining the prior record under the new URL.
Itemised Discount and Special Discount visibility is recalculated from the selected estimate after every route change.
Slower responses from a previously selected estimate cannot overwrite the current estimate detail screen.
Version 1.8.48
Accurate commercial-report discounts and payment history
Estimate and Proforma outputs hide unapplied discounts, render authored terms cleanly, and present part payments as a complete final audit table.
Sales document integrity
Estimate, Proforma, Tax Invoice and Sales Order discount columns follow positive persisted item-discount amounts, so zero discounts and stale percentage-only values remain hidden.
Special Discount rows remain conditional on a positive finite persisted amount, including coupon-only, cleared-discount and invalid imported records.
Customer-authored terms, notes, instructions and proposal conditions render as sanitized rich text instead of visible HTML tags.
Legacy HTML in plain addresses and item descriptions becomes readable text across sales reports.
A partial or split Proforma payment renders a final Payment History table with receipt/reference, mode, date, amount, cumulative paid and balance.
Version 1.8.47
Reliable HR travel-proof links
Pilot TA receipts now resolve against one valid public origin even when the configured browser allowlist contains several comma-separated URLs.
HR reimbursement evidence
New TA evidence uploads use the first configured client origin instead of treating the complete CORS allowlist as a hostname.
Reapplying the reversible HR UAT pack repairs only manifest-owned TA proof links from their governed upload records, preserving bills, approvals and files.
Version 1.8.46
Responsive employment-document register
Employment Documents keeps its heading and guidance readable at phone widths while actions wrap into their own row.
Mobile HR
The Back and New Document actions no longer compress the page title and description into a narrow column on mobile screens.
The document table remains contained in its horizontal scroll region without creating page-level overflow.
Version 1.8.45
Truthful legacy confirmation reconstruction
Historical probation metadata can prepare a confirmation draft while a missing canonical Employment History event remains visibly blocked for independent resolution.
Employment record integrity
Rajni Sehgal's existing probation metadata now prepares a pending-review confirmation draft without treating the legacy self-recorded action as independent approval.
The pilot pack reports confirmation-authority gaps separately from employees whose probation decision is entirely missing.
A blocked confirmation draft cannot be submitted until HR records the authoritative Employment History decision through a valid independent process.
Version 1.8.44
Governed employment documents and employee-file history
HR can reconstruct, approve, issue and acknowledge appointment letters, probation confirmations and professional-service agreements with controlled numbers and immutable issued records.
Employment document governance
Added a maker/checker register for appointment letters, probation confirmation letters and fixed-monthly professional-service agreements.
Historical reconstructions require verified evidence and source references; confirmation letters also require an authoritative confirmation event in employment history.
Approval freezes the employee, role and salary snapshot. Issuance uses a published report format, assigns a controlled document number and stores the rendered PDF for audit.
Employee 360 shows controlled employment documents separately from supporting attachments and opens issued PDFs through authenticated access.
Pilot preparation
Added published enterprise formats for appointment, probation-confirmation and professional-service documents, including compensation breakup, increment policy and information-security duties.
Added a reversible pilot pack that prepares seven appointment drafts, Rajni Sehgal's evidence-backed confirmation draft and two professional-service agreement drafts without approving, issuing, emailing or inferring consent.
Version 1.8.43
Reports without ribbons and corrected branding previews
All report ribbons are removed. Status appears as plain document metadata, and branding previews open at the top with accurate page sizing.
Report branding
Removed ribbons from all generated reports and previews, including older published formats. Headers use their full available width.
One-page previews no longer allocate a second blank page when the report includes a footer.
Changing the report or branding resets the preview pane to the document header.
Commercial samples reconcile item discounts, special discount, GST, amount in words and recorded sample transactions.
Version 1.8.42
Approved commercial reports and usable branding previews
Commercial documents follow the approved report skeletons with printable corner ribbons, consistent branding, safe continuation pages, and a responsive preview. Party Directory and Customer 360 now expose onboarding email actions.
Commercial reports
Estimate, Proforma Invoice, Sales Order, Delivery Challan, Receipt, Credit Note and Tax Invoice follow their approved document-specific layouts in colour and monochrome.
Corner status ribbons remain clear of the company and title. Measured pagination preserves margins, repeats table headings and keeps footer space on every page.
Proforma transactions use gray headings below Amount Payable and before terms. Item and special discounts preserve persisted-money and coupon-provenance rules.
Estimate downloads now use the selected governed report definition instead of a separate legacy layout.
Branding and Party 360
Theme branding previews the published report with unsaved header, footer, font and watermark choices, fitted to the side pane width.
Report Format editor controls stay within their panels at narrow widths.
Party Directory and Customer 360 offer onboarding for new and existing parties, with prefilled recipients, confirmation and keyboard-accessible dialogs.
Integrated HR release
Retains the governed disciplinary and recognition workflows, KPI proposal evidence, canonical actor permissions and discount integrity corrections delivered in 1.8.41.
Version 1.8.41
Governed employee records and commercial discount integrity
HR can issue controlled disciplinary and recognition documents, employees can see proposal-only KPI evidence on Home, and customer reports show discount columns only when positive persisted discount money exists.
Employee discipline and recognition
Warning and show-cause cases now follow evidence, maker-checker approval, controlled document numbering, immutable issue snapshots, acknowledgement, response, closure and audit controls.
Issued warning and show-cause letters use the governed report engine and preserve the employee identity approved at issue time.
Top Employee, Star Performer and custom achievement certificates support evidence, citations, approval, controlled numbering, immutable issued content, acknowledgement, revocation and Employee 360 visibility.
Performance and employee-file evidence
Home KRA and KPI cards surface the newest current-cycle synthetic pilot proposal evidence without presenting it as an approved score, appraisal result or incentive input.
The pilot employee-file baseline links current internal staff to structured designations while retaining the approved job descriptions, grades and employment history.
The July and August pilot evidence pack supplies 120 immutable, visibly synthetic and permanently score-ineligible KPI measurements for end-to-end review.
Estimate, proforma and invoice discounts
Accepted-estimate Proforma Invoices decide item discount-column visibility from positive persisted discount money, matching the Itemised Discount total.
Sales Invoices use the same persisted-money rule, so stale imported percentages cannot expose empty discount columns and real stored discounts cannot be hidden.
Special Discount remains hidden for zero, blank, invalid, negative or coupon-only values and appears with the normalized coupon label only for positive finite persisted money.
Version 1.8.40
Full-width commercial report preview
Branding now renders the selected commercial report skeleton in the dedicated right preview pane, at a usable scale and with the same header, discount, transaction, payment and footer structure as generated PDFs.
Report preview fidelity
Opening Report Branding replaces the generic application canvas with a full commercial document preview in the right pane instead of squeezing it into the narrow settings accordion.
The preview includes the governed Proforma header, Bill To and Ship To blocks, conditional item and coupon discounts, Amount Payable, transactions, commercial terms, payment status, receiving bank, signatory and footer.
Color and monochrome selection, the active header preset, universal font, logo controls, watermark and footer values update the same full document preview.
Version 1.8.39
Governed HR and KPI pilot foundations
New-hire probation, confidential offer delivery, structured employee designations and performance evidence now share enforceable source and approval controls without inventing production scores.
Employee-file and onboarding integrity
Normal boots no longer recreate retired demo HR catalogs when SEED_DEMO is disabled, and a guarded employee-file pack links the eight current staff records to structured designations.
Confidential offers require a verified personal address with verification time evidence, while direct employee creation, job postings and ATS conversion default new joinees to six months probation unless HR records a negotiated value.
CL request and accrual eligibility now resolve the same explicit or joining-date-derived probation window.
Performance evidence and scoring
CRM employee achievements use the current employee identity plus legitimate legacy ownership, and support evidence merges canonical CRM and legacy ticket queues once.
Lower-is-better quantitative KPIs score in the declared direction with deterministic zero handling.
Immutable measurement snapshots preserve source facts, digests, periods and maker-checker decisions; the guarded July/August UAT pack creates 120 synthetic readings that are permanently excluded from appraisal and incentive scoring.
Version 1.8.38
Preview-faithful commercial reports and print controls
Commercial PDFs now follow the approved estimate, proforma, sales-order and delivery-challan structures, with governed branding, color or monochrome output, conditional discount evidence and safe multipage pagination.
Report fidelity and payment evidence
The Professional GST Proforma keeps transactions directly below Amount Payable and before Commercial Terms and Notes, then closes with receiving-bank, payment-status and signatory details.
Item discount percentages appear only on discounted lines; special discounts remain hidden unless applied and show the stored coupon code when present.
Paid, unpaid, partially paid and cancelled states render as header ribbons, with print-safe color and monochrome palettes.
Universal branding and printing
Installation Branding controls the shared report font, header, footer, watermark, confidential marking and color mode, with a live side-pane preview.
All 16 governed report formats receive the selected branding without replacing their document-specific body structures.
A4 page boxes preserve margins and footer clearance; long sales orders and delivery challans repeat table headings and retain every line across page breaks.
Version 1.8.37
HR identity controls and estimate discount integrity
Estimate discounts now appear only when backed by positive persisted money, while HR identity, Digital ID, RACI, multi-establishment policy and employee-lifecycle controls are hardened for the pilot rollout.
Estimate and customer reports
Estimate detail and Executive Estimate output hide item discount evidence for zero, string-zero or stale percentage values, and keep totals aligned when the column is absent.
Itemised and Special Discount totals require positive persisted amounts; coupon evidence remains visible when a real special discount exists.
Commercial terms, notes and banking instructions retain safe formatting, universal branding preserves document-specific controls, and part-payment history closes the Professional GST Proforma.
HR identity and responsibility
PAN and Aadhaar capture is normalized and validated across employee, onboarding, API and model boundaries, including Aadhaar Verhoeff checksum validation.
Digital ID uses short-lived screen QR verification without printable cards or durable badge tokens, and employee profiles show their active RACI assignments within existing access boundaries.
Policy and lifecycle integrity
India State and Union Territory policy coverage resolves through the employee effective establishment and branch without treating unverified policy data as law.
Employee and Employment History writes remain transactional on replica sets and use compensating restoration on standalone pilot or local MongoDB installations.
The independently owned Quote Engine tree is unchanged from the deployed CRM and Sales base.
Version 1.8.36
Balanced proforma margins and payment placement
The Professional GST Proforma now uses even A4 page margins and keeps the receiving-bank, payment-status and signatory details as the final report block after commercial terms and notes.
Proforma page layout
All four Proforma Invoice page margins are set to 10 mm for consistent print alignment and footer clearance.
Commercial Terms and Notes appear before the payment section.
Receiving Bank, Payment Status and Authorised Signatory form the final report block immediately above the shared footer.
The approved fixture remains a single A4 page and its discount, coupon, GST and amount-in-words evidence remains unchanged.
Version 1.8.35
Compact proforma header and discounts
The proforma uses a more compact header with source evidence in the document body, and estimate/proforma detail tables show item discount percentages only when at least one line has an applied discount.
Commercial document clarity
The Proforma Invoice header keeps the shared commercial typography while moving source quotation and acceptance evidence into a compact body strip.
Estimate and proforma line-item tables hide the Discount column when every line has zero itemised discount.
When an itemised discount exists, the percentage column and itemised-discount total remain visible for reconciliation.
Special discounts use the coupon-aware label Special Discount (Coupon Applied : CODE) when coupon evidence is stored.
Version 1.8.34
CRM follow-ups, quick capture and governed reports
Leads can be captured quickly in a centered modal, calendar follow-ups can be completed and rescheduled in place, parties are searchable across connected modules, and commercial reports now follow the approved structures with installation-wide branding and conditional discount evidence.
Lead capture and follow-up
Quick Lead opens as a compact centered modal with name, phone, email, company, next action and follow-up date, while the complete lead record remains available through the full workspace.
Calendar activities and issued commercial documents now open a focused notes and next-follow-up editor, and person names are normalized consistently when leads are captured or edited.
The shared phone input uses a compact country-code control while keeping the readable country list, keyboard access and touch-safe sizing.
Connected records and navigation
CRM, Purchase and SaaS Commercial now expose a shared Party Directory for customers, suspended subscription accounts, contacts, partners, architects, B2B accounts, vendors and service vendors.
Page and form navigation uses the shared icon-led tab pattern throughout the application with roving keyboard focus, selected-state semantics, mobile overflow cues and no side-drawer form presentation.
Reports and branding
Executive Estimate, Professional GST Proforma, Compact Sales Order and Professional GST Invoice follow the approved report structures while retaining the universal installation font and text settings.
Installation Branding now controls report font, footer and legal text, standard watermarks and automatic confidential markings through versioned settings.
Item discount percentages and Special Discount rows appear only when applied; coupon provenance is retained and printed as Special Discount (Coupon Applied : CODE).
Version 1.8.33
Consistent forms, dialogs and icon-led navigation
Large CRM forms now show a clear selected section boundary, controls follow one size and focus contract, record actions open in centered dialogs or full workspaces, and tab and view choices carry relevant icons with accessible selected states.
Form clarity
Lead, Opportunity and Employee forms now give every collapsible section its own boundary, with the current section marked by the semantic primary outline and subtle elevation.
Lead dropdowns, phone fields and shared quick-create controls now match the common 40-pixel desktop control height and retain 44-pixel touch targets where required.
Navigation and overlays
Remaining tab, view, viewport, editor and density choices now use registered shared icons, visible selected states, keyboard focus and accessible pressed semantics.
Shared record overlays default to centered modal presentation, while primary create and edit work continues to replace the route workspace.
Prevention
App-wide audits now reject missing tab or view icons, undersized view controls, unregistered mapped icons, side-drawer presentation, mismatched form-control heights and missing collapsible-section boundaries.
The guarded pilot import now preserves lead and follow-up ownership for staff who have one verified active employee match by email, phone or exact name, while leaving unresolved identities unassigned for review.
Corrected
Deduplicated identical work and personal employee email fields so one active employee is never reported as an ambiguous pair.
Added ordered exact matching by email, normalized phone and unique active employee name, with inactive, deleted and genuinely ambiguous identities excluded.
Controlled import
Recorded the match rule in aggregate-only preview output and retained employee-linked active platform users where available.
Added a disposable-database regression test covering duplicate email fields, phone and name fallbacks, linked users, duplicate names and inactive employees.
Version 1.8.31
Universal icon-led workspace tabs
Tab navigation now follows one shared Analytics-style pattern throughout the app, with relevant icons, clearer selected state, keyboard movement and mobile overflow guidance.
Improved
Standardized 58 page and form navigation groups with 112 contextual icons while preserving each screen's labels, counts, permissions and actions.
Added consistent light and dark styling, 44-pixel touch targets, horizontal mobile scrolling and a visible continuation fade for longer tab sets.
Accessibility
Added shared Arrow Left, Arrow Right, Home and End navigation with roving focus for tab groups.
Added an app-wide audit that rejects new bespoke or iconless navigation tabs while retaining reviewed exemptions for compact editor controls and image thumbnails.
Version 1.8.30
Pilot fleet approval evidence
The registered Propulsive vehicle now has a guarded, reversible pilot data pack for Parvesh-to-Rajni trip, fuel and maintenance approval testing, including genuine synthetic refill-slip files without changing the vehicle master or odometer.
Added
Added four clearly marked historical fleet UAT rows covering an approved trip, approved fuel, pending fuel and rejected maintenance decision.
Added two genuine synthetic PNG refill slips owned by Parvesh Gera and linked through the upload ledger to the corresponding fuel logs.
Governance
Every log routes from Parvesh Gera to reporting manager Rajni Sehgal, while preview, exact database matching, backup acknowledgement and manifest-backed cleanup protect the pilot.
Cleanup refuses to erase a row after a live approval decision or edit, and the pack never creates or edits the registered vehicle, driver assignment, odometer or maintenance authority.
Fresh Propulsive deployments now create the Haryana salary-policy establishment after verified organization facts are available, allowing the State/UT policy interface to open without inventing registrations, contribution coverage or Aadhaar data.
Added
Added an insert-only Propulsive salary-establishment bootstrap keyed to the active tenant and verified proprietorship PAN/Haryana address.
Seeded no statutory registration, TAN, Aadhaar, EPF or ESI coverage; all applicability overrides remain AUTO for later evidence-based resolution.
Improved
Made masked Aadhaar optional in salary-establishment setup and retained strict format validation when HR has a documented reason to record it.
Preserved existing and soft-deleted establishment authority records without automatic edit or restoration.
Version 1.8.28
India-wide establishment-aware HR policy controls
Organization setup now records legal constitution and planned legal-employer transitions, while governed payroll policy packs can target every Indian State and Union Territory, legal-entity type and establishment context without treating unverified rules as certified. Offer negotiation also supports managerial notice defaults and complete probation-assessment terms.
Added
Added legal constitution, constitution effective date and evidence-aware planned legal-employer transition fields to Organization Settings, preserving the current employer identity until a successor entity and actual transfer are verified.
Extended payroll policy-pack selectors with legal-entity types and retained the complete 36-jurisdiction India catalogue for effective-dated State and Union Territory policy configuration.
Added a white-label compliance-engine design covering tenant, legal employer, establishment, workplace and employment assignment boundaries, plus a Haryana manufacturing compliance rollout and an exceptional employee service-agreement plan.
Improved
Managerial L4-and-above offers now default to a 60-day notice period, with a reasoned pre-joining negotiation flow that creates a superseding offer version, resets approval and document control, and invalidates the earlier consent link.
Offer terms now state the probation assessment factors for performance, learning, conduct, problem solving, communication and interpersonal capability, including reasoned extension, confirmation and lawful separation procedure.
Policy applicability continues to fail closed when a jurisdiction source, establishment fact or certification is incomplete, preventing invented State rules from reaching payroll calculations.
Version 1.8.27
Universal report branding and IT employment safeguards
Application Settings now controls eight approved report-header layouts across compatible reports, with Banner layout C selected by default for Propulsive. Offer terms include a governed information-security and data-breach schedule, and employee attendance history uses a compact month view with monthly insights.
Added
Added configurable A–H report-header presets, including four true three-column formats, logo fit and alignment, identity/control visibility, page numbering and repeat-header controls.
Applied the shared header policy to browser Offer Letters and compatible enterprise report formats, with one atomic branding version and Banner preset C as the Propulsive default.
Added versioned IT and data-protection terms covering confidential information, credentials, source code, personal data, incident and breach escalation, evidence preservation, devices, monitoring and disciplinary procedure.
Reduced the employee attendance calendar to compact fixed-height rows and added a monthly insights panel for present days, late arrivals, recorded leave and absences.
Version 1.8.26
Controlled offer letters show complete employment terms
HR can review a branded A4 offer with governed company identity, personal-email status, salary components, notice and increment policy before applying the approved format to other employee documents.
New
Offer approvals allocate a controlled PT/HR/OFFER document number from the shared atomic number-series engine before candidate delivery.
Employee 360 shows each employee's active RACI assignments with role badges, effective dates and a link to the complete responsibility matrix.
Improved
The A4 offer preview uses the configured light-surface logo, governed organization and business-unit identity, complete Gurugram address, GSTIN, PAN and website, while omitting unconfigured phone and email values.
Offer terms now freeze the approved salary revision breakup, probation and notice periods, attendance and leave policy, and the recorded annual-increment policy without promising an automatic raise.
Historical offer corrections are pilot-only, manifest-backed, reversible and preserve any draft that HR has edited or progressed through approval or candidate consent.
Corrected
Offer creation and delivery use the verified personal email; corporate login addresses remain a post-onboarding provisioning step.
CRM pilot snapshots can be written to the protected external backup directory while paths inside the deployed API checkout remain rejected.
Version 1.8.25
CRM and sales UAT controls are ready for the pilot
A guarded pilot pack can validate a complete CRM-to-cash flow with linked commercial and finance records while protecting background jobs and enforcing published enterprise receipt formats.
New
A manifest-backed UAT pack supplies 89 deterministic CRM, sales, billing, accounting and finance records with exact dependencies, scoped cleanup and HR-preservation checks.
Pilot isolation mode pauses all background jobs during the coordinated UAT window and reports that state through health and reminder endpoints.
Improved
Open leads require a next action and due date, surface inline validation, follow the configured status catalogue and retain usable keyboard focus.
Rupee inputs use Indian lakh and crore grouping, one accessible currency symbol and correct programmatic value and disabled-state handling.
Corrected
Payment receipts require a published canonical Report Format Engine definition and return an actionable service-unavailable response when no approved format exists.
Lead exports and ownership errors use explicit employee-account wording when an owner record is unavailable.
Version 1.8.24
Proprietor lifecycle and performance roll-up safeguards
HR can seed truthful employee lifecycle records without treating proprietor drawings as salary, while performance setup repairs only provably stale baseline roll-ups.
Corrected
Bhushan Gera remains in platform onboarding and Digital ID coverage, while salary-based employee offers, appointment letters and probation confirmation are recorded as not applicable to the sole proprietor.
ACTIVE salary authority remains mandatory for every employee contract record from EMP-00002 through EMP-00008.
Organization performance targets created before later baseline employee targets can be repaired when their original value and all supporting rows are reconstructable and unchanged.
Any credible administrator edit to an organization or employee target continues to block automated replacement.
Version 1.8.23
Employee lifecycle and performance setup are ready for governed pilot use
HR can rehearse employee entry-to-exit workflows, manage role-specific KRA and KPI plans, and use consistently sized, validated forms without exposing internal server failures.
New
A pilot-only employee lifecycle pack creates reviewable historical offer drafts and onboarding checklists for the eight existing employees without inventing acceptance, email, KYC or bank evidence.
A clearly labelled synthetic employee exercises onboarding, confirmation history, resignation, final settlement, experience-letter draft and Digital ID revocation with exact cleanup support.
Role-specific 2026 performance plans provide one goal, three KRAs and six balanced KPIs for each current Propulsive employee, with monthly, quarterly and annual operational targets where the source systems can measure them.
Improved
Table page-size selectors and form controls now share the UI kit height and spacing across platform modules, preventing overlap at desktop and mobile widths.
TA bills use a full-page workflow with associated labels, inline validation and touch-sized actions.
Performance seed replay preserves recorded actuals, administrator changes, achievement snapshots and governed incentive evidence.
Corrected
Unexpected server failures now return a safe actionable message to UI toasts while intentional validation and conflict messages remain visible.
Performance API validation now uses the model's complete metric catalogue, including collected revenue and realized margin.
Entity Code Settings now identifies TA bill numbering as an active automatic sequence.
Lifecycle document drafts identify their evidence provenance and require the published enterprise report format before issue; the legacy PDF engine is not used.
Version 1.8.22
Pilot HR workflows have a reversible two-month test baseline
HR can populate July and August pilot attendance and exercise leave, travel, advance and movement workflows with clearly marked synthetic evidence and a governed cleanup path.
New
A pilot-only UAT pack creates July and August attendance for all eight internal employees while preserving approved-timesheet, punch and fixed-monthly-service policies.
Attendance examples cover self, admin and biometric sources, GPS evidence, tea and lunch breaks, late decisions, shortfall, half-day, absence, leave, holiday, weekly-off work, missing checkout and regularization.
The same pack creates approved and pending CL/CO requests, every TA and salary-advance workflow state, expense claims, early-departure requests and temporary move-out outcomes.
Vijay Gera and CA Sandeep Yadav receive September service-visit evidence only because their fixed monthly engagements start on 1 September; attendance never prorates their fees.
Preview blocks non-UAT attendance collisions, apply and cleanup require a verified-backup acknowledgement, and a manifest reverses leave impacts and uploaded proof files.
Version 1.8.21
RACI ownership is visible as a matrix and on employee profiles
Employees can review their approved role duties and active process ownership, while HR sees a conventional process-by-person RACI matrix.
Improved
Employee Operations now presents active processes as rows and participating employees as columns, with clear Responsible, Accountable, Consulted and Informed cells and an accessible legend.
The RACI matrix supports keyboard and horizontal review at narrow widths while keeping process names visible in a sticky first column.
Each employee Profile now displays the responsibility list from the assigned approved Job Description and the employee's own active RACI process assignments.
The self-service Profile API returns only the signed-in employee's RACI roles and never exposes other process participants or grants permissions.
RACI creation now opens as a focused workspace and uses the shared searchable employee selector instead of native dropdown controls.
Version 1.8.20
Propulsive leave policy uses CL and Comp-off only
Paid Leave and Earned Leave have been retired from Propulsive's operating policy, and prior pilot availability is reversed through auditable ledger entries.
Corrected
A fresh Propulsive environment seeds only Casual Leave and Comp-off; PL and EL are never created as active policy types.
Existing PL and EL catalog rows are retained for audit but deactivated with zero accrual and no encashment, so an API restart cannot bring them back.
The guarded reconciliation refuses to erase any PL/EL record tied to a leave request and reports such cases for HR reclassification.
Remaining pilot PL availability is reversed with linked ledger adjustments instead of editing or deleting historical ledger entries.
The standard appointment template no longer promises Paid Leave and instead refers to the currently approved company leave policy.
Version 1.8.19
Existing employee files have an evidence-safe ERP baseline
Current employee roles can be recorded from the ERP start date without falsely treating the latest designation or manager as the employee's original joining record.
Improved
Employment History now includes an explicit ERP migration baseline event for people employed before the platform go-live.
The baseline records the approved department, designation, reporting manager, shift and employment type effective 1 September 2026 while keeping the original joining date on the employee master.
Subhash Malik's confirmed promotion effective 1 January 2026 is retained as a separate historical event; his original pre-promotion designation remains pending source evidence.
Bhushan Gera's single Founder & Sole Proprietor employee record is assigned L7 Director, matching its approved JD without creating a salary revision.
The guarded seed refuses missing employees, unapproved JDs or grade/JD mismatches and does not invent onboarding invitations before personal email addresses are supplied.
Version 1.8.18
HR records begin from the approved ERP go-live date
Attendance, leave and shift records now follow the 1 September 2026 operating baseline, with policy corrections retained as auditable ledger adjustments.
Improved
Monthly leave accrual excludes fixed monthly service and board-remuneration records, future joinees, and Casual Leave for interns, trainees or employees still on probation.
A guarded reconciliation removes disposable pre-go-live and orphan attendance records while retaining original leave entries and posting linked compensating adjustments.
September Paid Leave is corrected to one day, and Vijay Gera and CA Sandeep Yadav no longer carry employee leave balances.
General Shift is fixed at 10:00 AM to 7:00 PM with Tea 10, Lunch 40 and Tea 10 in sequence, an eight-hour net-work rule, and a 30-minute move-out grace period.
Parvesh Gera receives General Shift and Kramajeet's existing-employee probation is corrected to three months ending 1 July 2026, with employee audit entries retained.
Version 1.8.17
Business ownership is governed through RACI
Thirteen effective-dated RACI processes now document responsibility and accountability across Propulsive's current HR, customer, finance, purchasing, fleet, IT and operating workflows.
New
The RACI baseline covers ERP governance, HR onboarding, attendance and leave, salary advances, support and onboarding, sales and collections, invoicing and payment recording, manufacturing and dispatch, sourcing and purchase, financial audit, statutory compliance, fleet logs, and IT support/deployment/onboarding.
Every active process has exactly one Accountable owner and at least one Responsible employee, effective from 1 September 2026.
IT support and SaaS deployment use Rajni as the documented interim Responsible owner until the approved IT manager and executive roles are hired.
RACI remains separate from RBAC and approval matrices, so documenting ownership cannot grant access or bypass maker-checker controls.
The guarded seed is insert-only, preserves administrator-owned active versions, fails if a required employee is missing, and requires an exact database name plus verified-backup acknowledgement.
Version 1.8.16
KRA and KPI baselines cover every operating department
The production-safe performance seed now gives every governed department a measurable, editable plan without inventing achievements or ratings.
Improved
Executive Office now receives strategic execution, financial stewardship and go-live readiness KRAs, so the proprietor home page has a real performance plan.
Information Technology includes support reliability, SaaS deployment and onboarding, access review and IT asset-control measures.
Project, production, procurement, inventory, PPC, furniture quality, dispatch, showroom, installation and facilities teams now have department-specific governed KPI definitions, directions, targets and reconciliation sources.
The seed remains insert-only and leaves KPI actuals, reviews, ratings, appraisal scores and incentives empty for managers to update from real evidence.
Version 1.8.15
Trainees are distinct from interns
HR can classify a training-stipend engagement as Trainee across employee records, JDs, requisitions, postings and employment history.
Improved
Trainee is now an explicit employment type throughout the Platform HR hiring and employee lifecycle.
Intern remains available as a separate category for internship engagements.
The IT Deployment & Onboarding Trainee can now carry L1 and the Trainee employment type without using the Intern category.
Version 1.8.14
Job descriptions carry the current salary grade
HR can classify each employee and hiring role against the live L1-L7 Salary Structure ladder while payroll continues to use the employee's effective Salary Revision.
Improved
The Job Description form now loads L1-L7 from Salary Structure instead of calling the retired legacy pay-grade endpoint.
The JD catalogue shows the grade code and name for workforce planning, recruitment, and role comparisons.
The pilot role catalogue now includes a dedicated Information Technology department plus plant-head, uPVC, millwork, metal, PVD, packaging, dispatch, installation, facility, and machine-operation job families.
A JD grade remains optional for fixed-fee professionals and service providers who are outside employee salary bands.
Actual pay remains governed by the employee's approved, effective Salary Revision so a JD change cannot alter payroll.
Version 1.8.13
Job descriptions follow roles instead of salary bands
HR can maintain one reusable job description for a role without forcing it into a legacy pay grade. Employee compensation continues to come from each employee's effective salary revision, including professional-service engagements that have no employee grade.
Improved
The Job Description form labels the pay-grade link as an optional legacy reference and explains the effective Salary Revision path.
A JD can be shared across employees in different salary bands without changing their compensation.
Contract and professional-service roles can now receive accurate JDs without being assigned a fictional employee pay grade.
Version 1.8.12
Receipt-backed TA bills with separated approvals
Eligible employees can submit travel allowance bills with owned receipt evidence. Each bill follows reporting-manager review, independent HR approval, and a separate Finance reimbursement record with a payment reference.
Added
A dedicated TA Bills workspace shows employee eligibility, personal claims, approval queues, settlement targets, receipt evidence, and the full reimbursement status.
Every submission requires one to three active receipts or tickets uploaded by the employee who owns the bill.
Manager approval routes from the employee reporting line, then authorized HR gives final approval, and a different authorized user records payment with its bank, cash, or voucher reference.
Approval and reimbursement decisions write append-only audit events, while rejected claims retain their evidence and reason.
Approved attendance punch corrections now recalculate gross time, actual break deductions, personal move-out deductions, net working hours and the configured shortfall status before the corrected record reaches monthly reporting or payroll.
Fixed
Approving a corrected check-in or checkout rebuilds the attendance row's stored gross and net hours instead of leaving the previous value behind.
Completed and automatically closed breaks are deducted from corrected attendance, while non-official temporary move-outs remain excluded from net working time.
The eight-hour requirement and configured tolerance are reevaluated after correction so payroll receives the corrected shortfall state.
The Attendance Regularization description now states the actual single-stage approval rule: the employee's reporting manager or authorized HR can decide the request.
Version 1.8.10
Breaks and move-outs show live progress
Attendance actions now use full-width cards. Active tea and lunch breaks show live progress against the scheduled allowance, while temporary move-outs show progress from departure to the employee's expected return time on both the attendance card and the locked return screen.
Added
The break lock screen shows a live, accessible progress bar, elapsed time, remaining time and the scheduled allowance.
Temporary move-out screens show progress from the recorded departure time to the expected return time, including minutes remaining or overdue.
The attendance card repeats the active break and move-out progress indicators so status remains visible in degraded or manager-assisted flows.
Break actions use stacked, full-width cards with the whole unused card as the click target and a full-width resume action inside the active card.
Improved
Progress bars use the shared UI-kit component, semantic status colours and screen-reader labels in light and dark themes.
Break progress changes to the danger treatment after the scheduled allowance, while move-out progress changes when the promised return time is exceeded.
Break actions remain disabled while another break or a temporary move-out is active, and the card explains when they become available.
Version 1.8.9
HR controls employee devices and activity retention
HR can now decide whether an employee may use one, two, or three active devices, choose whether a new login replaces the oldest device or is blocked, and end one or all sessions. Employee activity uses the existing business and security audit trails, with configurable retention, deletion previews and legal holds. The attendance card also reliably applies the 10/40/10 break policy to legacy shifts and locks every permitted device during an active tea or lunch break.
Added
HR can configure one, two, or three active devices per employee. The default is one device with the newest login signing out the previous device; selected field roles can keep more than one active session.
The Access Control workspace lists active device sessions with start and last-active times and lets authorized HR end one device session or all sessions with a required audit reason.
The Activity & Privacy workspace configures separate retention windows for daily activity markers, employee access events and ended sessions, security/business audit events, and AI audit events.
HR can preview records due for deletion without changing data, publish a privacy-policy version and notice URL, and pause the scheduled deletion job under a reasoned legal hold.
Improved
Every browser installation now carries a stable device identifier so separate computers on the same network are governed independently.
A tea or lunch break started on one permitted device reaches other open devices within the attendance policy polling interval and activates the same break lock.
The legacy General Shift break backfill now recognizes both stored array orders, so the former 15/15/30 policy upgrades to two 10-minute tea breaks and one 40-minute lunch break.
The activity policy uses the existing audit and daily-use ledgers and does not capture keystrokes, screen contents, or private message text.
Version 1.8.8
Employee operations now have controlled approvals
Salary advances now move through request, independent approval, disbursement and payroll recovery. Fleet evidence follows the reporting line, HR can publish versioned RACI ownership, selected employees can use audited inactivity controls, and attendance now locks the ERP during governed tea and lunch breaks while enforcing an eight-hour review policy.
Added
Eligible employees can request salary advances with a business reason and recovery plan. Approval and disbursement require different authorized users, and disbursed instalments flow into the matching payroll period with an audit trail.
HR can create versioned RACI process records with one accountable owner, at least one responsible employee, optional consulted and informed participants, effective dates, coverage metrics and controlled activation.
Authorized HR administrators can enable a configurable inactivity lock for selected employees, review their unlock reason, restore access with a recorded decision, or terminate an active session. Employee accounts permit one active system session at a time.
Starting a scheduled tea or lunch break immediately opens a reload-surviving account lock with the employee image, live clock, break allowance and elapsed time. The ERP resumes only after the server records the break end.
Attendance checkout measures net working time after tea, lunch and personal move-out periods. Shortfalls against the configurable eight-hour standard enter an HR review queue before payroll can run.
Fuel entries require a refill slip and every new fleet log follows the submitter’s recorded reporting manager for approval.
Improved
The General Shift break standard is ten minutes for each tea break and forty minutes for lunch. Existing untouched 15/30/15 defaults are upgraded without overwriting custom shift policies.
Vehicle odometer and service facts update only after the related fleet log is approved; rejected logs retain their proof and reason without changing vehicle facts.
The app lock verifies the current password without opening a second login session. Server-side lock state survives refreshes and records policy changes, requests, decisions, session starts and session endings. Tabs in the same browser reuse one session identity while a different browser or device is refused.
Version 1.8.7
GST split by where the work is, and a quote that says what it cannot price
A quotation's tax now splits the way the law expects: CGST and SGST when the site is in your own state, IGST when it is not, decided from the site on the quote and printed as separate lines on the proforma. The total is unchanged either way — only its composition. Elsewhere this release is about a quote telling you what it could not work out: a sliding wardrobe with no track chosen, a panel with no collection, a mechanism your library does not stock now say so on the results screen and on the hardware schedule, instead of quietly leaving the item out of the price.
Added
Tax splits by place of supply: a quotation's GST becomes CGST plus SGST when the site is in the same state you supply from, and IGST when it is not. Set the state you supply from once in Production Configuration; the proforma then prints each component on its own line.
A quote now reports every line it could not price, with the reason, on the results screen — a sliding bay with no track system, a panel with no collection, a shelf with no rate. The reason used to exist only inside the calculation.
The hardware and accessory schedule lists what a job needs but your quotation does not supply, such as a sliding track nobody has chosen yet, instead of leaving the row out altogether.
Two placeholder sliding-track systems ship with the library so a sliding wardrobe can be planned and drawn straight away. They carry no price on purpose: a quote using one is reported unresolved rather than costed as though the track were free.
Gola runs can state which face of the profile their level was measured to, and a house convention for it can be set once in Production Configuration.
Changed
The proforma prints the tax component by component rather than as a single combined line.
A quotation now says which construction standards it was calculated against — and says plainly when those are the built-in defaults that nobody at your business has reviewed or saved.
The proposal's appendix list no longer describes the hardware schedule as empty when it has items to print that your quotation does not supply.
The setup checklist gained rows for the state you supply from and for the Gola convention, and shows the sliding-track systems it finds.
Fixed
A discount above the limit set for a quotation's channel level is now refused when it is entered, naming the limit — and the refusal names the correct level for quotes holding a B2B enquiry, which it previously did not.
Version 1.8.6
A help desk for your team, wardrobes in the Quote Engine, and tidier proposals
Your staff can now raise and track support requests from their own profile, and your support team has a full desk to answer them with private notes, replies and resolution history. The Quote Engine gains wardrobes end to end: a unit library, all four door types including sliding, named internal layouts, lofts and their hardware on the schedule. Areas can carry their own charge and discount, optional supply lines come from the catalogue instead of being typed, and printed proposals no longer break a page straight after a heading.
Added
Helpdesk under My Profile: any employee can raise a request, follow its status and exchange replies with the support team, without needing support permissions.
A Support desk for staff: one command centre with queues for pending, urgent and unassigned work, private internal notes kept separate from replies the requester sees, assignment, resolution history and CSV export.
Wardrobes in the Quote Engine: a unit library, hinged, sliding, bi-fold and open door types, named internal layouts you can fill a bay from and keep editing, lofts, and a sliding bay's track charged and listed on the hardware schedule.
Wardrobes are drawn as their real doors in 3D and included in the quote documents and bill of quantities.
An area can carry its own charge and its own discount, within the discount range its channel level allows.
Optional supply lines are picked from the catalogue instead of typed by hand, and a line that could not be priced is reported on the result rather than only during planning.
A setup checklist shows what an installation still needs entered before quotes can price.
Fixed
Printed proposals and proformas broke a page immediately after a heading, because two page-layout settings were silently dropped whenever a report format was saved. Stored formats now keep them.
A proposal appendix that had drawings to print could be described as empty.
Attendance punch-in reminders: the tests covering them failed around midnight, which masked whether the reminder rule itself was right. They now run against a fixed clock.
Version 1.8.5
Quote a project area by area, and send it as a proposal with drawings and a hardware schedule
A project is now one quote divided into areas — a kitchen, a study, a bedroom — each included or left out. It prints as a premium proposal the customer can sign, with your standard terms, a bill of quantities cabinet by cabinet, and optional appendices: drawings to scale, a complete hardware schedule and 3D views. Website content for the three sites is now edited, reviewed and released through the CMS.
Added
Divide a project into areas from 42 templates or your own, include or leave out each one, and see what each holds. Cabinet lines, kitchens and typed lines each belong to an area, the planner opens on one area at a time, and the proforma prints area by area.
The Projects screen lists the quotes that have areas and opens each on its Areas step.
Print a project as a premium proposal: who it is prepared for, work packages by area, a bill of quantities cabinet by cabinet, specifications, delivery, exclusions, payment milestones and a page for the customer to sign. A cabinet without a rate says so rather than printing a zero.
Keep your standard proposal terms in Production Configuration. Each quote starts from them and can change its own copy; issuing a revision keeps the terms it printed.
Choose what a proposal PDF holds: the areas its detail covers, drawings printed to a stated scale, the complete hardware and accessory schedule — every hinge, runner, fitting and handle with what is included in a price, billed or free — and schematic 3D views. A contents list gives the page of each section.
Every proposal PDF is kept with the options and revision it was made from, and can be reprinted from the Proposal step.
Clear pictures of hardware for customer documents in Production Configuration, with where each came from. Only cleared pictures print; every other line says the image is unavailable.
Website pages for the three sites are edited as drafts in the CMS, previewed privately, reviewed and released as versions that can be restored, with navigation, redirects and search settings managed alongside them.
The media library records usage rights and review for every image and prepares responsive sizes. Newsletter issues are approved before they are sent, job applications arrive from the websites with their CVs kept private, and website chat opens a support case. Each needs its provider set up before it sends or receives.
Changed
Excluded areas stay on the quote with their value but leave the total, the cut list and the proforma, which says which areas it covers.
Version 1.8.4
B2B cabinetry quotes from a kitchen box library, priced from your panel definitions
A B2B cabinetry enquiry is now built from its carcass and shutter definitions and a grouped library of kitchen boxes, priced at the quote's channel level and printed as a proforma invoice. Each box can be divided into drawers and doors, given a handle, fitted from the hardware library, and seen in 3D.
Added
Define carcass and shutter panels once in the Panel Library, and build a B2B enquiry from them in one step. Its proforma invoice can supply cabinets only, shutters only, or both, with optional discounted hardware and accessories.
Add boxes from a grouped kitchen library: drawer and door units, sink and hob units, corners, lift-ups, pull-outs and accessory units, appliance niches and openings, panels and fillers, internal drawers and open bays, glass cabinets, islands and angled ends.
Divide a box's front into drawers, doors, false fronts and flaps, choose its handle (bar, Gola, inlay profile, full grip or CNC), and leave out a panel it does not need. Gola profiles are cut into the carcass and appear on the cut list.
Pick each enquiry's drawer systems, lift fittings, handles and accessories from the hardware library; accessories are suggested by the box's width. A standard hardware and materials library is added to the Item master.
See the selected box in 3D, open its doors and drawers, and show its minifix and dowels.
Keep the factory's construction standards, drawer profiles and lift fittings in Production Configuration, and set panel markups, discount limits and glass shelf costs by channel level in Pricing.
Changed
Panels are priced from the quote's channel level. Edge banding is included in the panel price, and handle routing and hinge boring are charged on each front from the shutter's own rates.
A B2B line is priced for one cabinet and then multiplied by its quantity, so the unit price and the line total always agree.
Fixed
Saving a quote no longer erases its cabinet plan.
The Quote Engine's dropdowns now match the rest of the application.
Version 1.8.3
Email-only joinee invitations and safer customer and supplier onboarding
HR can now invite a new joinee with just their personal email address; the joinee enters their own name and details through the secure link, and HR completes employment setup after approving them. Customer and supplier onboarding keeps approved records stable, stores uploaded evidence privately, applies stricter review controls, and supports refunds to the original payment method and recorded bank exceptions.
Added
Invite a new joinee to onboarding with only their personal email address. They confirm the email with a one-time code and enter their name, personal, bank and emergency-contact details themselves.
Nothing a new joinee enters reaches the employee record until HR approves it. The joinee then stays in pre-boarding until HR completes their employment details and activates them. Onboarding an existing employee still starts by selecting that employee.
Fixed
Expired invitation links can no longer change a submitted or approved onboarding case, and verification or resend actions cannot reopen a locked submission.
Gateway refunds return to the original payment method without requiring bank evidence. Bank-transfer payouts can use an explicitly recorded and audited approval exception.
Shared SaaS subscriptions remain blocked by the tenant-isolation gate even when the customer has not yet been enrolled or linked to CRM.
Customer, supplier and employee onboarding documents are stored privately and accepted only when their file name, type and contents identify a genuine PDF, JPG or PNG.
Approval checks provider GST evidence before updating any customer or supplier record: an inactive registration, or a name that matches neither the legal nor the trade name, blocks approval. A GSTIN not yet verified by a provider can still be approved with a recorded reason, and no exception can approve an unsubmitted form.
Staff contact verification, selected-record email auto-fill and valid action visibility now reflect the saved case correctly.
The portal and invitation email describe the GST certificate as required only for GST-registered organizations.
Approving an employee onboarding submission made before this release keeps the employee’s name.
Version 1.8.2
Secure onboarding for customers, suppliers and new joiners
Customers, suppliers and software subscribers can now be invited to a secure onboarding page to confirm their company details, contacts, bank account and documents, and one organization can be a supplier, a customer and a subscriber under a single verified record. HR gets the same kind of secure page for new joiners and for existing employees whose records need completing. In both cases the person confirms their email with a one-time code, and nothing they enter reaches your records until someone on your team approves it.
Added
Invite a customer, supplier, software subscriber or legacy white-label customer to a secure onboarding page. One organization can hold several of these roles at once, with one set of verified details.
The invitation email lists the documents to prepare. The authorized signatory's name is enough, with no proof of authority requested. The establishment registration and the Udyam/MSME certificate are needed only if they apply, and the GST certificate only when the business is GST registered.
The organization confirms its email with a one-time code, then enters its legal details, owner, accounts and IT contacts, who should receive which messages, and its bank account for payments or refunds.
Your team reviews each document, checks the GSTIN and the bank account, and approves the case. Approval updates the customer or supplier record.
Once an organization is enrolled, sales order confirmation, purchase order issue, payments, refunds and subscription activation wait for its approval. Existing customers and suppliers who have not been enrolled keep working as before and show a reminder to enrol them.
Onboarding invitations for new joiners and for existing employees, sent to the person's personal email address. The email lists each document to upload and says whether it is required, optional or needed only if applicable.
The employee onboarding page opens only after the person enters a one-time code sent to that personal email. The code expires after 10 minutes.
HR can accept each document or send it back with a correction note, open uploads through a secure link that expires after five minutes, and approve the submission once every required document is accepted.
Changed
Approving an existing employee's onboarding updates their personal details and documents only. Their login, roles and access stay exactly as they were.
Fixed
Links in onboarding, offer-letter and experience-letter emails could open a broken address. They now open the right page.
Version 1.8.1
Quote Engine cabinets planned on the drawing are priced from their technical definition
A cabinet placed on a Quote Engine room plan can now use a technical definition, so its panels are calculated at the size it is actually built and the same panels reach the price, the cut list, the drawings and the SVG, DXF and PDF exports. This release also carries the owner's construction decisions for corner, drawer and top panels, and fixes a set of planning problems found while working through complete kitchen and wardrobe quotes.
New
Choose a technical definition for a cabinet on the room plan and fill in the values it asks for. Its parts are calculated from that definition at the cabinet's planned size.
Kitchen cabinets can have drawers added, edited and removed after the cabinet is placed, including the drawer system's make, family, article and side clearance.
A board stock can carry its sheet price, and a part is only cut from a board of its own thickness.
Corner tops and bottoms are listed at full size, with a note that the L or diagonal shape is cut on the panel or beam saw, or by the nesting program.
Fixed
Undo and Redo on the room plan failed every time. They now work.
A cabinet created without doors could never be given doors afterwards.
A thicker replacement side narrowed the top and bottom but left the back too wide to fit.
A beam adjustment for a beam that was not in the room still cut the cabinet down.
A width, depth or height of zero or less was quietly changed to 600 mm. It is now refused with a message.
Editing the bays of a second wardrobe changed the first wardrobe instead.
Drawer backs and bases were labelled as drawer sides in the parts list.
A CNC premium could not read the size of the shutter it was on.
A technical definition that could not be calculated was quietly replaced by a standard cabinet. It is now shown as needing attention.
Some planning and quote screens ran off the edge of narrow windows.
Version 1.8.0
Edits in multi-row forms stay with the row you changed
Forms that hold a list of rows, such as document lines, addresses, discount tiers, salary slabs and workflow transitions, now keep every edit with the row it was made in. Before this release, an edit could be dropped without any message when you saved: after switching to another record while the form was still open, after removing a row from the middle of a list, or after moving a row up or down.
Fixed
After opening a different record while a form was still on screen, changes to that record's rows were not saved; the rows could even show the previous record's values. The rows now show the record you opened, and your changes to them are saved.
Saving a document with line items and then editing its lines again without closing it could lose the second change. Every save now includes the lines as you last edited them.
Removing a row from the middle of a list made the last row disappear instead, while the removed row stayed on screen. The row you remove is now the one that goes.
Moving a row up or down changed the saved order without moving the row on screen. The screen now shows the order that will be saved.
Version 1.7.1
Process flows that look like the design, and say what they know
The process band on every module now follows the approved design: completed stages are a pale tint of the brand colour with a check, the current stage is filled, and upcoming stages are plain tiles with an empty circle. Module Process Flow pages show bold, clearly separated stages instead of a thin strip. On an opportunity, stages carry their real names, the band ends in a single Won / Lost stage, stages ahead are shown as upcoming, and a stage the opportunity actually moved on from shows as completed with the date it did.
Changed
Process bands use one colour family, taken from your brand colour: completed stages are a pale tint with a check mark, the current stage is filled, and upcoming stages are neutral tiles. Completed stages were previously green, which did not match the design or the rest of the band. Choosing the Operational Teal palette under Appearance gives the exact colours of the design previews.
Module Process Flow pages show taller tiles with larger stage names and a solid arrow between stages, instead of a thin strip of small text.
The status legend beside a record uses the same marks as the band.
Fixed
An opportunity's pipeline stages showed their internal keys, such as demo_scheduled and proposal_sent. They now show their names.
Won and Lost appeared as two separate stages at the end of an opportunity's pipeline. They are one final Won / Lost stage again, and a lost opportunity is marked as lost there.
Every stage after an opportunity's current stage read Not determined. Stages not reached yet now read Upcoming.
A stage an opportunity has been moved on from now shows as completed, with the date of that move, taken from its recorded stage changes. A stage it was never moved through, such as one skipped by creating the opportunity at a later stage, still says Not determined rather than claiming it was done.
Version 1.7.0
See where the work stands, and plan projects from reviewed templates
Every module now has a Process Flow page that explains how its work moves from stage to stage, and an opportunity shows how far its own work has actually progressed, built from the quotations, orders, projects, surveys, deliveries and invoices saved against it rather than from its pipeline stage alone. Projects can start from ten reviewed milestone templates, with a preview of the plan against working days and holidays before anything is created. Customers now carry an explicit GST registration declaration and an individual or business identity, instead of both being guessed from whether a GSTIN happens to be recorded.
Added
A Process Flow page for each module, listed below its command center. It explains what each stage is for, what it needs first and who usually does it, and opens the screen where that work happens. It is a guide: it does not claim any record's progress.
An opportunity's record page shows how its work is progressing, read from the records saved against it: quotations, orders, projects, site surveys, production and purchasing, deliveries, acceptance, invoices and collections. Where something has not been recorded, or you do not have access to it, the page says so instead of marking the stage complete.
Opportunities can be classified as IT services, SaaS, B2B furniture, retail interiors or mixed. The classification is kept separately from the sales pipeline and the customer record, and changing one never rewrites the others.
Ten reviewed milestone-template families, from custom software and SaaS implementation to B2B cabinetry, retail kitchens and wardrobes, turnkey interiors, commercial fit-out and supply-only delivery. Templates can be edited, reviewed, published, copied and retired. Installing them creates drafts for review; nothing is published automatically.
Applying a template previews the resulting plan first: the work, its dependencies, owner and reviewer roles, the evidence each acceptance milestone needs, and dates calculated around your working calendar and holidays. Applying it to an existing project requires a reviewed baseline and an approved change, and keeps the work and financial links already there. Applying the same template twice returns the same project rather than creating a second one.
Where Estimation & Quotation is enabled, an ERP Sales quotation can be written, revised, reviewed, issued and accepted on one screen and handed to a sales order. The customer's tax classification is fixed at the moment the quotation is issued, so later changes to the customer do not rewrite an issued document.
Where Site Survey is enabled, a survey can be planned from the opportunity it belongs to and answered with typed values, each recording how it was measured and how confident the surveyor is. Verification and approval need a different person from the one who captured it.
Changed
A customer's GST registration status and whether they are an individual or a business are now declared on the customer record. A missing GSTIN no longer implies the customer is unregistered, and an existing customer with no declaration reads as not yet classified rather than being assigned one.
Fixed
Quotation codes generated into a CRM activity timeline are now hidden from people without permission to read quotations, on the opportunity, the customer timeline and the AI assistant's context. Notes people wrote themselves are unaffected, and no historical record was changed.
The quotation document-discount fields and the customer's GST declaration reason now show their error beside the field, rather than only in a message at the top of the form.
Version 1.6.0
An ID card with an ID on it, and somewhere to issue one
The Digital Employee ID has had a card design, a printable PDF, a scannable code and a public verification page for some time — and no way to issue one, so every employee's Workspace read "No Digital ID has been issued for you yet — ask HR to issue one" and HR had nowhere to do it. HR can now issue, reissue, suspend, reinstate and revoke a Digital ID from an employee's record, which makes the rest of it reachable for the first time. Alongside that: three of the four attendance card formats on Home carried no identity at all, and choosing a format did nothing until the page was reloaded; the calendar and the organization chart stopped short of the space they were given; and the Lead and Opportunity forms now follow the same sectioned pattern as the Employee form.
Added
HR can issue a Digital Employee ID from the employee's record, under a new Digital ID tab, and can reissue, suspend, reinstate or revoke it. Suspending is reversible and revoking is not, and the screen says so before you choose. Each action needs the permission it has always declared, so an installation can grant suspend without granting revoke.
Once a card is issued, the employee's own Workspace shows it with Download ID, Print ID and a verification code a reception or security desk can scan. None of that was reachable before, because no card could exist.
Fixed
Choosing a different attendance card format under Customize dashboard now changes the card straight away. It used to report success and leave the card exactly as it was until the next full page load.
Three of the four attendance card formats showed no photo, name, designation, employee code or work location — despite being named after an ID card. All four now carry the same identity line.
The attendance card's Check In, Move Out and Check Out buttons no longer run out of the card and over the panel beside them in the narrow Home column.
The calendar fills the space on screen instead of stopping short and leaving a band of empty page below it. Month, week, day and agenda each scroll inside themselves, and the calendars panel scrolls itself rather than stretching the page.
The organization chart uses the full width of the page rather than a capped reading column, and its frame takes the height left to it. A chart shorter than its frame now sits in the middle of it instead of at the top with the rest blank.
Changed
The Lead and Opportunity forms now follow the Employee form's sections: numbered steps that say which one you are on and how many there are, Back and Next buttons that name where they go, and a section marked "Needs attention" when it holds the field that is blocking the save. A blocked Opportunity save opens the section that is genuinely at fault rather than always the first one.
Both forms now behave correctly for keyboard and screen-reader users: opening a section moves focus to it, and each section header is properly tied to the panel it controls. No field moved and no grouping changed.
Version 1.5.10
Opening an opportunity now opens the opportunity
Opportunities opens on the board view, and a card on that board offered only an edit pencil — so clicking an opportunity opened the edit form, and the opportunity’s own page was reachable only from the table view, and only if you knew to switch first. The card title is now a link, so the record opens from the view that actually opens. Alongside that, three things on the record page that were visibly wrong have been corrected: the progress stages had a grey groove between them instead of meeting cleanly, the pipeline drew a dangling branch for “Lost” that the approved design does not have, and the GST panel was overlapping its own text inside the narrow side column.
Fixed
An opportunity card on the board now opens the opportunity. It previously opened the edit form, which is why the record page appeared not to have changed — most people were never seeing it.
The progress stages meet cleanly instead of showing a grey gap between each pair.
The pipeline ends in a single “Won / Lost” stage, as the approved design does, instead of a separate “Lost” hanging below the row on a dashed line. A lost opportunity is still shown as closed without a sale and still does not count as progress.
The GST panel no longer overlaps its own labels in the side column. It now shows the diagram where there is room for it and the plain statement where there is not.
The opportunity’s details are laid out in readable columns rather than stretching a date across half the screen.
Changed
The record page no longer displays a “Process” control. There is only one opportunity process, so it offered no choice and told a reader nothing.
Version 1.5.9
The opportunity page, matched to the approved design
The opportunity screen has been taken through the approved design one element at a time rather than in outline. It now opens with a single heading naming the record, its customer and its reference — “OPP-0142 · Asha Mehta — Kitchen renovation” — over the line of context the design shows, instead of two competing titles. Its fields sit in two labelled columns, each value in its own box, as drawn. Activity is a dated table with the person who logged each entry. The GST check sits inside the readiness card where the design puts it, rather than beside it, and the next agreed action carries the page’s one filled button.
Changed
One heading, not two. The page named the record twice, the second time with a value and a stage already shown by the progress band and the details below it.
The details card is two columns of labelled boxes, matching the design. It was three columns of loose text.
Activity is a table of date, time, what happened and who — with “Add note” as an action on the card rather than a form permanently open.
The GST compliance check is now inside the readiness card, and linked records say what kind of document each one is and when it was raised.
The page states which process it is showing and that you are looking at a record’s progress rather than the process guide.
Note
Some things the design shows are deliberately not on the page: a site location, a priority and tags, none of which this system records against an opportunity; and “attach file” and “view all” on the activity card, which have nothing behind them here. An empty box reads as information somebody failed to enter, and a button that opens nothing is worse than no button.
The breadcrumb follows the record’s real location rather than the one in the design image, which the design’s own written instructions ask implementers to replace.
Version 1.5.8
The opportunity page reads like the design
The opportunity record page kept three of its four sections behind tabs, so opening an opportunity showed you a quarter of it — and the part it hid worst was the activity history, which sat out of sight of the readiness check a few inches away that grades whether the record has any activity at all. The page is now a single column of cards you scroll, in the order the approved design shows: the opportunity’s own details, the site surveys raised against it, then its activity. The Process Flow page has been brought to the same chrome, with the process picker where the design puts it.
Added
Site requirement. A site survey has always been able to record which opportunity it belongs to, and nothing could ask the question — so the surveys existed and the opportunity had no way to list its own. It can now, and the card is honest about the difference between “no surveys” and “the surveys could not be loaded”, which matter differently to somebody deciding whether to send a surveyor.
A note can be added to an opportunity from the opportunity itself, rather than from a separate screen. The timeline is re-read from the server afterwards, so what appears is what was actually saved.
Changed
The opportunity page is a stack of cards rather than a set of tabs. Details, site requirement and activity are all on the page at once, followed by commercial documents, campaign attribution, competitors and stakeholders.
Every card now says in one line what it is, which the approved design does throughout and the page previously did not.
The Process Flow page carries a description under its title and puts its process picker in the page header as a dropdown, matching the design. Its footer now states plainly why every stage on that page is shown as not-started: a guide describes the process, it does not report on a record.
Note
The design also shows an “attach file” action beside “add note”. It is not built, because there is no file store behind an opportunity’s activity to attach anything to. A button that opens nothing would be worse than its absence.
Version 1.5.7
One name for an opportunity, and a cleaner main page
Two things the owner asked for after looking at the running system. The application had been calling the same record a “deal” in some places and an “opportunity” in others, sometimes on the same screen — the record page was headed “Opportunity details” under a breadcrumb reading “Deals”. It is now called an opportunity everywhere a person can read it. Separately, thirty screens — every module overview, dashboard and command centre — carried a strip of process stages above their figures. That strip describes a process rather than reporting on any particular record, so it was grey on every one of them, and it has been taken off. It remains where it means something: on a record, showing that record’s progress, and on the module’s own Process Flow page.
Changed
An opportunity is called an opportunity — in the menu, in search, in the command palette, and on every page title, breadcrumb, button, column heading, form label and empty state. Web addresses are unchanged, so existing links and bookmarks still work.
Module overviews, dashboards and command centres no longer carry the process strip. It described the module’s process in general and could not report progress, because those screens are not about one record. Each module’s Process Flow page still explains the process in full, and the menu still links to it.
The strip still appears on the twenty-one record screens where it shows real progress through that record’s own stages.
Note
Roles and permissions are untouched by the rename. Only what is written on the screen changed.
Version 1.5.6
Quote Engine stops looking like a different application
Quote Engine was drawing its icons from a different icon set than the rest of the product — different shapes and weights on every button, list row and panel, on every screen. Beside it in the same menu sat the older commercial quotation screens, which were on the correct set, so the newer workspace was the one that looked out of place. Every Quote Engine icon now comes from the same set as the rest of the application. The menu has also been reduced to the Quote Engine itself: the older commercial quotation and commercial masters screens no longer appear in it.
Changed
Every icon in the Quote Engine — buttons, list rows, panels, the drawing view list, the product workspace tiles — now comes from the same icon set the rest of the application uses.
The Quote Engine menu now contains only Quote Engine: Command Center, Process Flow, Quotes and Calculation Coverage. The commercial quotation lifecycle, commercial insights and the commercial masters under Setup & Administration no longer appear there.
Unchanged, deliberately
The commercial quotation screens still exist and still open. Only their menu entries were removed — nothing was retired, no permission changed, and an existing link or bookmark still works.
Converting a commercial quotation into a sales order is unaffected. That screen never had a menu entry of its own; it is opened from a quotation row or from a CRM deal, and the CRM route is untouched.
Version 1.5.5
The opportunity page can name its customer
Opening an opportunity from the deals list showed a progress band, a readiness checklist and a set of tabs, and nowhere on the screen did it say who the opportunity was for. The list row beside it showed the company and the contact; the record page showed neither. The cause was in the API: the list query asked for those names and the single-record query did not, so the page was sent two identifiers and had nothing to display. With the names arriving, the page now leads with an Opportunity details card carrying the record’s own facts, and the next agreed action moves to the side panel where it sits beside the check that grades it.
Fixed
An opportunity now shows its customer, its primary contact and how to reach them, the customer type and GSTIN held against the account, the owner, when it was created, its expected value and close date, its probability, its lead source and pipeline, and the requirement recorded against it. None of this was previously on the page.
The readiness checklist no longer contradicts itself. “Contact identified” counted a contact it could not name, so a green check sat above the words “No primary contact recorded”. Both halves now read from the same resolved contact.
The GST panel could not reach a classified state on this screen, because it reads the account and was only ever given the account’s identifier. It now reads the real account. Where an account has not declared its registration status the panel still says so — a missing GSTIN is not a declaration, and tax still applies either way.
The next agreed action, and whether it is overdue, is now visible without opening a tab. It sat inside the Overview tab, out of sight of the readiness check that grades it.
Changed
The record header no longer repeats six facts the details card below it now carries, and the side panel’s “Key facts” box is gone into the same card. The same fact shown twice on one screen invites a reader to wonder which is current.
Fields the design shows but the system does not hold — site location, priority and tags — are absent rather than shown empty. An empty labelled row reads as something somebody forgot to fill in.
Version 1.5.4
The Quote Engine landing screens join the rest of the application
The Quote Engine’s own screens — its Command Center, quote list, calculation coverage and quote progress board — were missing the process band that every other module carries at the top of its landing and list screens, and their summary figures were plain unclickable panels. Opening Quote Engine therefore looked like arriving in an older, separate product, whatever the screens further in looked like. The band is now there, and each figure on the Command Center is a real card: it says what the number means and where it came from, and clicking it opens the records behind it.
Changed
Quote Engine’s Command Center, quote list, calculation coverage and quote progress screens now carry the same process band as every other module, in guide form — it explains the stages a quote goes through rather than reporting any one quote’s progress.
The four figures on the Command Center — quotes, drafts, issued and declared rule gaps — are now cards you can open. Each carries the definition of what it counts, and the rule-gap card also says how it was counted: from the engine’s own registry of what it does not implement, never inferred from missing output.
From the Command Center you can now reach the quote list and calculation coverage by clicking a figure, rather than only through the navigation menu.
Known
The quote list still draws its own table rather than using the shared one, so it does not yet offer the column, density and sorting controls other lists in the application have. The table is correct and readable; it is the controls around it that are missing.
Version 1.5.3
Open a record from its list
Twelve modules had a record screen — the page showing one support case, one work order, one purchase order, one asset — and nothing in the application linked to any of them. They were built and they worked; there was simply no way to open one. The only process flow anyone could reach was the module guide page, which explains a process rather than tracking a record, so every stage there reads as not yet started and the whole band is deliberately grey. That is why the flow looked colourless: not a broken palette, but the correct rendering of the only page that could be opened. Each list now opens its record from the identifier in the row.
Fixed
The identifier in each list row now opens that record, across support, manufacturing, purchase, accounts, inventory, assets, projects, fulfilment, training and leave.
Work management opens its records from the work breakdown tree, which is where work items actually appear — there is no separate work-items list to click through.
Onboarding opens by employee, because that is how an onboarding record is identified.
The process flow on a record screen now shows that record’s real progress. It was only ever grey because the module guide was the sole reachable page, and a guide asserts no progress by design.
Changed
Lists keep managing records in side drawers, which is unchanged and deliberate. The row identifier is now additionally a way into the full record screen.
Version 1.5.2
The kitchen and wardrobe screens look like the workspace they are
The CAD planning and drawing screens that arrived in 1.5.0 worked, but they were laid out like a standard record page — a heading, a row of summary tiles, then stacked notices — rather than like the drawing workspace they were designed as. This rebuilds them on the layout the design review approved: the quote’s name and status at the top with its key facts on one line, the process band beneath it, a row of sections, and then a single framed workspace holding the list of views, the drawing itself with its own toolbar, and a properties panel beside it. Nothing about the drawings, the calculation or the exports changed — only where things sit and how the screen reads.
Changed
CAD planning and Drawing review now open as a single bordered workspace: the list of drawing views on the left, the drawing in the middle with its own zoom and fit controls, and the properties panel — layers, plot settings, exports and the resolved specification codes — on the right.
The revision, formula version, view count and output status used to sit in four tiles across the top. They are facts about which quote you are looking at, so they now sit on one line under the title, with the revision status shown as a chip beside the name.
The drawing sits on a framed sheet with its own header and footer, so the caption that says the on-screen rendering is not to the sheet scale reads as a property of the drawing rather than a note about the page.
The quote configuration screen carries the same identity header, so moving between configuring a quote, planning it and reviewing its drawings no longer feels like moving between three products.
Zoom and fit on the drawing are screen-only. They change nothing about the geometry, the sheet scale, or a single byte of any export.
Fixed
The process band on these screens was a second, thinner copy of the one every other module uses. It now uses the shared band, which means each step shows the sentence explaining its state, and steps that cannot be reached say so rather than looking merely incomplete.
Sections that have no screen in this release are no longer shown as tabs. A tab that does nothing when clicked reads as a broken workspace rather than an unfinished one.
Version 1.5.1
The corporate homepage is edited in the CMS, not in the code
The corporate site’s homepage lived in the website source, so changing a headline meant a developer and a rebuild. This release moves that page into the CMS: the homepage is imported as a governed draft, edited and published through the normal page workflow, and the website reads it from the published feed. Publishing a page still does not make a hidden site readable — the public feed checks that the site itself is published, not just the page.
Added
The corporate homepage is a CMS page. An import brings the existing hero, expertise, outcome and closing-call-to-action blocks in as a draft, so the live wording is preserved rather than retyped, and replaying the import on untouched content changes nothing.
The public website reads the homepage from the published CMS feed instead of from its own source, so an editor’s published change reaches the site on its next build with no code change.
A time-limited preview grant renders an unpublished homepage draft at a chosen viewport, so wording and layout can be checked before publishing without exposing the draft publicly.
Changed
The public content feed sends no-store cache headers and asks search engines not to index it, so unpublishing a page takes effect immediately rather than after a cache expires.
Fixed
Two dead Bootstrap classes in CRM and elsewhere that styled nothing after the design-system migration.
Not included
Editing the homepage does not publish the website. The corporate site is still governed separately, and its publication state is what decides whether the page is served.
Version 1.5.0
Plan a kitchen on screen, and quote from the same drawing
The Quote Engine could price a kitchen but never place one. It calculated parts — a width, a height, a thickness and a quantity — with nothing to record which drawer sat in which cabinet or how high a shelf landed, so no drawing could be derived from a quote and the two were kept in step by hand. This release adds a planning workspace where cabinets and wardrobe bays are placed against measured walls, and produces the plans, elevations and sections from the same saved calculation the quote is issued from — so a drawing cannot describe a different kitchen from the one being priced. Alongside it: the HR onboarding flow, process-flow status on 22 of 23 modules, and several dropdowns that were being clipped by the panels they sat in.
Added
Kitchen and wardrobe CAD planning in the Quote Engine. Rooms, walls, openings and obstructions are measured; cabinets are placed along a wall and wardrobe bays across an opening, with internals — levels, shelves, rails and drawers — placed inside them. Dimensions are edited against the base you actually measured (site opening, external carcass, clear interior, additional cover or overall installed), and the screen says which one it is using.
Placements are checked in three dimensions, not on the plan alone. A wall unit sitting directly above a base unit overlaps when seen from above and is correct; a plan-only check would reject it, and every real kitchen with it. An edit that would put two cabinets in the same space is refused and the previous layout is left exactly as it was.
Coordinated drawings from the saved revision: a plan, an elevation for every measured wall — including walls that carry only a window or a door — and sections. A wardrobe gets closed-front, internal, plan, rear, both ends and a section for each bay.
Export as SVG, as a vector PDF sheet, or as DXF for CAD. All three are drawn from one set of entities, so they cannot disagree with each other, and a reprint of an issued revision is identical to the first print.
Planned cabinets now reach the cut list, the board plan and the costing, not just the drawings. A planned kitchen produces panels to saw in the same place every other module does.
Sloping tops, columns and beams. Panels, backs, shelves, fronts and fittings each recompute against the shape; anything the engine cannot resolve stays an editable draft carrying the reason, rather than being quietly approximated.
A Quote Engine Command Center, and a Quote progress board showing where every quote stands across Site & measurements, CAD planning, Collections, Internals & fittings, Drawing review and Quote. A step counts as complete only when the saved record supports it — opening a tab does not complete a step.
The HR onboarding flow, built from the models its own preview shows.
Process Flow is now recorded on 22 of 23 modules, so the status band reports what a module actually has rather than reporting nothing.
Changed
The status band no longer tells readers the system lacks things it has. It was describing absent records for modules that had them.
The Quote Engine uses the platform-wide Process Flow row rather than one of its own, so the entry behaves the same here as in every other module.
Fixed
Dropdowns clipped to a sliver by the panel they sat in — the calendar view selector, the CMS site switcher and the Quote Engine planning inspector. Each showed only its current value and could not be opened. A page header scrolls sideways, and a menu drawn inside it was cut off at the edge; the menus are now drawn above the page instead.
robots.txt reported the wrong cause when it was serving a restrictive rule, so the diagnostic sent readers to the wrong setting.
Not included
Exact manufacturer cutting rules. Naming a brand does not select a deduction, so without a resolved manufacturer, article and technical revision a drawer or slider is reported unresolved rather than guessed.
Hinge, lock and closer counts — no rule derives one from a leaf size or weight.
Native DWG, associative dimensions and CNC output. The DXF is validated on its own terms; exporting a drawing does not drive any machine.
Shaped-part nesting. The saw planner still prepares rectangular blanks, so a notched part is not finished merely because the rectangle around it fits.
The other eight product workspaces. They are named in the Command Center and marked not yet operational rather than left to look available.
Version 1.4.0
A calendar you can read a week in
The calendar that arrived in 1.3.0 showed the right work in the wrong shape: everything sat at the top of its hour, a fifteen-minute call and a three-hour installation drew the same block, two meetings in one hour covered each other up, and the panel beside the grid was usually empty. This rebuilds the workspace around a continuous time grid where an event sits at the minute it starts and is as tall as it actually lasts. There is a Day view, a small month navigator for jumping around, a list of your calendars you can switch on and off, and event details that open where you clicked instead of in a permanent side panel. Times are now shown in your organisation's timezone throughout — the toolbar said one thing and the grid did another.
Added
A Day view, alongside Month, Week and Agenda. Picking a date and switching to Day opens on the day you picked, not on whatever the previous view was centred on.
A month navigator beside the calendar for moving around quickly. It shades the range the main view is actually showing, and the arrow keys move a day, a week or a month at a time.
A list of your calendars, grouped by the module each belongs to, with reminders kept in their own group. Each one carries the colour its events use in the grid, so the list reads as a key rather than a set of filters. Collapsing a group hides its rows and changes nothing about what is shown.
Event details now open in a small panel next to the event you clicked, with the date and time, the timezone, which calendar it came from, its status, any amount you are allowed to see, and Open source record. Escape or the close button dismisses it and puts you back on the event.
A line above the grid when something falls outside working hours — "1 item outside 09:00-18:00, earliest Thu 02:40" — with a Show link that scrolls to it.
The whole day is always there to scroll through, so evening visits, night shifts and overnight jobs have somewhere to appear.
Changed
Events are placed by the minute they start and drawn as tall as they last. A 09:30 meeting no longer sits on the 09:00 line, and a three-hour installation no longer looks like a forty-five minute call.
Overlapping events sit side by side in their own columns instead of on top of one another. Two events that merely run back to back still each get the full width.
Times are shown in your organisation's timezone everywhere — which day an event falls on, where it sits in the grid, which day is marked today, and the current-time line. The toolbar named that timezone before but the grid quietly used your computer's. If the two differ, the calendar now says so.
The always-present panel beside the grid is gone. It was empty unless you had selected something, and the space belongs to the calendar.
Unticking every calendar now shows nothing, and says so. It used to show everything, which is the opposite of what unticking them asks for.
Your view, your calendar selection, the panel being open or closed, and where the grid was scrolled to are remembered between visits. A saved selection is re-checked against what you can currently see, and the calendar still opens on today.
Opening a record from the calendar and coming back returns you to the date and view you left.
On a phone the agenda gives each entry its own line for the record name instead of squeezing it into a narrow column, and the calendars panel starts closed so the schedule is the first thing on screen.
Each calendar has its own colour, used consistently in the week grid, the month cells, the agenda and the list. Colour is never the only signal — every entry also carries its calendar's name and an icon for its kind.
Fixed
A reminder, or anything with no recorded end time, no longer appears to occupy an hour. It is shown as a marker at its moment, and its details show one time rather than a range.
Work spanning several days now appears on every day it covers. It previously showed on the first and last day only, so a three-day installation was missing from the middle of the week.
Something running until exactly midnight no longer also appears on the following morning.
The current-time line is drawn only in today's column. It previously ran across unrelated days, and it is a clock marker rather than a warning — red is kept for work that is genuinely overdue.
An overdue deadline is now marked as overdue in the month view too.
Long record names no longer push the time out of an event and get cut mid-line. Short events show what fits and the full text is always in the details panel and the agenda.
A day with a single early reminder no longer opens the week on an empty pre-dawn screen. The grid starts on the working day and points at the early item.
Note on the version number
1.3.0 is live on both servers, so this is a new version rather than another build of that one. Nothing about 1.3.0 is withdrawn — this changes how its calendar looks and behaves, and the underlying data, permissions and sources are the same.
Version 1.3.0
A quoting engine, a calendar everywhere, and drawings the shop can build from
The largest release so far, and the first to reach these servers since 1.1.56. Estimation & Quotation becomes Quote Engine: a standalone workspace that prices a kitchen, wardrobe or doorset and returns a cut list, a board plan and an issued revision that still adds up months later. A shared calendar shows everything dated you are meant to see, and the same calendar appears inside ten modules. The shop floor gets part labels it can print and a terminal it can scan at, and the drawings, BOMs and cut plans it works from now agree with each other about thickness. Account & Access is rebuilt around roles, so an HR Admin can grant a new starter their access without going to a Superadmin.
Added
Quote Engine, at Quote Engine → Quotes. Enter wall runs for a preliminary budget, or configure carcasses, shutters, drawers and doorsets for a detailed one. It returns parts with both finished and cut sizes, a nested board plan with a sheet count, costing, and issued revisions. The module also stops being hidden: the flag that concealed the whole section is gone, so it appears in the launcher on installations where that flag was never switched on.
A Calculation Coverage screen listing every geometry, costing and board-planning rule the engine applies and where each came from — and the five things it refuses to guess: hinge, lock and closer quantities, wardrobe-specific construction, and glass and aluminium profiles. A gap you can price by hand is worth more than a number nobody can trace.
Part labels that print. Every part-label screen previously returned data only, so the shop had a scanning system and nothing to scan. There are now two printable outputs: a single 100×70mm label carrying QR, cabinet, size, material and next station, or a whole work order’s labels as one print job — a page each, sorted by cabinet and part.
An operator terminal under Manufacturing, built for standing at a machine. The scan box keeps and re-takes focus after every scan, because a barcode scanner is a keyboard and lost focus looks like a broken station. The verdict is the largest thing on screen and is carried by shape and text as well as by colour.
A design workspace that can place openings: pick a window or door from a template picker showing each type’s plan symbol, watch a ghost preview report problems as sentences you can act on — “Runs off the end of the wall” — and sketch several obstructions in one pass.
A People calendar under Time & Attendance: approved leave as one entry per day of a multi-day absence, joining, probation-end and notice-period milestones, holidays and interviews.
A shared calendar at Calendar, with Month, Week and Agenda views. Week opens by default on a desktop; on a phone it opens on Agenda, where a seven-column grid cannot be read.
The same calendar inside People, Financial, Sales, Purchase, Delivery, Production, Statutory, Despatch, Developer and Assets, each showing only that area’s own work.
Thirty-eight kinds of dated record now appear, including meetings and follow-ups, service response deadlines and site visits, holidays, interviews, approved leave, joining and probation dates, invoices and vendor bills due, estimate and quotation expiry, purchase deliveries, RFQ deadlines, scheduled work and deliverables, work orders and planned maintenance, despatch lines, e-way bill validity, TDS deposits, vehicle document expiry and your own to-dos.
Reminder entries appear separately from the work they remind you about, so acting on a reminder never marks the underlying task done.
Changed
Account & Access on an employee is now just roles. The old “1. Module Access / 2. Roles for Selected Modules / 3. Access Review” wizard has been removed — its module checklist never granted anything, because permissions have only ever come from roles. In its place: a searchable role picker, and a read-only Effective access panel showing what the person can actually open, worked out by the server from the same rules it enforces.
An HR Admin can now grant staff their access without a Superadmin, for anything whose permissions sit inside what HR Admin itself holds. In exchange HR Admin becomes a privileged role: only a Superadmin or Platform Admin can grant it.
Roles you are not allowed to hand out are locked in the picker with the reason on the row — “Grants permissions you do not hold yourself, so you cannot delegate it”, “Privileged role — needs global role-assignment authority” — rather than failing silently on save.
Assigning roles is its own action with its own reason. “Save roles” will not run without one, every change is written to the audit trail with who and when, and a save refuses to overwrite someone else’s edit made since you opened the form. Editing employment facts can no longer change access at all.
You cannot change your own access, and resetting someone’s password now requires that you would be allowed to assign every role they hold — closing the route where a password reset stood in for a promotion.
Seeing costs and margin on a quote is a separate permission from opening one. A coordinator gets the full specification, cut list and board plan; the Costing tab says “Costing is hidden for your role” instead of showing zeros that read as free.
An issued quote still adds up months later. Picking a material copies its code, description, unit, dimensions and rate onto the quote along with the catalog version and the time it was taken, and every calculation reads that copy. A draft offers “Check for catalog changes”; an issued revision never moves under you.
You only ever see calendar entries you already have permission to read, decided for each kind of record before it is fetched. The list of calendars you can switch on shows only what is available to you.
If one kind of record cannot be loaded, the calendar says which and keeps showing the rest, instead of appearing empty as though nothing were scheduled.
People data stays out of the organisation-wide view. A probation ending shows as an unnamed entry there and names the person only on the People calendar.
Your to-do list is visible only to you, on your own calendar, whatever anyone else’s permissions are.
Fixed
The BOM is issued per board, not per material name, and at the size you actually cut. A larder used to issue one line reading “MDF, 89.48 sqft” covering 18mm carcass panels, a 6mm back and 6mm drawer bottoms — nothing anyone can order from, since the same rate card prices 6mm and 18mm 87.5% apart. Lines now split by material and thickness, and the BOM stops requisitioning more board than the quote ever priced.
Cut plans put each piece on a sheet of its own board, and name that board’s thickness. Every nesting layout used the first sheet in the list regardless of the piece’s material, so a 6mm back, an 18mm side and a 20mm stone slab were laid out together and the second sheet definition was inert.
Cabinet drawings now agree with each other and with the cut list. Doors and drawer fronts in the section view were drawn from the cavity rather than the cabinet top, putting a 694mm door 12mm below the wall unit it hangs on; corner units had no drawings at all.
A quote could show six sheets of ply and a priced doorset and still total zero, because neither reached the total. Both are counted now, with the board plan’s waste marked as already included so a wastage percentage cannot be applied on top of it twice.
The room check stops inventing conflicts with beams and doorways, and starts catching the case that matters: two cabinets in the same place.
A production batch that scraps a panel at cutting can be closed, instead of staying open forever.
The CRM calendar no longer shows one salesperson the whole team’s diary. The owner was a filter the caller chose rather than a scope, so anyone holding one of four CRM read grants could read every user’s scheduled activities by changing an id in the address bar.
Terminating or deleting an employee can no longer lock the business out of its own access administration. The last active account able to administer access cannot be stripped of that role, disabled, terminated or deleted — and that refusal now covers the ordinary HR paths too, which previously went around it.
People data stays inside HR on the company-wide calendar. Outside HRMS, an absence, a probation ending or an interview shows without naming anyone; names appear only on the People calendar, and only to someone holding the HR read permission for that kind of record.
Organization chart: “Fit to screen” now actually fits. It measured width only — correct while the chart frame was always taller than the chart, but since the frame started filling the page a tall organisation overflowed downward and the button did nothing at all. It now takes whichever of width or height needs the bigger reduction, and rounds the zoom down rather than up, so the result no longer overshoots the frame by a few pixels.
Module Control announces what happened to a screen reader when you reorder or save. Moving a row swapped it and renumbered every position, all of it invisible without sight.
Self-service checkout stops telling a customer mid-purchase that it lost their session when it had not.
Each of the three websites gets its own link preview card. All three emitted the same neutral image, so a Woodworking ERP link and a Propulsive link previewed identically wherever they were shared.
The CRM calendar could show one person the whole team’s scheduled activity. It now shows an individual contributor only their own, matching the follow-up and appointment lists beside it.
Due dates, holidays and expiry dates can no longer shift by a day. An invoice due on the 9th reads as the 9th regardless of timezone.
Needs a database update before it takes effect
Codes on 86 record types — Product Engine materials and the Design Library first, then AMC, service ticket, warranty, expense claim and payment receipt numbers among others — were declared unique in the code, but the constraint had never actually existed in the database, so duplicates could be created. The repair ships here as database updates 054–058. Deploying does not run them: they are applied by hand, per server, and until that is done duplicates remain possible on those records. Everything else in this release works without them.
Note on the version number
This release has been numbered three times, and both earlier numbers were already taken. It was first 1.1.49, which a parallel line of work had already used and has since carried to 1.1.54. It then became 1.2.0 — but 1.2.0 was already published on woodworkingerp.com and propulsive.in as "August platform update", dated 2026-08-25, so that number already names a different release in front of customers. It is now 1.3.0, which nothing has published. Nothing was ever published from here as 1.1.49 or as 1.2.0.
Version 1.1.48
Two release lines merged, plus Reports-to and document details
This number named two releases. On one line it merged the Design Engine and report-format work with the role-only access change and fixed a checkout lease and a test port race. On the other it made Reports-to save and gave documents their own recorded details. Both shipped as 1.1.48 before the lines were joined, so both are recorded here rather than one being renumbered after the fact.
Changed (merged-lines release)
Two release lines were merged into one. The only overlaps were version identity files and the changelog; no source conflicts arose.
The merged tree is 1.1.48 because 1.1.30 names two different releases — each line numbered independently from 1.1.29 — and neither was renumbered after publication.
Fixed (merged-lines release)
Self-service checkout could report "processing ownership was lost" to the worker that still held the lease, when two heartbeats landed in the same millisecond. Ownership is now proved by matching the lease, not by the write changing a value.
The parallel-test port-race retry recognised only one of the two messages that race produces, so whole test files failed together while the retry never fired.
Fixed (HR and documents release)
Choosing a reporting manager saved nothing. The picker showed the person you clicked, and the record kept none — confirmed against the database, where every employee on both environments had no reporting manager at all, including records saved that morning. The picker emits the selected employee rather than a plain id, and the code read a field that employee does not have, so a real choice became empty on the way to the form. Reopening an employee also now shows the manager already on file.
Added (HR and documents release)
Employee documents now record the document number and issue date beside the expiry date and the attachment, so a licence, passport or certificate is filed as a document rather than only as a scan. Aadhaar Card and PAN Card are unchanged — they remain plain upload slots.
Verified (HR and documents release)
New reporting-manager and document contract suites 8/8 between them, HR 677/677, platform 8456/8458 (the two failures are an unrelated timing-sensitive test that passes on its own).
Note on the version number
1.1.48 was issued independently on two lines of work that were numbering separately. Both had already shipped under it, so neither was renumbered; this entry carries what each contained. The lines were merged on 2026-09-08 so it cannot happen again.
Version 1.1.35
Money and tax corrections in Sales
Four defects in how credit notes, GST place of supply, mixed-category tax rates and draft invoices handle money. None has reached a customer — there are no invoices or credit notes on production yet.
Fixed
A credit note credited the price before discount. A line billed at ₹8,000 after a 20% discount was credited at ₹10,000 — refunding money the customer never paid and reversing GST that was never charged. A full credit of a discounted invoice was then rejected for exceeding the invoice total, so only partial, over-refunding credits went through. Credit notes now use the price actually billed.
An undetermined place of supply was charged as IGST. When the customer’s state could not be resolved, the whole tax was assumed to be inter-state — so a local customer was charged IGST instead of CGST+SGST and filed in the wrong GSTR bucket. It no longer guesses; a taxed document whose place of supply cannot be determined is refused at posting, naming the record to fix.
A mixed-category estimate was taxed at whichever line happened to sit first, so reordering the lines could change the tax on the quotation. Every category is now resolved: if they agree that is the rate, and if they genuinely differ the platform default applies — the documented behaviour all along. Same fix on quotations.
A draft tax invoice printed a grand total that included tax above three tax lines each reading zero, because the CGST/SGST/IGST split ran only at posting. Drafts now carry their own split, so the figures agree.
Verified
New money and tax contract suite: 12 tests covering the intra/inter/undetermined split, credit-note discount arithmetic, a full credit reproducing the invoice total, and order-independence of the mixed-category rate.
Sales, tax, invoice, credit-note, estimate, quotation and commercial suites 806/806; accounting money 21/21 and ledger 9/9.
Setup note
A GST invoice cannot state CGST/SGST or IGST without the seller’s own registration. The Head Office business unit has no GSTIN or state set, so a taxed invoice will not post until one is entered.
Version 1.1.36
Destroyed vendor details, a compensation leak, and two wrong prices
Four confirmed defects from the pre-production audit: an edit that silently wiped vendor bank and tax details, salary changes visible to a role denied compensation access, quotation revisions that raised the price, and ESI charged to employees who are not covered.
Fixed
Editing a vendor silently erased its GSTIN, PAN and bank details. Those fields are hidden from anyone without the admin-only bank/tax grant, so the edit form loaded them empty and saved them back as empty — destroying values that role can never see to retype. The damage carried onward: vendor bills read the place of supply from that GSTIN, so the next bill lost its CGST/SGST vs IGST determination and the GSTR purchase rows went out with a blank counterparty. A field you may not read is no longer a field you may write; the stored value is left untouched.
The employee audit log returned salary and bank changes to roles denied compensation access. Salary is stripped from the employee list, the detail screen, the CSV export and the employment summary for those roles — and was then handed back in the change log, with the previous value attached. The values are now redacted while the row still records that a change happened, who made it and when.
Revising a quotation silently raised the price. The revision copied every line field except the negotiated per-line discount, and the total is recomputed from that percentage — so a quote of ₹1,06,200 came back as a v2 draft at ₹1,18,000 with the discount gone from every line and nothing on screen saying so.
ESI was charged to employees who are not covered by it. Eligibility was tested against the month’s prorated pay rather than the contracted salary, so anyone above the wage ceiling dropped below it in any month with unpaid leave and gained an ESI deduction they have never had and hold no ESI number for — contradicting their own approved salary structure. Coverage now follows the contracted salary; the contribution still follows the wages actually paid.
Verified
New wave-1 contract suite 8/8; vendor sensitive-data masking 9/9 including a case that posts blank bank fields and asserts the stored values survive.
HR 672/672, CRM 729/729, platform 8405/8406 — the one failure is a timing-sensitive lease test that passes in isolation and is unrelated.
Version 1.1.37
Dashboard figures that were quietly wrong
Receivables that omitted money still owed, a CRM open-AR figure that collapsed to zero, and won deals credited to the wrong month.
Fixed
The Sales Command Center dropped every partially credited invoice from receivables, overdue and ageing. A partial credit note reduces an invoice; it does not settle it, and the remainder is still owed. The same invoice counted against the customer’s credit limit and appeared in the AR ageing report while being missing from the dashboard. The definition of an open receivable now lives in one place instead of five.
CRM open receivables collapsed to ₹0 for the rest of the day as soon as any lead or deal was created before the nightly figures ran. The dashboard took its balances from whichever snapshot row came last, and an event creates a row with no financial figures in it — so a real balance read as zero, indistinguishable from being paid up. Rows now record whether the financial pass actually ran.
“Won this month” credited each win to the day the deal was created rather than the day it closed, so it only ever counted deals created and closed inside the same calendar month — the longer the sales cycle, the more of the month’s revenue disappeared from the figure. The same applied to deals lost. A deal with no recorded close date still counts on its creation day, exactly as before, so nothing moves without evidence.
Verified
CRM 733/733 including four new cases: a July-created deal won in September counted in September and not July, the creation counter staying on the creation day, and open AR surviving a later event-only row.
Platform 8410/8410 — a fully green run.
Version 1.1.38
Permissions that hid the wrong things from the wrong people
Approvals invisible to the managers authorised to give them, settings screens hidden behind a key none of them use, and write buttons offered to viewers who cannot use them.
Fixed
Reporting managers could see their team’s attendance regularization and move-out requests but had no Approve or Reject button. The decision endpoint deliberately allows either the employee’s reporting manager or the HR approval permission; the screen checked only the permission, so the queue built for line managers was unusable by them. Each row now carries the server’s own answer.
CRM Module Settings was hidden behind the CRM settings-write permission — the key for one of its eleven screens. Anyone holding, say, Portal Users access but not CRM settings-write lost the entire group. Each destination is now gated on the permission it actually requires.
HR Module Settings had the same fault: an HR Manager who may edit shifts, departments, holidays and leave types saw none of them, because the group demanded a settings-write key none of those screens use.
CRM Deals, CRM Leads and Sales Estimates offered Add, Edit, Delete and Create revision to every viewer and refused the action only after it was attempted. Those buttons now appear only for people who can actually complete them.
Changed
A settings group whose destinations are all hidden by permission no longer renders as an empty heading.
Verified
New permission-gate contract suite 6/6, including a check that both approval queues fail closed outside the approval scope.
Customer receivables summed from the 50 newest invoices, a bank reconciliation that never looked at the ledger, marketing rates counting inbound replies, and three more totals counting the wrong rows.
Fixed
Bank Reconciliation’s Difference never consulted the ledger. It was arithmetically just the unmatched statement total — the number already shown beside it — so matching every imported line displayed a green 0.00 “reconciled” while the books still held entries no statement accounted for. The book side now comes from posted, unreconciled ledger movements, and a new tile shows them.
Customer 360’s Open AR and Payments were summed from the 50 most recent invoices and payments. Both lists are sorted newest first, so the figures excluded precisely the oldest — the ones most likely to be overdue. Both are now aggregated over the whole customer, and a partially credited invoice counts toward what is still owed.
Marketing delivery, read and failure rates counted inbound customer replies, which are stored as delivered because they did arrive. A busy inbound week pushed the delivery rate up and the failure rate down while outbound performance was unchanged. The statistics now describe only what was sent.
The Customer 360 service card called every high-priority ticket ever raised “urgent”, so a customer whose urgent issues were all resolved kept the same red count forever — and disagreed with the Command Center and CRM Dashboard, which both scope urgency to open tickets.
AP ageing ignored the “As of” date while AR honoured it, so the combined screen aged supplier bills that had not been raised yet on the chosen date and moved Net exposure when only the receivables half should have changed.
People Command Center’s “Active Workforce” counted soft-deleted employees and the dev onboarding account, contradicting the Payroll Readiness figure beside it.
Verified
New figures contract suite 7/7, including a case proving the reconciliation difference can now be non-zero when every statement line is matched — the state the old formula made arithmetically impossible.
CRM 733/733, HR 672/672, platform 8415/8416 (the one failure is an unrelated timing-sensitive test), TypeScript clean.
Version 1.1.40
Reports, exports and payroll that disagreed with themselves
A report that ignored its own filters, a cost-to-company lower than net pay, PF capped against the salary structure’s own setting, two CSV exports shipping database ids, and a sales funnel counting the wrong documents.
Fixed
HR Department Analysis ignored the Department, Business Unit, Status, Designation and Employee filters while the page stated every number was filtered by them — selecting one department showed the whole organisation, and nothing said so.
The Payroll report’s “Cost to Company” omitted holiday and week-off bonuses and employer labour welfare fund, all of which were actually paid. On a payroll including any of them, the cost to company printed lower than the net pay beside it.
PF was capped at the statutory wage ceiling even when the salary structure switched that cap off. The structure honours the toggle; the payslip dropped it, so the two disagreed for every employee earning above the ceiling under an uncapped policy. A missing toggle is now rejected as a misconfigured policy rather than guessed.
The Employees CSV export wrote the Business Unit’s database id instead of the branch name, and the Contacts CSV export did the same for the linked company — 24-character identifiers in files people open in a spreadsheet.
The Benefits list never loaded employee names, so its Employee column showed a database id.
Team Workspace “Present Today” counted half-day, holiday and week-off rows as fully present — on a public holiday a manager saw full attendance. Those are now counted separately, and an unrecognised status is counted nowhere rather than as present.
The Quote-to-Cash funnel’s “Dispatched” stage looked for two delivery-challan statuses that do not exist, so it always fell back to counting every challan including drafts and cancellations. Its “Paid” stage counted proforma advance receipts rather than tax-invoice collections — a different document on a different path, which could exceed the stages above it.
Verified
HR 673/673 including a new case proving the PF ceiling toggle reaches the payslip, CRM 733/733, platform 8423/8423 — fully green.
Version 1.1.41
Deal figures and company names that stopped at 200 records
The Deals cards contradicted the Total beside them, and Deals and Contacts showed a dash for any company outside the first 200.
Fixed
The Deals screen’s Open, Won and Open Pipeline Value cards were computed from the 300 rows already fetched for the pipeline board, while Total Deals used the real count — so the four cards contradicted each other as soon as the pipeline outgrew that page, and the money figure was the one that quietly went missing. All four now come from one server aggregate over the whole pipeline, scoped to the viewer the same way their list is.
Deals and Contacts resolved each row’s company and contact name against a separate 200-record fetch, so anything outside it rendered a dash — indistinguishable from a record with no company at all. The list now returns the linked names with the rows.
Both edit forms still submit a plain reference, so opening a record for editing keeps its company selected rather than blanking the picker.
Verified
New CRM list contract suite 4/4, CRM 733/733, platform 8427/8427 — fully green. TypeScript and build clean.
Version 1.1.42
HR screens that mistook a page of records for the records
A leave tab that told you an employee had no leave, an attendance register with no names past employee 200, a monthly card that under-counted, and a register showing 100 of 340 employees with no way to see the rest.
Fixed
Employee 360’s Leave tab read “No leave requests yet” for anyone whose requests fell outside the newest 200 in the company. It fetched the company’s recent leave and filtered it on screen, so a statement about company volume was presented as a fact about the person. It now asks for that employee’s leave.
The attendance register showed a dash instead of a name from employee 201 onward, because names were matched against a separate 200-employee fetch. Each row now carries its own employee.
“Approved This Month” counted approvals within the 200 most recent approved requests, so past that point it could only under-count — silently, while reading like a fact about the month. It is now counted by the database over the month itself.
The HR Employee Register rendered 100 rows, printed the true total underneath and offered no way to reach row 101 — which reads as “here are all 340 employees” while showing 100. It now says how many of how many, and pages.
Verified
New HR list contract suite 5/5, HR 673/673, platform 8431/8432 (the one failure is an unrelated timing-sensitive test). TypeScript and build clean.
Version 1.1.43
Compliance tiles stuck at zero, and other figures that misread themselves
Every e-invoice tile read a field that does not exist, expired e-way bills were counted in the wrong 100 rows, the leakage KPI counted resolved cases, appointment lists showed the oldest entries ever, and a failed audit-log fetch read as “nothing happened”.
Fixed
Every e-invoice tile on the Compliance dashboard sat permanently at zero. It read a top-level field that does not exist — the real status is nested — and fell through to the invoice’s own status instead. Counts now come from the server, over every candidate rather than the first hundred rows.
“Expired E-Way Bills” was counted within the 100 most recent bills. Sorted newest first, those are the least likely to have expired, so the tile under-reported almost by construction. It is now counted over every bill.
“Open leakage” counted cases of every status, including resolved and dismissed ones, and stopped rising at 500 however many there were. It now counts open cases, uncapped.
Appointments and Scheduled Demos listed the oldest scheduled activities ever recorded, so with any real history no upcoming appointment appeared — a schedule that was in effect an archive. With no date filter they now start from today.
A failed audit-log fetch on Closing & Audit Log rendered “No audit entries found” — a statement that nothing happened, on the one screen whose purpose is to evidence that something did. It now says the load failed.
CRM Quotation detail rounded every amount to whole rupees, printing a real balance due of ₹0.40 as ₹0 — paid in full, on a screen customers are shown.
The Leads CSV export wrote the owner’s database id in the Owner column instead of their name.
Verified
New contract suite 5/5, CRM 733/733, platform 8437/8437 — fully green. TypeScript and build clean.
Version 1.1.44
A reconciliation that said no match existed, and controls that failed in silence
Bank reconciliation reported that no journal line matched an amount whenever the entry was an old one, and four controls sat empty and unusable without saying why.
Fixed
Bank reconciliation searched the 200 most recent unreconciled journals and only then compared amounts, so if the matching entry was older it reported “No unreconciled journal lines match this amount” — a statement that the entry does not exist, about one that does. The amount is now part of the query, so the limit applies to entries that actually match. The line conditions also bind to the same journal line, which they previously did not.
The Approval Inbox printed 24-character database ids for “Requested by” and “Current step” whenever the viewer could not read the employee directory — and for anyone past the 200th employee, because the directory was only ever fetched one page deep. It now pages, and an unresolved reference reads as text saying which situation it is.
The tax-invoice “New invoice from SO” picker discarded every load failure, leaving Create draft disabled behind an empty list with no reason shown. A permission failure now says so.
“Record receipt” could offer no bank account and no explanation, leaving a form that could never be submitted. It now says whether no receipt account is configured or the lookup failed.
The estimate form’s Customer field is required by the save but its label never said so, and an empty picker gave no hint whether the lookup had failed or no company exists. Both are now stated.
Verified
New contract suite 4/4; platform 8441/8441 — fully green. TypeScript and build clean.
Version 1.1.45
An unpostable invoice says so while you are still drafting it
A tax invoice whose place of supply cannot be determined is refused at posting. It now warns on the draft instead, naming the two records to fix.
Changed
A draft tax invoice carrying tax whose CGST/SGST vs IGST split cannot be decided now shows a warning on the draft itself, naming the business unit and the customer account as the records to fix. The refusal at posting is unchanged and correct — charging a guessed tax is worse than refusing — but discovering it only when Post is pressed meant building the whole invoice first. The draft has carried this information since the split began running on every draft write; it simply was not shown.
Note
Setting a GSTIN or state on the Head Office business unit is a one-field configuration step, and is required before any taxed invoice can be posted.
Version 1.1.46
A tax cliff, two permissions nobody could hold, and a tile with no source
Earning ₹600 more could cost ₹62,493 in tax; two agreement features were unreachable because their permissions were never declared; and a dispatch tile reported zero when it had nothing to measure.
Fixed
Income tax had a cliff at the Section 87A rebate threshold: crossing it by ₹600 attracted the full slab tax of ₹62,493, leaving the employee materially worse off for earning more and putting ₹5,208 a month on their payslip. Statutory marginal relief now caps the tax at the income earned above the threshold. It applies on both the governed slab path and the built-in fallback, and can only ever reduce tax.
The usage-evidence table and “Attest usage” action on a Commercial Agreement were unreachable for everyone except a full module administrator, because the two permissions their routes require were never declared in the permission catalogue and so were never created. Both now exist and are assignable; the commercial-ops manager role that owns period attestations picks them up.
“Ready to Dispatch” reported 0 on any installation not running the fulfilment-planning engine — the only thing that ever sets the field it counts — so it stated a fact it had no source for. It now reads “Not tracked” in that case, and explains why. A genuine zero under a running engine still shows 0.
Note
Marginal relief is applied to income tax before cess, which is the standard computation. Net pay therefore still dips by the cess on the marginal income — about 4% of it — rather than by the whole slab tax. Capping the tax inclusive of cess would remove even that, but would withhold less than the usual treatment, so it is not done without a ruling.
Verified
New statutory contract suite 9/9 including the exact case from the audit, HR 673/673, platform 8451/8451 — fully green.
Version 1.1.47
Three caps a cross-check caught
A reconciliation table that stopped at 200 lines, an account picker that lost everything past the first 200, and a vendor form still showing blank boxes for fields it cannot read.
Fixed
The bank reconciliation table rendered the first 200 statement lines and stopped, while the summary tiles above it counted every one — so on a larger statement the totals described a set the table could not show, and those lines could not be reconciled at all. It now pages and states how many of how many.
The journal entry’s account picker loaded only the first 200 accounts, which is also the server’s maximum page, so a larger chart of accounts silently lost its tail: those accounts could not be posted to, and an existing line referencing one showed a database id instead of a name. Every page is loaded now.
The vendor form showed empty Tax and Bank boxes to roles that cannot read those fields, which reads as “this vendor has no GSTIN” when it has one. Those roles now see a short note instead, confirming that values already on file are preserved when they save.
Verified
New contract suite 3/3; platform 8454/8454 — fully green. TypeScript and build clean.
Version 1.1.49
Proforma invoice rebuilt, employee documents become a list, three modules move
The Proforma Invoice now prints like the Tax Invoice instead of a basic layout, and a discount bug in its figures is fixed. Employee documents are a list you add to, with a type, number, issue and expiry date and attachments per document. Compliance now sits under Accounts, Developer Tasks under SaaS Commercial, and Role Dashboards under HRMS.
Fixed
Proforma Invoice: the printed taxable value ignored line-item discounts. It read the gross line total minus the header discount, so on any quotation with a line discount the subtotal was overstated by exactly the line-discount total and disagreed with the grand total printed beside it.
Proforma Invoice: the tax split was assumed rather than resolved. Where either GSTIN was missing the document printed no tax at all while still charging it; the place of supply is now resolved from the customer GSTIN or, failing that, their address state, and a genuinely undeterminable one prints a single GST column and says so rather than asserting a split nobody established.
Proforma Invoice: no logo, no CIN or registration line, and no authorised signatory, because the document read company details from a settings field that no longer exists. It now uses the same business-unit and legal-entity letterhead every other document does.
Changed
Proforma Invoice: rebuilt to match the Professional GST Tax Invoice — letterhead, Bill To and Ship To with place of supply, an item table whose tax columns follow the supply type, a GST summary by HSN or SAC, an ordered totals panel, amount in words, receiving-bank details, payment status against the amount received, commercial terms and an authorised signatory, with a footer that repeats the non-tax-invoice statement and the document number on every page.
Employee documents: a list you add to. Each row records the type of document, its number, issue date, expiry date where the type expires, and its attachments — so two education certificates or three other documents can be filed separately. Aadhaar Card and PAN Card are unchanged, keeping their fixed front and back upload slots with no detail capture.
Navigation: Compliance moved under Accounts, Developer Tasks under SaaS Commercial, and Role Dashboards under HRMS. Every destination stays reachable and keeps the exact permission it had; a compliance-only, approvals-only or dashboards-only user still opens the section their work is in and sees nothing more.
Version 1.1.50
Organization chart rebuilt as a real hierarchy
The organization chart is a top-down tree instead of an indented list, with a focus view for one person and their reporting line. Search, zoom and Fit to screen actually work, the chart is navigable by keyboard, and the same chart reads as an outline on a phone.
Changed
Organization chart: rebuilt to the approved Classic hierarchy concept — a top-down tree with connectors drawn to each card, replacing the indented list. Cards match the employee directory: photo, name, designation, employee code, status and direct-report count, with initials where a photo is missing or unreadable.
Organization chart: selecting a person opens the Focus view — their manager, themselves and their direct reports, beside a panel with their code, department, resolved manager and report count, and a link to their full profile. The manager section is omitted for someone at the top rather than shown empty. Returning to the full chart restores the position and zoom it was left at.
Organization chart: the toolbar controls all do something. Search reveals a match and opens its reporting line rather than filtering people out of the chart, and says plainly when nobody matches. Zoom is bounded and shows its level, and Fit to screen measures the chart against the window.
Organization chart: the chart and the phone-friendly outline are the same content, restyled — so an employee is never listed twice for a screen reader, and the two cannot drift apart.
Fixed
Organization chart: the chart claimed to be a navigable tree but had no keyboard handling at all, so every node was reachable only by tabbing through the whole organization. Arrow keys now move between people, expand and collapse, and Enter opens someone.
Organization chart: the spoken description of each person replaced their own card contents, which silently hid their employment status and any reporting-line problem from screen readers.
Organization chart: an employee recorded as their own reporting manager was reported as a generic reporting cycle. It now says exactly that, because it is a single-record correction rather than a puzzle.
Organization chart: the keyboard focus outline was drawn around a manager entire team instead of the person focused.
Organization chart: connector lines were drawn a few pixels to the left of the cards they pointed at, and the clear-search button was below the minimum touch size.
Verified
The reporting-line logic moved into its own module so it could be tested for real rather than by reading the source: multiple tops, managers recorded as text or as a linked record, missing managers, self-references, reporting cycles, a sixty-deep chain, and direct-report counts.
Frontend suites 1,432 checks; production build, type checking and interface governance clean; no sideways scrolling and no undersized controls at desktop, tablet and phone widths in both light and dark.
Version 1.1.51
Employee cards show the real role, and stop wasting a third of themselves
Every employee card in the directory was labelled "Support" regardless of the roles actually assigned. Cards also carried a large empty gap, could shear a long name with no way to read it, and could show a deputation that had already ended.
Fixed
Employee directory: the Role on every card read "Support", whatever roles the employee actually held — including people with no login at all, whose own Login row on the same card said "None". The directory was not loading the assigned role names, so the card fell back to a coarse account setting that is "support" for everyone by default. Real role names are loaded now, and where a role genuinely cannot be resolved the card says so instead of inventing one.
Employee directory: a long name or job title could be cut off on the front of a card with no way to read the rest. Both now wrap, and the identity area gives way rather than pushing View profile and Details off the card.
Employee directory: a card could keep showing "Deputed to …" after the deputation had ended, while the table row for the same person showed nothing. Both now agree.
Employee directory: every card carried about 90px of empty space between the status badge and its buttons. The card is shorter by that much, with nothing lost.
Verified
A new backend check drives the real directory endpoint to prove role names arrive resolved, and pins the account setting as a last resort rather than a stand-in for a role.
The check protecting the rule that flipping a card is not a permission boundary was rewritten: it could previously pass with contact details sitting outside the permission gate. It now fails on exactly that.
Card geometry measured at desktop, tablet and phone widths against the real application chrome: four columns, two, then one; the card cannot change size when flipped; the loading placeholder matches it exactly; no sideways scrolling and no undersized controls.
Version 1.1.52
Experience totals that are true, bank details that can pay someone, addresses that agree
An employee with a blank end date on an old job was credited with every year since — one 2015 row alone read as eleven years and eight months, under a heading that called it verified. The employee record also accepted anything at all as an IFSC code, held too few bank fields to produce a bank transfer, and recorded country, state and city as free text. The organization chart used about a sixth of the screen it was given.
Fixed
Employee record: total experience was wrong in six of eight cases checked. A previous job left without an end date was counted as still running to today — a row starting in 2015 added eleven years and eight months that nobody worked. A job recorded as ending in 2032 was counted in full. Working from 31 January to 1 February counted as a whole month, and a single leap day counted as a month. A job whose end date was before its start was dropped from the total with no trace. All of these are corrected.
Employee record: the figure labelled "Verified total including current tenure" counted every dated job whatever its verification status. Verified experience is now its own separate figure, computed only from jobs actually marked verified, and the combined total is called what it is.
Employee record: jobs that cannot be counted are now listed with the reason — no end date, end before start, start in the future — instead of quietly lowering the total. A blank end date is treated as unknown, not as ongoing; where someone genuinely still works there, a new "Still working here" tick states it.
Employee record: saving the form discarded the internal identifiers on each previous-employment row, so documents attached to a particular employer lost track of which employer that was. The identifiers now survive a save.
Employee record: the Bank IFSC code field accepted any eleven characters — "abcdefghijk" and "1" both saved onto the account a salary is paid into. It is now checked against the real IFSC format, the same rule the company’s own bank accounts have always been held to. The candidate self-service onboarding form, which was the loosest of all at fifteen characters, is held to the same rule.
Organization chart: the chart sat in a short box with the rest of the window empty below it, and could not grow past about two thirds of the screen however much room there was. It now fills the space available — measured at 184px before and 813px after on a 1176px-tall window. On a short window it keeps a usable minimum and the page scrolls instead.
Employee record: country, state and city on both the permanent and communication addresses were free-text boxes, so "Punjab", "punjab", "PB" and "Panjab" were four different states and nothing could group or report on where people are. All three now come from the same governed location list the CRM Lead form uses.
Added
Employee record: a Look up button beside the IFSC code fills the bank, branch, branch address and MICR code from the public bank directory, so they no longer have to be typed. The screen states plainly that this confirms the branch only — it does not check the account number.
Employee record: the disbursement account gained the fields a bank transfer actually needs — account holder name exactly as the bank has it, account type (savings or current), branch, branch address, MICR code and UPI ID. The account holder name is asked for separately and never guessed from the employee’s own name, because a bank matches on the name it holds.
Every one of the new bank fields is recorded in the employee’s change history and carries the same restriction as the account number, so none of them can be read by someone not entitled to see bank details.
Employee record: the experience figures shown while editing now follow exactly the same rules as the ones stored on the record, so the preview and the saved value cannot disagree. Contradictory rows — marked ongoing and given an end date, or an end date before the start — are refused by the server as well as the form.
Verified
The experience calculation was measured against the shipped version first, case by case, so every claim above is a number rather than an assertion. Twenty-three new checks cover month boundaries, leap days, overlapping jobs, gaps between jobs, unknown and future dates, and the verified subset.
The IFSC rule now exists once and is shared. A check proves the copy the browser uses and the copy the server enforces are character-for-character identical, so they cannot drift into disagreeing about what an IFSC is.
Chart height measured against a reproduction of the real application chrome at three window sizes, including a short window where the page is expected to scroll rather than the chart to be crushed.
Thirteen new backend checks and twenty new frontend checks. Every new safeguard was deliberately broken to confirm it fails — including one that caught a new check quietly registering nothing while still reporting success.
Version 1.1.53
Bank details are restricted to the people entitled to see them
Anyone who could open the employee directory received every employee’s bank account number and IFSC in full. Worse, a reporting manager approving a subordinate’s leave request, expense claim or resignation received that subordinate’s account number in the approval response — without holding any employee permission at all, and without being able to open the directory. Bank details now require a dedicated permission.
Fixed
Employee bank details — account number, IFSC, bank, branch, branch address, MICR, account type, account holder name and UPI ID — are no longer returned to everyone who can read an employee. They now need the dedicated "View bank and tax details" permission, the same restriction a supplier’s bank details have always had.
The more serious case: eleven approval and decision screens returned the employee’s whole record alongside the decision, bank details included. Seven of them require no employee permission at all — a reporting manager reaches them through the reporting line. So approving a subordinate’s leave, expense claim, regularization, move-out or resignation handed over their bank account number. All eleven are now restricted.
The onboarding checklist keeps its own copy of what a candidate submitted, including their bank details, and it is read under a different permission. Completing a single onboarding task on a subordinate returned that copy. It is now restricted the same way.
Changed
The Salary A/C Details section of the employee form is hidden from anyone without the permission, and says so plainly instead of appearing empty. Showing empty boxes that accept typing and then quietly discard it would be worse than saying no.
An edit made by someone without the permission can no longer clear bank details. The form sends every field on every save, so without this a manager changing a phone number would have wiped the account number — silently, and discovered on payday. Those fields are now left exactly as they were.
The IFSC Look up button needs the same permission as the fields it fills.
Verified
Twenty-two new checks cover all nine fields, list rows, records nested inside an approval response, the onboarding copy, and the rule that an edit without permission cannot clear anything.
Nine deliberate breakages confirmed each safeguard actually fails when removed — including dropping the restriction from a single one of the thirty protected routes, and moving one input outside the hidden section.
Version 1.1.54
Approval screens stop handing over the whole employee record
Approving a subordinate’s leave, expense claim or resignation returned that person’s entire employee record in the response — salary, PAN, Aadhaar, personal email and home address included. The previous release restricted the bank details on these screens; this removes everything else that was never needed there.
Fixed
Fourteen approval and decision actions returned the employee’s complete record alongside the decision. Seven of them need no employee permission at all — a reporting manager reaches them through the reporting line — so approving a subordinate’s leave request, expense claim, attendance regularization, late check-in, move-out or resignation disclosed their salary, PAN, Aadhaar, personal email address and home address. Each now returns only the identifying details the screen actually shows: employee code, name, and where relevant department, designation and status.
Release 1.1.53 restricted the bank details on these same screens. That closed the field that had been reported; this closes the rest of what was riding along with it.
Verified
Established before changing anything that nothing depends on the removed fields: internally these actions read only the employee’s id, code, name and reporting manager, and where real work needs the full record it already loads it separately. On screen, every one of these actions either ignores the response and reloads the list or reads a field that is not part of the employee.
Each action now returns exactly what the matching view screen already returns for the same record, so nothing on screen can be reading a field it no longer receives.
Six new checks, and five deliberate breakages to confirm they fail — including one that caught a check which would have missed a genuine regression, and which was rewritten before this shipped.
Version 1.1.55
The onboarding link is treated as the credential it is
The link emailed to a new joiner is a password in all but name — anyone holding it can submit that person’s PAN, Aadhaar and bank details, with no sign-in. It was stored in readable form and travelled back inside ordinary onboarding responses, including one screen action that needs no permission at all. It is now stored scrambled and never sent anywhere.
Fixed
The onboarding self-fill link was stored in readable form and included in onboarding responses — among them completing a single checklist task, which any reporting manager can do for their own team member without holding an onboarding permission. Anyone who saw one of those responses held a working link to submit that candidate’s KYC and bank details. The link is now stored scrambled, cannot be read back by anyone, and is never included in a response.
The link is now shown exactly once, in the email it is sent in — the same place it always went. Nothing else can retrieve it, including the system itself.
Changed
Links already emailed to candidates keep working. Nobody needs to be chased for a resend.
Sending a fresh link now properly cancels the previous one. It did not before, which was found while testing this change rather than assumed.
Verified
Fifteen new checks, including that a link already in a candidate’s inbox still opens, that re-sending genuinely invalidates the old link, and that the stored value can never be turned back into a working link.
Seven deliberate breakages confirmed each safeguard fails when removed — including one that caught a gap in this change while it was being written, and another that caught a check which was not testing what its name claimed.
Version 1.1.56
Housekeeping: a database update was numbered the same as another team’s
No change to how anything behaves. The pending database update shipped in the previous release carried the same sequence number as one another workstream had already prepared, which would have stopped both from running. Renumbered before either was applied.
Changed
The database update that accompanies the onboarding-link change was renumbered so it no longer clashes with an update prepared elsewhere. Nothing had run yet, so there is nothing to undo and no effect on any record.
Version 1.1.30
Letterhead, logo and fonts on every generated document
Generated documents could never show the company logo, never applied their fonts and carried no letterhead at all. All three are fixed, and the GST Tax Invoice, Sales Order and Payment Receipt were rebuilt against their reference designs.
Fixed
The logo could never appear on any generated document. Branding stores it as an asset path the renderer has no base URL to resolve, and the obvious fix — inlining it — was silently rejected by the renderer’s URL guard. Both halves are fixed, and the API now carries its own copy of the brand wordmarks so the default resolves wherever the web root is deployed.
The fonts never applied, for two independent reasons: the stack led with typefaces the Linux render host does not have, and design-token values were HTML-escaped into a style block, where character references are literal text — so the declaration was discarded outright.
Documents were printing with no company letterhead at all. Eight controllers built their company information from a settings field that was removed some time ago, so the lookup returned an empty object every time. The letterhead now comes from the document’s Business Unit and Legal Entity, which also supply the CIN and the authorised signatory.
Changed
Professional GST Tax Invoice and Compact Sales Order rebuilt against their reference designs — logo and full letterhead, per-column alignment and widths, a TOTAL row summed from exactly the lines above it, the HSN-wise GST summary, Bill To / Ship To panels, bank and declaration blocks and the signatory panel.
Nothing was invented to fill those references. There is no website field anywhere in the schema, so that line is absent; a sales order has no currency field, so the reference’s Currency line is not printed rather than filled with a constant.
The Payment Receipt has an adapter at last — the format shipped with a complete data contract and no code to build its data. Only a genuinely posted journal entry reads as Settled. The instrument reference and bank account number are masked, and anything under eight characters is withheld entirely rather than “masked” into disclosing most of itself.
A governed way to get a format change onto an environment that has already booted. The catalog seed is insert-only by design, so editing a format had no effect anywhere that had started once; republishing now runs the same fork, preflight and publish flow the Studio uses, and a definition that fails preflight is refused rather than shipped.
Verified
Report Format Engine suite green: 408 tests, including new coverage for the logo fix and for the inline URLs that must still be refused.
Existing formats render byte-identically — the new ruled totals and header-band styling are opt-in per format.
Version 1.1.31
Uploads survive a deploy
Every deploy had been silently deleting every uploaded file. Uploads now live outside the application tree, the restored files are back in place, and documents render with real fonts, real icons and the dark-ink logo.
Fixed
Every deploy was destroying every uploaded file. The API served /uploads from a directory inside its own tree, and each release swaps a freshly staged tree into place. Uploads now live outside the app tree and are symlinked back in on every swap; the restored files are back (7,995 on production, 5 on pilot).
An uploaded logo is read from disk, not fetched over HTTP. For an uploaded logo that URL is served by the very API doing the rendering, so the document depended on a network round trip that could 404 — and did. A genuine external URL is still left to the browser.
Reports always use the dark-ink logo. The branding variant names describe the surface, not the ink, so on white paper only the orange chevron survived.
Documents render in a proportional typeface. The render host carried two font families, one of them monospace, so every PDF printed like a typewriter whatever the format asked for.
Icons are inline SVG. The glyphs used before have no coverage in the fonts that host carries, so they printed as empty boxes sized by font metrics rather than by the document.
Changed
Names are cased for print — a contact saved as “subhash malik” reached a customer exactly like that. Applied to names only: a word already containing a capital is left alone, so product codes and initialisms survive untouched.
The estimate’s itemised discount is a column, showing the percent entered with the amount beneath, rather than a note tucked under the item name.
The build stamp reads in 12-hour IST with AM/PM, and the product version increments per publish.
Version 1.1.32
Settings for five modules, and Email Templates where you would look for them
Sales, Purchase, Assets, Compliance and Order Fulfilment had no settings group at all, so their email templates and document formats were reachable only by someone who already knew the URL. Each has one now, and the 196-template email catalogue is in Application Settings.
Added
Sales, Purchase, Assets, Compliance and Order Fulfilment each have a footer-pinned Module Settings group carrying that module’s own Email Templates and, where the format catalogue actually holds one, Report Templates — 33 Sales templates and 10 formats, 19 Purchase and 4, 5 Fulfilment and 1, 5 Assets & Fleet, 2 Compliance. Each link is gated on the permission its destination requires, so a shortcut is never a dead link.
Email Templates is in Application Settings. The 196-template catalogue had no entry there at all — “Transactional Email” is the SMTP relay, not the messages. It spans 26 modules, so it now has a platform route to match; the old accounts route still works.
Sales, Purchase and Order Fulfilment appear in the Business Module Settings directory, which previously could not answer “where do I configure Sales?” for the three modules whose documents customers and suppliers actually receive.
Fixed
Seven of the thirteen live report document types were invisible in the Studio. Its picker named one key wrongly and omitted six others outright, so the entire Purchase document set could not be filtered for and rendered with its raw key as a label. A contract test now pins the picker and the catalogue to each other in both directions.
Nine email templates had no module, and the API filed them under a bucket no template actually declared. They now declare Sales, Payments and Marketing, and the fallback says “Unclassified” rather than inventing a home for a template whose key has left the catalogue.
Changed
Approvals and IT & Infrastructure now live inside Developer Tasks — two fewer top-level sidebar apps, with every item keeping the exact gate it carried as its own app. The group-level developer permission moved onto the individual items, so the infrastructure team’s own settings are not hidden behind a developer key.
Version 1.1.33
One document engine, and the pendency it was hiding
Estimates and quotations could resolve three different renderers, which is why format changes kept appearing to be skipped. There is exactly one now, and the HR, CRM and ledger defects that had been sitting behind it are fixed.
Changed
A document now has exactly one renderer. Which of the three won depended on what happened to be published, with nothing on screen saying — so a change could land in an engine the document never reached. Every other document type had already been cut over; estimates and quotations had not. When no governed format is published the download now refuses and says so, rather than silently printing a different layout.
Fixed
The Executive Estimate splits tax the way its reference does — CGST/SGST, or IGST — determined from the seller’s and the customer’s GSTIN state codes. A missing or malformed GSTIN keeps the single Tax line rather than guessing, and the rate is named only when every taxed line shares one. The footer also numbers pages properly instead of printing “Page 1” on every page.
Issued documents recorded an undefined template version, so a PDF could not name the revision that produced it.
Collapsing a manager on the organization chart accused their whole team of broken data — one traversal both marked nodes visited and stopped at a collapsed manager, so the “find cycles and disconnected records” pass swept up every hidden report and re-listed them at the top as hierarchy errors. Reachability is computed over the whole graph now; only rendering knows about collapse.
Two screens silently truncated the organisation at 500 employees — the employee directory’s Reporting Manager picker and the org chart. Anyone reporting to employee 501 or beyond read “Not available”, indistinguishable from a broken reference. Both page to the end, and an incomplete fetch says so instead of blaming the data.
The employee card printed a raw database id as the role. An unpopulated reference serialises to a string, so the “it is already a slug” branch took it.
Employee salary is labelled “Legacy monthly salary” and states that an approved Salary Revision is what payroll pays — which the backend has enforced for some time, while the screen still presented the old number as authoritative.
Employee 360’s Expenses tab said there was no Expense entity. There is; the tab lists that employee’s claims, behind a per-employee filter so the screen does not fetch every claim in the organisation.
Digital Employee ID download and print work. The badge code is derived rather than stored, so a card re-renders identically without keeping a recoverable token at rest, and a five-minute on-screen QR was added for gate and reception verification.
“My Day” led only to “My Day is unavailable” — its projection is pre-seeded disabled and checked fail-closed. The link is gated on that flag and appears when it is enabled.
Thirteen sidebar entries had icons that do not exist, including Experience Letters and every Command Center, so they rendered as blank space.
Overlapping controls in the document template editor: the style-swap button and the structure-locked badge both positioned themselves at the same corner, so the badge covered the button.
The ledger’s base-currency conversion assumed a scale of 2 — right for INR and USD, wrong by a factor of a hundred for a zero-decimal currency. It reads the currency’s own scale now.
The AI-summary thumbs-up and thumbs-down on Customer 360 and Lead detail wrote to the browser console, or nothing at all. There is no feedback store, so the control is off rather than pretending to record an opinion.
Version 1.1.34
The release note catches up with the version number
Six releases shipped with the version number updating and nothing written down behind it. The missing entries are here, 26 test fixtures that had been shipping as release notes are gone, and a version with no release note can no longer be built.
Fixed
Six releases shipped with no release note. The build copies the product version into the footer, the account menu and this screen, so all three always named the running version — and nothing checked whether anyone had written down what that version changed. 1.1.28 through 1.1.33 shipped while this history still ended at 1.1.27. Those six entries are written below.
26 test fixtures were shipping as release notes. This history is a tracked file the release tooling writes to, and before the test suite was isolated from it, it published fixtures straight into it — rows titled “RM-8 test release” and “RM-3 gate test release” at versions 7.x through 10.x, each with an empty body. They are gone.
Changed
A version with no release note now fails the build. A reminder would have been forgotten the same way the last six were, so the check sits on the script that stamps the version itself and names the changelog headings to source the content from. Running the app locally only warns — a developer working on their own machine has not shipped anything. The same check rejects a duplicate version, a malformed date, an empty entry and the test-fixture shape.
Version 1.1.28
Recovered settings screens and the Delivery Challan download
Seven configuration screens that could only be opened by typing their URL are back in the sidebar, the Delivery Challan can be downloaded at last, and line endings are decided by the repository rather than by each developer’s machine.
Added
Seven settings screens recovered from URL-only access — Report Customizer, Report Formats, Document Block Templates, the Block Palette, Email Block Templates, CRM Integration Governance and platform Operations. Each had a working route, a component and a permission, and no sidebar entry at all.
CRM message templates moved into Module Settings, alongside the rest of that module’s configuration rather than under Communications. A move, not a copy — a second entry to one screen is the duplicate-destination pattern that was removed earlier.
Delivery Challan PDF download — the only Sales document with no download path at all. The document states quantities and no pricing, and every field the model cannot supply stays absent rather than blank.
Fixed
Line endings were decided per developer rather than by the repository, so any test comparing file content passed on CI and failed on Windows for a reason that had nothing to do with the code under test.
Verified
Frontend suite green: 145 spec bundles, 1,060 specs.
Delivery Challan report-format adapter: 13 focused tests, with adjacent document suites green (35 tests).
Navigation gates within limits — reachable destinations 348 → 354, visible menu depth still 2, dead-route audit clean.
Version 1.1.29
Superseded document editors kept out of navigation
Four replaced document editors that the previous release listed in the sidebar are retired again — they stay reachable by URL, as their retirement plan requires — and Report Formats moved beside the Studio it belongs with.
Fixed
Four superseded document editors removed from navigation again — Report Customizer, Document Block Templates, the Block Palette and Email Block Templates. Their absence was deliberate, not an oversight: they are the two legacy families the Report Format Studio replaces, and listing them again steered users toward the engine being phased out.
No route, component, permission or endpoint changed. All four stay reachable by URL and by deep link, which their retirement plan requires.
Changed
Report Formats — the one screen of the five that is genuinely current — now sits in the existing Documents & developer group beside Document Template Studio, rather than alone in a group of one.
Verified
A guard test pins the four retired destinations out of navigation and Report Formats in. The mistake is recurrent by construction: any sweep that reads “routed but unlisted” as a defect will rediscover these four, so the reason they are absent is now recorded where that sweep will find it.
Version 1.1.27
Field-level validation messages and restored regression gates
Every validated field now names its own problem instead of relying on a form-level banner, two Save buttons that blocked silently are fixed, and the automated test suites that had been skipped rather than passing are running again.
Fixed
Regional Defaults: Default country and Default phone country code blocked Save while showing no message at all.
Added the missing error text to 64 validated fields across HR Salary Structure (authority, engine, policy packs, statutory masters), CMS Media Library, CMS Navigation, Location Management, Sales Invoices and Regional Defaults. Each field now states its own problem instead of a banner listing field names in prose.
Assets: Fleet menu items shared hide-keys with Asset menu items, so hiding Asset Register also hid Fleet Tracker, and hiding Asset Maintenance also hid Vehicles.
Industry Packs, in both Product Engine and Work Management: the page heading rendered twice while creating a pack.
Estimation & Quotation commercial dashboard: the tab read "Approval Requests" while the page it opens calls itself "Approval Inbox".
Marketing website: a duplicate export stopped all three sites building, and every CMS media block would have failed to render.
Quality and verification
The four backend test suites had been reported as skipped rather than passing: they depend on a static-analysis job that was failing on both this branch and main, so CI never ran them. Repairing that job ran them for the first time and surfaced 90 failures, all now fixed.
Roughly half were real defects rather than out-of-date tests, including sales-order pages that would fail to load whenever their controller was the first thing loaded, and a lead-routing lease that was validated against a different clock than the one that granted it.
The website build gate now checks the page count the build itself reports, so it no longer demands a shape that publication gating is designed not to produce.
Version 1.1.26
Guided access setup and professional report review
Simplifies RBAC role authoring, brands password recovery and exposes the next six professional accounting formats for governed Studio review.
Added
Added guided module, access-breadth and role-template controls with an effective-access preview and advanced matrix fallback.
Made custom non-CRUD actions such as approve, publish, post and issue visible in the canonical permission matrix.
Added realistic draft previews for Payment Receipt, Purchase Order, Goods Receipt Note, Delivery Challan, GST Debit Note and Internal Vendor Bill Approval Sheet.
Added Payment Receipt PDF download to the Sales Receipts list.
Security and communication
Moved password-reset email onto the enterprise branded shell with a Reset password button and single-use expiry notice.
Reset destinations now come only from the installation-configured frontend origin, never a caller-supplied redirect base.
Guided access presets do not bypass ownership, reporting-hierarchy, business-unit, record-state or feature-flag checks.
Version 1.1.25
Professional report rendering and designer typography
Makes URE previews and PDFs render as print-ready documents and exposes safe typography and image-size controls in Report Format Studio.
Fixed
Applied one shared print stylesheet to preview and PDF output for headers, footers, tables, totals, signatures, images and pagination.
Added direct document font, body-size, table-size and maximum-image-height controls to Report Format Studio.
Certified invoice and credit-note mappings against the live URE adapters instead of the removed legacy adapter utility.
Added professional typography and density defaults to the six bootstrapped URE catalogue formats.
Quality gates
All 368 report-format kernel, format, safeguard, adapter and PDF-pipeline tests pass.
Visual references remain composition and design-intent baselines; record data continues to come only from certified adapters and Pilot fixtures.
Version 1.1.24
Phase 1 UI and backend route reconciliation
Restores completed non-reserved Phase 1 applications to Pilot, aligns the GST feature flag and clears the remaining dead-route and mechanical UI-governance findings.
Recovered
Exposed Assets/Fleet, Library, Projects, Work Management, Fulfilment, Training, Estimation & Quotation, Inventory and Infrastructure in Pilot.
Kept Product Engine, Design Engine and Manufacturing outside this release under their separate ownership and rollout gates.
Aligned GST Verification navigation with the canonical backend feature-flag key.
Repointed Commercial and Work Management dashboard actions to declared, usable application routes.
Quality gates
Dead-route audit now reports zero unresolved links and has no grandfathered baseline exceptions.
UI-governance audit now reports zero blockers and zero warnings.
Page-header audit now passes all enforceable checks.
Version 1.1.23
Live Work Inbox unread count
Keeps the shared desktop and mobile Work Inbox badges synchronized with the employee notification source for every role.
Fixed
Refreshes the employee-scoped Work Inbox count every 15 seconds instead of only once at shell startup for non-approval roles.
Uses the same inbox response for desktop and mobile badges, avoiding conflicting approval-only rendering paths.
Stops the polling subscription when the Platform shell is destroyed.
Version 1.1.22
International phone capture completion
Completes country-aware phone capture in every discovered in-scope flow and makes the default-country configuration visible in Platform Settings.
Fixed
Replaced raw Lead, mobile CRM and Partner Portal phone fields with the shared country-prefix control.
Phone values are normalized to E.164 using the selected country while preserving existing legacy values for editing.
Added a complete libphonenumber country fallback so public Careers, Onboarding and Partner forms remain usable when the protected Location Authority API is unavailable.
Added Regional Defaults to Platform Settings navigation for default country and default phone-country management.
Boundary and verification
Manufacturing-owned phone fields were not changed because that module remains in its separately owned lane.
A frontend contract pins E.164 handling, fallback-country availability and adoption in Lead, mobile CRM and Partner capture.
Version 1.1.21
Recovered navigation, employee cards and branding verification
Restores visible Phase 1 UI integrations that were present in completed branches but lost or masked in the combined Pilot candidate, with explicit residual ownership boundaries.
Recovered
Restored bottom-pinned Module Settings groups and their original routes for CRM, Marketing, HRMS, Accounts, Support, Projects and Work Management.
Restored Platform Settings and Integrations as peer navigation applications while keeping Application Settings focused on Setup Center readiness.
Added the requested employee directory flip-card interaction: identity, organization and reporting summary remain on the front; email, phone and login are on the reverse face.
Retained the previously completed employee accordion form, Quick Capture first step and structured prior-employment table in the integrated source.
Verified
Claude's shared-topbar brand placement remains present across navigation modes; Pilot's configured light/dark full and compact SVG URLs respond successfully.
Theme and Branding still expose Installation Branding, Console Appearance and Brand Preview Studio through Platform Settings.
Frontend regression coverage now pins the employee flip-card reverse-face field contract.
Residual ownership and test status
Manufacturing Module Settings remains excluded from this recovery because Manufacturing is reserved to the Claude-owned lane.
The full frontend gate still reports pre-existing Manufacturing, Asset/Fleet and retired document-adapter expectations; all in-scope CRM, HRMS, Accounts, Support, Projects, Work Management and Settings ownership failures were cleared.
Pilot deployment requires a successful Angular build and human authenticated browser acceptance before production promotion.
Version 1.1.20
Resource-certified CMS and Asset recovery
Recovered completed Phase 1 Asset/Fleet and Websites/CMS work that was omitted or masked during branch reconciliation, with exact Pilot comparison evidence.
New
Restored the completed Asset and Fleet dashboards, registers, maintenance controls and governed navigation.
Restored the Resource-defined three-site CMS migration pack with 39 site-scoped noindex drafts and immutable version lineage.
CMS media permissions now use the certified least-privilege submit, review, approve and archive lifecycle.
Active lead forms enforce the required intake-field contract, and expired or revoked media rights fail closed.
Bugs resolved
Fixed branch reconciliation that dropped CMS migration lineage and unresolved internet-media publication safeguards.
Fixed the Pilot local-preview origin rejection that appeared as a Gateway Timeout during sign-in.
Verification
CMS backend contracts: 246/246 passing.
Asset and Fleet backend contracts: 49/49 passing.
Combined frontend production build succeeds; production promotion remains subject to Pilot human acceptance.
Version 1.1.19
Phase 1 reconciliation and Pilot recovery
Completed Phase 1 work from the handed-off branches is reconciled into one tested Pilot candidate, including restored HR/CRM forms, governed reports, command centers and settings.
New
Restored the completed accordion-based Lead and Employee capture experiences, previous-employment records and attendance bypass mapping.
Included the completed CRM, CMS, Compliance, Support, SaaS commercial and HR salary-authority candidates in the integrated Pilot release.
Restored CRM navigation for My Day, territories, adaptive sequences, governed agents, revenue intelligence and metadata studio, plus CMS media and navigation tools.
Improved
Unified Estimate, Sales Order and Invoice PDF actions now call the governed document download endpoints through the Sales service boundary.
Report generation includes the complete governed format catalogue and legacy-renderer retirement work.
Pilot settings, top navigation and cache/deployment safeguards are retained while completed module work is reconciled.
Bugs resolved
Fixed merge gaps that removed CMS declarations, HR Labour Welfare Fund service routes and sales-document download methods from the combined build.
Fixed the stale Pilot artifact gap that made completed CRM and HR features appear absent or disabled.
Known issues
Production promotion remains subject to Pilot acceptance; this release is for integrated human testing.
Version 1.1.18
Complete Phase 1 Pilot candidate
The committed Phase 1 application candidate is available in Pilot for integrated acceptance testing.
New
The completed CRM candidate and the remaining committed Phase 1 module work are included for integrated Pilot testing.
Improved
Pilot now runs from one committed candidate revision with a reproducible frontend build and API route graph.
Bugs resolved
Closed the deployment gap that left completed workspace changes out of the previous Pilot artifact.
Known issues
Production promotion remains subject to Pilot acceptance and deployment evidence; this release does not itself claim production certification.
Version 1.1.17
Pilot routing and browser cache recovery
Pilot now targets its isolated API consistently and safely refreshes browser application assets after deployment.
Improved
Pilot builds now use the dedicated Pilot API origin and publish a valid Angular service-worker manifest.
Bugs resolved
Corrected a deployment that directed the Pilot frontend to the production API.
Corrected browser cache rules that could retain an older application worker and stale release identity after a Pilot update.
Restored the visible application version to a monotonic release after the working branch regressed it to 1.0.1.
Version 1.0.1
Uploads, honest confirmations, and a readable build stamp
Employee photos now appear, several screens stopped claiming saves nobody made, and the build stamp says when it was built.
New
The build identifier shown on the dashboard, in the account menu and on this page is now the date and time the build was made (UTC), instead of a counter that told you nothing about which build you were looking at.
Improved
Release history is reliably newest-first, including several releases published on the same day — previously the order was arbitrary whenever dates matched.
Test entries published while the release-management tools were being built have been removed from this changelog. They were never real releases and should not have been visible here.
Bugs resolved
Employee photos uploaded successfully but never appeared. They were being written to a storage bucket that is not publicly readable; uploads now go to the correct bucket and photos display.
Seven screens showed a green “Saved successfully” or “Updated successfully” for something nobody did. The worst appeared at the exact moment the application crashed, which could tell you a save had worked when it had in fact failed. Two others reported a save while previewing a design change whose Apply button had not been pressed.
Opening this Version & changelog page announced a save.
The Document Template Studio warned that Experience Letters “will fail” without a published template. They generate correctly using the fixed legal layout; publishing a template there replaces that layout rather than enabling it.
A deployment no longer deletes the server's uploaded-files directory.
Known issues
Deleting a previously uploaded file fails. The storage account is missing delete permission; the file remains in place and nothing else is affected.
Version 1.0.0
Version visibility and release history baseline
This is the first governed changelog entry. Earlier work has not been reconstructed or assigned artificial release dates.
New
The running application version and exact build number are now visible from the application shell.
Users can open release notes inside the application without leaving their current workspace.
The product website and application use the same approved release-history record.
Improved
Version access is available from both the global footer and the account menu, without adding clutter to the main navigation.
Bugs resolved
Resolved the lack of a discoverable running-version indicator and an in-application changelog destination.
Known issues
Release history begins with this baseline; earlier changes are intentionally not reconstructed without verified release records.
Module availability snapshot
Platform status snapshot
A module-by-module summary of what's genuinely available today versus what's in beta or planned. Every line links to the module's full product page, where the same status is broken down capability by capability.