Some checks failed
repo hygiene / hygiene (push) Has been cancelled
nigig-build (CAD) / supply-chain (push) Has been cancelled
nigig-build (CAD) / cad-module (push) Has been cancelled
nigig-build (CAD) / full-crate-check (push) Has been cancelled
nigig-build (CAD) / cad-engine-coverage (push) Has been cancelled
nigig-build (CAD) / doc-workspace-coverage (push) Has been cancelled
nigig-build (CAD) / cad-widget-coverage (push) Has been cancelled
707 lines
42 KiB
Markdown
707 lines
42 KiB
Markdown
# 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 `.json` filename. 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
|
||
|
||
1. **No workspace without `ProjectContext`.** CAD, documents, spreadsheets, invoices, schedules, solar designs, materials, workers, and progress receive a typed `ProjectId`; they cannot open or persist with an implicit global project.
|
||
2. **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`.
|
||
3. **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.
|
||
4. **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.
|
||
5. **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.
|
||
6. **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.
|
||
7. **Money is not binary floating point.** Amounts use checked minor units/fixed decimal, explicit ISO currency, explicit tax/rounding policy, and bounded quantities.
|
||
8. **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.
|
||
9. **All primary navigation is honest.** Scaffold or unavailable workflows are marked unavailable; production labels appear only when acceptance criteria are met.
|
||
10. **No I/O in draw.** Rendering reads in-memory snapshots. Repository load/save and heavy calculation run through lifecycle events and bounded jobs.
|
||
11. **Desktop and mobile share the same domain actions.** Adaptive layout changes presentation, not project identity, data, limits, or business rules.
|
||
12. **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
|
||
|
||
```text
|
||
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 by `cad-core`/`cad-ui` workflows.
|
||
- 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 explicit `NoProjectSelected` state.
|
||
- Implement one `ProjectSession` and 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_DIR` paths.
|
||
- 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::fs` remains 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.rs` only compose/import `task`, `logic`, `persistence`, `history`, `interaction`, and `renderer` modules.
|
||
- 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 `ScheduleResult` with 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 changed` remains.
|
||
|
||
**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 `Schedule` aggregate 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 `ProjectRepository` or 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 `Invoice` with 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-decimal `Quantity`, ISO currency, and typed tax rate/category. No financial `f64`.
|
||
- 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_autonomy` materially 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.json` schedule plus save-as copies.
|
||
- `generated/current.invoice.json` and `invoice_copy.json` pipe records.
|
||
- Solar values/results if persisted elsewhere later.
|
||
- CAD scripts/documents referenced by current project records.
|
||
|
||
### Procedure
|
||
|
||
1. Freeze legacy writers and compute checksums of original files.
|
||
2. Copy bounded inputs into a migration quarantine; never parse directly into live state.
|
||
3. Ask the user to assign ambiguous global workbook/schedule/invoice data to a project. Do not guess from “active” UI state.
|
||
4. Decode with a format-specific legacy reader. Record dropped/ambiguous fields explicitly.
|
||
5. Validate the new aggregate, write revision 1 atomically, reopen, and compare its canonical hash/domain totals.
|
||
6. Mark migration complete in the new manifest only after all required aggregates verify.
|
||
7. Keep original bytes and a mapping of legacy ID/path → new typed ID for the compatibility window.
|
||
8. A future schema is read-only; corruption is recoverable; valid empty remains empty.
|
||
9. 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
|
||
|
||
```bash
|
||
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:
|
||
|
||
```bash
|
||
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 `|| true` around 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:
|
||
|
||
1. Start from a clean worktree; record HEAD and the tests that fail before the fix.
|
||
2. Implement only one atomic exit criterion when the listed tranche is too broad for review.
|
||
3. Run targeted tests, the required consumer matrix, and `git diff --check`.
|
||
4. Commit with the tranche ID.
|
||
5. Immediately before each push, `git fetch origin main` and compare merge base/remote changes.
|
||
6. Rebase or merge without dropping remote work; rerun tests after any reconciliation.
|
||
7. Push without force and verify the remote contains that exact commit before beginning the next tested chunk.
|
||
8. 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
|
||
|
||
```text
|
||
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 and `cad-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.
|