42 KiB
nigig-build — Remediation Execution Plan
Plan date: 2026-09-12
Audit baseline: e899a271c69efca0e11ae274b879378d2f26485f (main)
Scope: crates/apps/nigig-build and its project-scoped integrations with CAD, documents, spreadsheets, scheduling, invoices, and solar design
Status: Proposed; no implementation tranche below is complete
Release posture: Do not represent this as an operational construction-management system. It is a prototype shell containing three explicit primary-tab scaffolds and several global, lossy, or mathematically unsafe workspaces.
1. Executive verdict
The app has broad product ambition but no reliable project boundary. A construction app that opens CAD, spreadsheet, invoice, schedule, and solar tools without making a typed project context mandatory does not have separate projects; it has multiple views over mutable global state. That is the central defect and must be repaired before adding workflows.
The visible completeness is misleading:
- Materials, Workers, and Progress—the primary navigation for core construction work—literally tell the developer to replace the scaffold.
- Desktop does not provide a real project-selection/open lifecycle. Mobile renders only the first three projects.
- Spreadsheet, invoice, schedule, and calculator state is global rather than project-owned.
- Project-management production code concatenates local copies of modules that also exist as separately tested files. Tests can be green against code the app does not execute.
- Scheduling uses convergence loops rather than a validated DAG algorithm. One critical-path loop can fail to terminate; automatic scheduling can stop without convergence and still return success.
- Invoice data is pipe-delimited line-item text written to a
.jsonfilename. It drops invoice identity, parties, dates, terms, currency, tax, discount, shipping, and other visible metadata. Write failures are discarded while UI reports success. - Financial and engineering inputs use unrestricted
f64. NaN, infinity, negative values, rounding ambiguity, unsafe array topology, and physically incomplete solar designs are not rejected. - CI contains a large block of CAD checks aimed at a directory that no longer exists and omits the runtime targets that are broken.
The 94 passing library tests and 264 passing non-runtime integration tests are not an acceptance signal. Production/test source divergence invalidates part of that evidence, and all 97 runtime UI cases terminate with exit code 127 before exercising their assertions.
Current grade: architecture D-, data integrity D-, scheduling correctness F, financial correctness F, engineering safety F, UX completeness D, security C-, test credibility D.
2. Evidence and current baseline
2.1 Observed validation
| Check | Result | Honest interpretation |
|---|---|---|
cargo test --locked -p nigig-build --lib |
94 passed | Pure/local regression value only. |
| Non-runtime integration cases | 264 passed | Many duplicate algorithms or extracted modules instead of production wiring. |
| Runtime UI cases | 0 of 97 exercised; every case exits 127 before assertions | Harness/startup failure, not 97 product assertion failures and certainly not a pass. |
.forgejo/workflows/nigig-build.yml |
Present | Misnamed “CAD”, scans removed CAD paths, suppresses/omits meaningful broken targets. |
| Primary Materials/Workers/Progress screens | Explicit scaffolds | Core advertised workflows do not exist. |
2.2 Primary evidence locations
src/construction_frame/pages/{materials,workers,progress}.rs: identical scaffold structure and explicit replacement copy.src/construction_frame/pages/workspace/project/mod.rs: project list lifecycle, per-draw I/O, adaptive desktop/mobile divergence, spreadsheet underflow, workspace routing without mandatory context.src/construction_frame/pages/workspace/project_management/{mod,logic,persistence,task,history}.rs: production/test duplication, unconstrained graph/date logic, global persistence, full-string history.src/construction_frame/pages/workspace/invoice/mod.rs: build-tree storage path, lossy fake JSON, discarded save errors, unrestricted financial values.src/construction_frame/pages/workspace/solar_calculator/{mod,engine}.rs: parse-to-zero behavior, unchecked indices, unused autonomy input, incomplete array/battery/electrical design..forgejo/workflows/nigig-build.yml,tools/test-cad-coverage.sh,tools/test-cad-widget-coverage.sh: stale ownership and false-positive gates.
3. Non-negotiable product invariants
- No workspace without
ProjectContext. CAD, documents, spreadsheets, invoices, schedules, solar designs, materials, workers, and progress receive a typedProjectId; they cannot open or persist with an implicit global project. - One project repository. All project data uses one injected repository rooted in the platform app-data directory. No runtime path is derived from
CARGO_MANIFEST_DIR. - Versioned data, atomic commits. Every aggregate has schema version, aggregate ID, project ID, revision, timestamps, and checksum/integrity metadata where appropriate. Successful writes are atomic and errors reach the UI.
- No corruption-to-demo. Missing, empty, corrupt, future-version, and valid-empty are distinct states. Demo fixtures require an explicit command and are never recovery behavior.
- Production code is tested directly. There is one implementation of task, scheduling, persistence, invoice math, and spreadsheet commands. Integration tests import it rather than copying it.
- Valid graph before schedule. Task IDs are unique; dependencies exist; self-links/cycles are rejected; dates/durations/calendars are bounded. Scheduling is deterministic and terminates in O(V+E) for the supported model.
- Money is not binary floating point. Amounts use checked minor units/fixed decimal, explicit ISO currency, explicit tax/rounding policy, and bounded quantities.
- Engineering output is qualified. A solar result is either a validated preliminary design with assumptions/warnings or a blocked/incomplete result. It is never presented as safe system sizing from an incomplete formula.
- All primary navigation is honest. Scaffold or unavailable workflows are marked unavailable; production labels appear only when acceptance criteria are met.
- No I/O in draw. Rendering reads in-memory snapshots. Repository load/save and heavy calculation run through lifecycle events and bounded jobs.
- Desktop and mobile share the same domain actions. Adaptive layout changes presentation, not project identity, data, limits, or business rules.
- PII and commercial records have lifecycle controls. Worker/client/contact data has purpose, access boundary, export policy, and deletion/retention behavior.
4. Severity-ranked findings
P0 — release blockers
| ID | Finding | Failure mode |
|---|---|---|
| BUILD-P0-01 | Workspaces can open without selecting/binding a project; each persists globally. | Data entered for Project A appears in Project B or is overwritten by it. |
| BUILD-P0-02 | Desktop project creation does not establish an active project; desktop cards are not a real open/select workflow. Mobile exposes only three records. | Users cannot reliably navigate projects, and platform behavior diverges. |
| BUILD-P0-03 | Runtime persistence uses build/source-tree paths in invoice and project-management code. | Installed/read-only builds fail or write into developer checkout; multiple users/projects collide. |
| BUILD-P0-04 | Writes are non-atomic or discarded, and UI can say “Saved” unconditionally. | Silent durable-data loss. |
| BUILD-P0-05 | Project-management mod.rs contains concatenated shadow implementations while extracted modules are separately tested. |
Tests and production execute different scheduling/persistence logic. |
| BUILD-P0-06 | Critical-path propagation uses an unbounded while changed; automatic scheduling stops at tasks.len() * 2 without proving convergence. |
Hang, wrong dates, or wrong critical path with no error. |
| BUILD-P0-07 | Duplicate/missing task IDs, dangling dependencies, cycles, negative/huge durations and excessive spans are not a hard precondition failure. | Order-dependent or non-terminating schedules and integer/date overflow. |
| BUILD-P0-08 | Invoice .json is a lossy pipe format and only persists line items. |
Saved invoice is not the invoice shown to the user; legal/commercial metadata disappears. |
| BUILD-P0-09 | Invoice quantity/price/tax/discount/shipping use unrestricted f64 and accept malformed, negative, NaN, or infinite values. |
Invalid totals, non-deterministic rounding, and unrepresentable persisted output. |
| BUILD-P0-10 | Spreadsheet aggregate actions subtract before checking row/column zero. | Debug panic or release underflow/wrong cell access at the first row/column. |
| BUILD-P0-11 | Solar output omits critical electrical and design constraints but is presented as a system design. | Unsafe strings, controllers, batteries, inverter, conductors, or protection can be recommended. |
P1 — major product, security, and correctness gaps
| ID | Finding | Consequence |
|---|---|---|
| BUILD-P1-01 | Materials, Workers, and Progress primary tabs are explicit scaffolds. | The advertised core product workflow is absent. |
| BUILD-P1-02 | Project list is reloaded during draw_walk; adaptive transitions use disk as synchronization. |
UI-thread I/O, jank, hidden error handling, and state races. |
| BUILD-P1-03 | Timestamp-derived project IDs can collide; project IDs are used without a unified path-safe type. | Record overwrite or path confusion. |
| BUILD-P1-04 | Schedule and invoice undo store full serialized strings and omit aggregate-level transaction semantics. | Memory growth and partial undo across visible metadata. |
| BUILD-P1-05 | Parsers replace invalid input with defaults/zero and deserializers seed plausible records. | User error/corruption becomes believable but false business data. |
| BUILD-P1-06 | Schedule serialization is hand-rolled and permissive. | Escaping, forward-compatibility, and malformed-data behavior are unreliable. |
| BUILD-P1-07 | Invoice “Save As” accepts a filename into a joined path and does not use a final picker/delivery lifecycle. | Traversal/overwrite risk and misleading saved destination. |
| BUILD-P1-08 | days_of_autonomy is collected but not applied to capacity; battery count ignores voltage topology. |
Results contradict entered requirements. |
| BUILD-P1-09 | PV sizing omits temperature-corrected Voc, MPPT window/current, parallel-string current, irradiance/weather, inverter limits, conductor/protection, and applicable code checks. | A numerically neat result is not an electrically valid design. |
| BUILD-P1-10 | Worker/client/commercial data lacks an explicit data-protection and access model. | PII or pricing can be disclosed or retained without policy. |
| BUILD-P1-11 | Tool copy and demo records look operational. | Users may mistake fixtures for their project records. |
P2 — maintainability, performance, and UX debt
- Multi-thousand-line widgets combine domain, persistence, formatting, hit testing, keyboard input, and rendering.
- Mobile and desktop handlers duplicate actions and differ semantically.
- Fixed mobile project buttons make list behavior non-scalable and inaccessible.
- Formula/schedule operations lack observable cost and cancellation.
- There is no explicit offline conflict model if multi-device storage is added later.
- CI spends substantial time on stale CAD source scans while meaningful production runtime behavior is absent.
5. Target architecture
BuildApp / Makepad views
│ user intents
▼
ProjectSession
├─ ProjectContext { ProjectId, revision, permissions/capabilities }
├─ WorkspaceRouter (refuses MissingContext)
├─ ProjectRepository
└─ Aggregate controllers
├─ ScheduleController -> Schedule aggregate
├─ SpreadsheetController -> Workbook reference/aggregate
├─ InvoiceController -> Invoice aggregate
├─ SolarDesignController -> PreliminarySolarDesign aggregate
├─ MaterialsController -> Material ledger/procurement links
├─ WorkersController -> roster/assignment/attendance
├─ ProgressController -> evidence + computed progress
└─ CadSession / DocsSession (typed project/document references)
ProjectRepository
<ProjectId>/manifest.json
<ProjectId>/aggregates/<kind>/<aggregate-id>.json
<ProjectId>/attachments/<content-id>
<ProjectId>/journal/...
Domain/repository rules
- IDs are opaque random 128-bit values (or another reviewed collision-resistant type), never timestamps or filenames.
- Repositories accept typed project/aggregate IDs and an injected root; UI code cannot construct storage paths.
- Each aggregate update is revision-checked and returns a durable commit result.
- Makepad widgets depend on controller traits and view models, not
std::fs. - Cross-workspace references contain project ID and target aggregate ID and are validated before commit.
- Derived totals, schedule dates, and progress are recomputed from typed source data, not independently edited copies.
6. Initial safety and performance budgets
| Resource | Initial limit/target | Enforcement |
|---|---|---|
| Projects per local repository | 10,000 | Paginated/virtualized query; never load all in draw. |
| Aggregate file input | 16 MiB | Check metadata/read cap before deserialize. |
| Schedule tasks | 10,000 | Decoder/command validation. |
| Schedule dependency edges | 100,000 | Decoder/graph builder. |
| Task duration | 1–36,500 working days | Typed constructor. |
| Schedule span | 100 years | Calendar validation before arithmetic. |
| Scheduler complexity | O(V+E); p95 < 100 ms for 10k tasks/100k edges on reference runner | Benchmark and complexity review. |
| Invoice line items | 10,000 | Command validation and virtualized UI. |
| Invoice serialized bytes | 16 MiB | Repository. |
| Money absolute amount | Product-configured, default <= 9×10^15 minor units | Checked i64 arithmetic; overflow is error. |
| Quantity decimal | <= 6 fractional digits and configured non-negative maximum | Fixed-decimal constructor. |
| Workbook | 100,000 non-empty cells, 1,000,000 dependency edges | Workbook engine. |
| Formula bytes / AST depth | 8 KiB / 128 | Parser before evaluation. |
| Formula recalculation | p95 < 100 ms for reference 100k-cell workbook; cancellable beyond one frame | Worker + benchmark. |
| Undo | 200 commands or 64 MiB per aggregate | Bounded journal by measured bytes. |
| UI event handler | p95 < 8 ms desktop / 12 ms mobile | No I/O or large calculation. |
| Repository save | debounced <= 500 ms; explicit save completion reports final durability | Bounded single-writer per project. |
| Attachment | 25 MiB each, 1 GiB/project default quota | Streamed content store; configurable policy. |
A budget failure is a named error and leaves the last durable aggregate intact. It is never converted to zero, an empty list, or demo content.
7. Dependency-ordered implementation tranches
BUILD-00 — Make CI test the product that ships
Priority: P0 Effort: 2–4 person-days Depends on: none
Change
- Remove/move stale CAD gates aimed at
crates/apps/nigig-build/.../workspace/cad; CAD is now owned bycad-core/cad-uiworkflows. - Make every source scan assert a non-empty target set.
- Compile/test production module paths rather than copied integration algorithms.
- Repair runtime UI startup so tests reach
AppStarted; classify exit 127 as harness failure. - Run library, integration, binary, runtime UI, clippy, supply-chain, and migration jobs separately with artifacts.
Tests / exit
- Deliberately empty a gate target and prove CI fails.
- Add a production-only mutation fixture and prove integration tests catch it.
- At least one runtime test proves an assertion executes after app startup on each supported CI platform.
- No command suppresses Cargo failure and then reports green from filtered output.
Rollback: CI mechanics may be corrected; stale scans and unexercised-runtime green status may not return.
BUILD-01 — Immediate containment and honest navigation
Priority: P0/P1 Effort: 1–2 person-days Depends on: BUILD-00
Change
- Label Materials, Workers, and Progress as unavailable prototypes or remove them from production navigation.
- Mark schedule, invoice, spreadsheet, solar, and CAD as project-scoped and block entry when no project is selected.
- Remove unconditional “Saved” copy from invoice and project-management actions.
- Label solar output “unvalidated estimate—not an electrical design” until BUILD-10 passes.
- Visually identify demo/template records and never load them automatically as user state.
Tests / exit
- Capability matrix drives navigation and copy on desktop/mobile.
- No missing-context route reaches a mutable workspace.
- Simulated write failure cannot display a save-success message.
- No scaffold is presented as an operational feature.
Rollback: unsafe/incomplete capabilities remain blocked or labelled; rollback cannot restore deceptive copy.
BUILD-02 — Mandatory typed ProjectContext
Priority: P0 Effort: 5–8 person-days Depends on: BUILD-01
Change
- Add typed
ProjectId,AggregateId,ProjectContext, and explicitNoProjectSelectedstate. - Implement one
ProjectSessionand one router; every workspace constructor/action receives context. - Replace timestamp project IDs with collision-resistant opaque IDs.
- Implement project select/open/close/delete/archive actions once, shared by adaptive views.
- Replace fixed three-item mobile controls with a virtualized, paginated list; provide the same lifecycle on desktop.
Tests / exit
- Compile/API tests prevent repository/workspace mutation without
ProjectContext. - A/B sentinel suite proves schedule, workbook, invoice, solar, CAD, and documents cannot cross project IDs.
- Creating/selecting/opening the 4th and 1,000th project works on mobile and desktop.
- ID collision injection is handled without overwrite.
Migration: map legacy timestamp IDs to new opaque IDs through a durable lookup table; never derive a path from the old raw value.
Rollback: retain a read-only legacy ID alias, but new writes always use typed IDs.
BUILD-03 — Versioned atomic ProjectRepository
Priority: P0 Effort: 6–9 person-days Depends on: BUILD-02
Change
- Create an injected repository root from platform app-data; ban runtime
CARGO_MANIFEST_DIRpaths. - Define versioned project manifest and aggregate envelope with project/aggregate ID, revision, created/updated timestamp, payload kind, and schema version.
- Use unique same-directory temp files, write/flush/sync, atomic replace, and directory sync where supported.
- Serialize with a maintained codec rather than hand-built JSON.
- Distinguish missing, valid empty, corrupt, unsupported future, permission, lock/conflict, quota, and I/O errors.
- Serialize writes per project and reject stale expected revisions.
Tests / exit
- Fault injection at create/write/flush/sync/rename/manifest steps preserves the previous revision.
- Concurrent stale writers receive conflicts rather than last-writer overwrite.
- Corrupt/future/truncated/oversized files never become empty or demo state.
- Symlink/path traversal and read-only-root tests fail safely.
- No
std::fsremains in widget modules except a reviewed picker handoff adapter.
Migration: copy legacy global/build-tree files into a quarantine area, parse with bounded readers, assign project explicitly, write/reopen/verify new aggregate, then mark legacy source migrated. Ambiguous global state requires user choice.
Rollback: manifest points to the last verified revision; preserve original legacy bytes.
BUILD-04 — Eliminate project-management source divergence
Priority: P0 Effort: 3–5 person-days Depends on: BUILD-00, BUILD-03
Change
- Make
project_management/mod.rsonly compose/importtask,logic,persistence,history,interaction, andrenderermodules. - Remove concatenated duplicate definitions and comments describing inline copies as intentional.
- Move pure domain/scheduler code into a Makepad-independent module or small crate.
- Make production widget call exactly the functions imported by tests.
Tests / exit
- Static uniqueness test reports one definition of each core task/scheduler/serializer type/function.
- Existing tests are moved to/import the production module with no algorithm copies.
- Mutation testing of a production scheduler branch makes the corresponding integration test fail.
- Public API docs name one source of truth.
Rollback: revert as a unit if module registration breaks, but do not keep duplicate algorithms active.
BUILD-05 — Validated deterministic scheduling engine
Priority: P0 Effort: 7–11 person-days Depends on: BUILD-04
Change
- Define typed task/dependency IDs, positive working-day durations, supported dependency relation (initially Finish-to-Start unless others are fully implemented), lag bounds, calendar, and date domain.
- Validate unique IDs, references, self-links, cycles, hierarchy, milestones, duration/date bounds, and edge/task limits before calculation.
- Topologically schedule earliest starts/finishes in O(V+E); reject rather than “iterate until maybe stable.”
- Compute latest dates/slack/critical path in reverse topological order against one explicit project finish.
- Return
ScheduleResultwith warnings and calculation revision; never mutate input partially.
Tests / exit
- Golden DAGs, multiple roots/sinks, diamonds, milestones, lag, calendars, unordered input, duplicate/dangling/self/cyclic graphs, and boundary dates.
- Property tests prove every valid dependency constraint and deterministic output under input permutation.
- Differential fixtures compare a reviewed reference implementation/tool for the supported subset.
- Scheduler terminates and meets §6; no
while changedremains.
Rollback: retain manual dates and disable automatic scheduling; do not restore best-effort unconverged output.
BUILD-06 — Project-scoped schedule persistence and commands
Priority: P0/P1 Effort: 5–8 person-days Depends on: BUILD-03, BUILD-05
Change
- Persist a versioned
Scheduleaggregate under project context. - Route add/edit/move/resize/link/delete/indent/bulk operations through revision-checked commands that validate and schedule a candidate before commit.
- Use bounded typed inverse commands rather than full serialized strings.
- Separate explicit “create demo schedule” from open/recovery.
- Preserve user-entered constraints and distinguish them from computed dates.
Tests / exit
- Apply → undo → redo restores canonical aggregate bytes/results.
- Rejected link/cycle/date edit leaves schedule/history/revision unchanged.
- A/B project and restart tests preserve independent schedules.
- Corrupt state opens recovery; valid empty remains empty.
- Save success waits for repository durability.
Rollback: switch manifest to prior schedule revision; no demo seeding.
BUILD-07 — Spreadsheet boundary and correctness hardening
Priority: P0/P1
Effort: 6–10 person-days across this app and spreadsheet-ui
Depends on: BUILD-02, BUILD-03
Change
- Bind workbook ID to project context and remove global
WorkspaceModel::load_saved()/save()from adaptive transitions. - Share one in-memory workbook controller between desktop/mobile; layout switch is not a disk synchronization protocol.
- Fix row/column-zero subtraction by checking before access and centralizing range/neighbor operations.
- Enforce cell/formula/dependency/AST budgets, cycle handling, finite numeric semantics, and cancellable incremental recalculation.
- Persist workbook revision atomically through
ProjectRepositoryor a repository adapter with the same contract.
Tests / exit
- First row/column, empty/single/multi-cell selections, reversed ranges, max boundaries, and aggregate actions do not panic or underflow.
- Desktop ↔ mobile resize preserves unsaved edits without disk round trip.
- A/B project and restart tests preserve distinct workbooks.
- Formula cycles, huge ranges, depth bombs, non-finite results, and cancellation are deterministic bounded errors.
Rollback: disable affected aggregate shortcuts and keep manual cell edit; never access wrapped coordinates.
BUILD-08 — Lossless typed invoice aggregate and migration
Priority: P0 Effort: 6–9 person-days Depends on: BUILD-03
Change
- Define
Invoicewith ID, project ID, number, status, issuer snapshot, client snapshot, billing/service address, issue/due date, currency, terms, references, line IDs/items, discounts, shipping, taxes, notes, revision, and audit timestamps. - Use checked minor-unit/fixed-decimal
Money, fixed-decimalQuantity, ISO currency, and typed tax rate/category. No financialf64. - Define line/tax/discount/rounding order and inclusive/exclusive policy explicitly.
- Serialize real versioned JSON (or documented codec) losslessly and validate on decode.
- Make invoice number uniqueness project/account scoped and enforce status transitions.
Tests / exit
- Every visible field survives save/reopen and undo/redo.
- Currency mismatch, overflow, negative disallowed values, NaN/inf legacy tokens, invalid dates, duplicate IDs/numbers, and future schema fail with precise errors.
- Golden totals cover taxable/non-taxable lines, line/document discounts, shipping, zero/maximum values, and half-way rounding.
- Legacy pipe data is recognized as legacy, never as JSON.
Migration: import line items into a draft invoice, require the user to supply/confirm all lost metadata, retain original bytes and migration warning, then save only after explicit review.
Rollback: restore the prior invoice revision/original legacy bytes; no lossy down-conversion.
BUILD-09 — Honest invoice UI, delivery, and audit
Priority: P1 Effort: 5–8 person-days Depends on: BUILD-08
Change
- Bind every header/party/date/term/total control to the aggregate, not static demo labels or table-only serialization.
- Surface field validation inline; invalid text is not silently replaced by 8.5/25/100.
- Route mutations through aggregate commands and bounded undo.
- Implement Save/Save As/export state machine: pending picker, cancelled, writing, durable, failed. Sanitize suggested names; destination is picker-provided, not joined user text.
- Record status transitions and immutable issued-invoice revisions; editing an issued invoice creates a revision/credit-note flow according to product policy.
Tests / exit
- UI-to-domain round trip covers all invoice fields and errors.
- Injected write/disk-full/picker-cancel cannot show saved.
- Keyboard/touch row editing respects validation and accessibility focus.
- Printed/exported totals equal domain totals exactly; no UI recomputation.
Rollback: invoices remain draft/read-only if issuance/export is unavailable.
BUILD-10 — Validate or constrain the solar design engine
Priority: P0 safety Effort: 12–20 person-days plus qualified electrical review Depends on: BUILD-02, BUILD-03
Change
- First narrow product claim to “preliminary estimate” and list required assumptions/omissions.
- Replace parse-to-zero with typed validated inputs and structured errors. Reject NaN/inf, negative, zero where invalid, unchecked dropdown index, and out-of-policy bounds.
- Model energy demand profile, system losses, location/weather dataset and provenance, autonomy days, battery chemistry/capacity/voltage/series-parallel topology, DoD, efficiency, temperature, aging, and surge/continuous inverter demand.
- Model panel temperature coefficient, minimum temperature, corrected Voc, Vmp/MPPT window, string/parallel current, controller/inverter input limits, DC/AC ratio, conductors, voltage drop, disconnects/overcurrent protection, and applicable local code assumptions.
- Return design validity, assumptions, warnings, and unresolved decisions—not just six numbers.
- Version component specifications with source/date rather than unexplained static spreadsheet values.
Tests / exit
- Independent hand calculations and a reviewed engineering tool agree within documented tolerance for the supported scope.
- Cold-Voc, hot-Vmp, current, surge, autonomy, series/parallel battery, controller, conductor/protection, extreme climate, and unavailable-data cases.
days_of_autonomymaterially affects output and is verified.- A licensed/qualified electrical or solar engineer approves formulas, assumptions, warnings, and product wording for target jurisdictions.
- If any required design constraint is unresolved, output is blocked or explicitly incomplete.
Migration: existing results are marked LegacyUnvalidated; never silently bless them after engine upgrade.
Rollback: expose only energy/load worksheets and disable equipment recommendations.
BUILD-11 — Implement project-scoped Materials workflow
Priority: P1 product completion Effort: 10–16 person-days Depends on: BUILD-02, BUILD-03; integrate procurement only through typed references
Change
- Define material/catalog item, unit of measure, planned quantity, requisition/order/receipt/issue/return/waste/adjustment ledger, storage location, supplier reference, unit cost/currency, and audit fields.
- Compute stock from immutable movements; do not allow direct total edits without an adjustment reason.
- Validate dimensions/finite quantities/unit conversion and project ownership.
- Provide list/search/filter, create/edit, receive/issue/adjust, low-stock/variance, and import/export with preview.
Tests / exit
- Ledger conservation, unit conversion, partial receipts, returns, waste, negative-stock policy, concurrent revision, and cost rounding.
- Every action is project-scoped, audited, undoable where legally appropriate, and durable.
- Mobile/desktop can operate beyond three rows and with keyboard/touch accessibility.
Rollback: keep tab unavailable rather than replace ledger rules with mutable demo totals.
BUILD-12 — Implement privacy-aware Workers workflow
Priority: P1 product completion Effort: 10–16 person-days plus privacy review Depends on: BUILD-02, BUILD-03
Change
- Define worker/contractor identity, trade/role, engagement status, contact fields only where necessary, qualifications/expiry, availability, project assignment, attendance/time record, and audit history.
- Separate global person record from project assignment if multi-project reuse is required; enforce least-data views.
- Add retention/deletion/export policy and redact sensitive fields from logs/diagnostics.
- Validate unique references, date ranges, hours, overlaps, qualification expiry, and project ownership.
Tests / exit
- Role/capability tests control sensitive field display/export.
- Assignment/attendance/date/overlap/expiry and A/B isolation tests.
- Deletion/anonymization/retention and backup behavior are documented and exercised.
- No production/demo worker PII seeds automatically.
Rollback: tab remains unavailable or read-only; no insecure partial roster.
BUILD-13 — Implement evidence-based Progress workflow
Priority: P1 product completion Effort: 8–14 person-days Depends on: BUILD-05, BUILD-06, optionally BUILD-11/12
Change
- Define progress update with task/quantity reference, reporting period, measured quantity/percent, evidence attachments, author, revision, approval status, and audit.
- Derive project/task progress from explicit weights/quantities; prohibit arbitrary double-counting and percent >100 unless policy names the exception.
- Compare baseline/current schedule and planned/actual quantities with transparent formulas.
- Preserve historical snapshots when baseline or weights change.
Tests / exit
- Weighted rollups, zero weight, overrun, revised baseline, rejected update, duplicate evidence/update, time-zone/date boundary, and A/B isolation.
- Displayed progress traces to source updates and formula version.
- Mobile/desktop create/review workflows are equivalent and accessible.
Rollback: show schedule-only status clearly; do not fabricate progress from elapsed time.
BUILD-14 — Project-scoped CAD and document integration
Priority: P1
Effort: 5–9 person-days after upstream contracts
Depends on: BUILD-02/03, cad-core CORE-03/06, cad-ui UI-02/03
Change
- Bind CAD/document sessions with typed project/document references from
ProjectContext. - Define link ownership, delete/archive behavior, and revision displayed in Build.
- Do not share thread-local active project or global generated files.
- Validate all cross-workspace links before commit; stale/deleted targets show explicit broken-link state.
Tests / exit
- A/B project switch cannot retain CAD geometry, document content, selection, undo, or async results.
- Archive/delete conflict behavior is deterministic.
- Save/restart reopens the referenced exact revisions.
- Build consumer tests run against canonical CAD contracts and real document repository APIs.
Rollback: disable embedded launch and expose read-only external references; never fall back to global state.
BUILD-15 — Responsive UX, lifecycle performance, and decomposition
Priority: P2 after domain correctness Effort: 8–14 person-days Depends on: BUILD-02 through required workflow tranches
Change
- Share domain intents/controllers between desktop/mobile; keep layout-specific rendering only.
- Remove repository calls from
draw_walk; load on session events and update via observed snapshots. - Virtualize project/task/invoice/material/worker lists and use stable IDs/focus.
- Move parser/scheduler/recalculation/file work off UI handlers with bounded, revision-correlated jobs.
- Split thousand-line widgets into domain controller, view model, renderer, input adapter, and persistence adapter.
- Add accessible labels, focus order, touch targets, keyboard navigation, contrast, loading/empty/error states.
Tests / exit
- Draw/event instrumentation detects I/O and fails the test.
- 10k-project/task and 100k-cell fixtures remain within §6 UI/compute budgets.
- Desktop/mobile conformance suite dispatches the same domain commands/results.
- Idle/hidden workspaces stop redraw/timers/background recalculation.
Rollback: revert presentation extraction independently; domain/project/repository boundaries remain.
BUILD-16 — Migration, runtime, adversarial, and release evidence
Priority: P0 release gate Effort: 7–12 person-days plus device time Depends on: all enabled-feature tranches
Change
- Add real runtime journeys: create/select/switch project, each enabled workspace, save, restart, conflict, recovery, export, mobile/desktop transition.
- Add malformed/oversized/future persistence corpus; schedule/formula property tests; financial golden corpus; solar reviewed corpus.
- Run forced I/O failures and long-session soak with memory, queue, write, recalculation, and frame metrics.
- Publish a capability matrix and release evidence artifact by commit/toolchain/platform.
Tests / exit
- All runtime tests reach app startup and assertions; zero unexplained ignores.
- Legacy migration is tested on copies, with rollback demonstrated.
- No cross-project sentinel appears after switch/restart/export.
- Performance and safety budgets pass on declared reference platforms.
- Only workflows whose complete gates pass are labelled operational.
Rollback: block release or disable the failing capability through BUILD-01's matrix.
8. Migration strategy
Legacy sources to inventory
- Project records/project types and active CAD marker.
- Global spreadsheet workbook.
generated/current.project.jsonschedule plus save-as copies.generated/current.invoice.jsonandinvoice_copy.jsonpipe records.- Solar values/results if persisted elsewhere later.
- CAD scripts/documents referenced by current project records.
Procedure
- Freeze legacy writers and compute checksums of original files.
- Copy bounded inputs into a migration quarantine; never parse directly into live state.
- Ask the user to assign ambiguous global workbook/schedule/invoice data to a project. Do not guess from “active” UI state.
- Decode with a format-specific legacy reader. Record dropped/ambiguous fields explicitly.
- Validate the new aggregate, write revision 1 atomically, reopen, and compare its canonical hash/domain totals.
- Mark migration complete in the new manifest only after all required aggregates verify.
- Keep original bytes and a mapping of legacy ID/path → new typed ID for the compatibility window.
- A future schema is read-only; corruption is recoverable; valid empty remains empty.
- Remove legacy write paths immediately, legacy readers after a documented support window.
Invoice migration cannot be lossless because the current file never stored visible metadata. It must create an unissued draft requiring review rather than inventing issuer/client/date/currency/tax terms.
9. Required CI matrix
cargo fmt -p nigig-build -- --check
cargo metadata --locked --format-version 1 >/dev/null
cargo check --locked -p nigig-build --all-targets
cargo test --locked -p nigig-build --lib -- --test-threads=1
cargo test --locked -p nigig-build --tests -- --test-threads=1
cargo clippy --locked -p nigig-build --all-targets -- -D warnings
git diff --check
As tranches land:
cargo test --locked -p nigig-build --test project_isolation -- --test-threads=1
cargo test --locked -p nigig-build --test persistence_faults -- --test-threads=1
cargo test --locked -p nigig-build --test schedule_properties -- --test-threads=1
cargo test --locked -p nigig-build --test invoice_golden -- --test-threads=1
cargo test --locked -p nigig-build --test spreadsheet_boundaries -- --test-threads=1
cargo test --locked -p nigig-build --test runtime_ui -- --test-threads=1
Also run direct dependencies/consumers for touched contracts (spreadsheet-ui, doc, cad-core, cad-ui, nigig-core, nigig-uikit). The workflow must use package names confirmed by cargo metadata, not guessed directory names.
Rules:
- No
|| truearound Cargo, clippy, runtime, migration, or source-ownership gates. - Exit 127 before startup is a failed harness job.
- Tests that copy a production algorithm are deleted/replaced, not counted.
- Source scans fail if no file is scanned.
- Engineering review and independent calculation evidence are release artifacts, not unit-test comments.
10. Release gates
- CI targets the current source tree and runtime tests execute assertions.
- Every mutable workspace requires typed
ProjectContext. - Desktop/mobile provide the same scalable select/open/close project lifecycle.
- Versioned atomic repository, conflict detection, recovery, and fault-injection tests pass.
- No runtime path uses
CARGO_MANIFEST_DIR; no widget performs filesystem I/O. - A/B sentinel suite proves zero cross-project leakage in every enabled workspace.
- Production scheduling has one implementation and passes graph/property/complexity gates.
- Spreadsheet row/column boundaries, formula limits, and project isolation pass.
- Invoice persistence is lossless and all financial math uses checked decimal/minor-unit types.
- Save/picker/write failures can never produce success UI.
- Solar remains estimate-only or satisfies the complete qualified-review gate.
- Materials/Workers/Progress remain unavailable unless their full workflow criteria pass.
- CAD/doc integration uses typed project/document/revision contracts.
- No automatic demo seeding occurs on missing/corrupt state.
- PII/commercial data lifecycle and export policy are approved and tested.
- Runtime, migration, forced-failure, soak, accessibility, and performance evidence passes on supported platforms.
- Zero unexplained/expired ignored tests and zero warnings suppressed from owned code.
11. Delivery, push safety, and rollback
For every BUILD-NN tranche:
- Start from a clean worktree; record HEAD and the tests that fail before the fix.
- Implement only one atomic exit criterion when the listed tranche is too broad for review.
- Run targeted tests, the required consumer matrix, and
git diff --check. - Commit with the tranche ID.
- Immediately before each push,
git fetch origin mainand compare merge base/remote changes. - Rebase or merge without dropping remote work; rerun tests after any reconciliation.
- Push without force and verify the remote contains that exact commit before beginning the next tested chunk.
- If authentication is unavailable, retain and report the tested local commit; never pretend it was pushed or later overwrite remote history.
Rollback principles:
- Optional incomplete workflows are disabled through the capability matrix.
- Aggregate rollback selects the prior verified revision; original migration inputs are preserved.
- Financial/engineering safety checks are fail-closed and are never removed to restore availability.
- Project context and repository boundaries do not get feature-flagged off after migration begins.
12. Critical path and cross-plan dependencies
BUILD-00 → BUILD-01 → BUILD-02 → BUILD-03
│ ├→ BUILD-04 → BUILD-05 → BUILD-06 → BUILD-13
│ ├→ BUILD-07
│ ├→ BUILD-08 → BUILD-09
│ ├→ BUILD-10
│ ├→ BUILD-11
│ └→ BUILD-12
└─ CAD core/UI prerequisites ─→ BUILD-14
All enabled paths → BUILD-15 → BUILD-16
- CAD integration waits for
cad-core's canonical document/transaction contracts andcad-ui's session/project isolation. - Spreadsheet changes must be made in its real owner and tested through this app; do not fork its engine into
nigig-build. - Site data is not silently reused for workers/procurement. Any future integration needs authenticated project/site mapping, field minimization, and conflict semantics.
- Solar equipment recommendations remain off the critical path; a safe release can omit them.