Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions docs/CODEX_WORKFLOW_STABILEO.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,81 @@ The quality bar is not just "pretty drawings". It is:
- continuity that engineers trust
- schedules that help fabrication
- reports that are professionally readable

## PR19 is RC CAD constructibility (reassigned 2026-07-30)

Stack position 19 now belongs to **RC detail CAD constructibility review**, not seismic.

- **Seismic (INPRES-CIRSOC 103) is deferred.** Its original implementation was lost with the
2026-07-29 workstation data loss and no Git object survived. The specification that could be
recovered is preserved in `docs/handoffs/deferred-seismic-103-2026-07-29.md`. No seismic
branch, tag or implementation exists.
- **PR19 begins in POC / design phase.** The branch `pr/19-rc-cad-constructibility` starts as
documentation and architecture only, with no production CAD integration code.
- **It is intended to mature in place** into a real, mergeable PR19 on the same branch, rather
than being replaced by a separate implementation branch later.
- First component is a single **isolated footing**, drawn from a real PR18 production fixture.
- It stacks on `pr/18-rc-slabs-walls-foundations`, never on a QA branch.

Design record: `docs/poc/rc-footing-cad-review.md`.

## Branch backup policy — corrected 2026-07-30

The earlier version of this policy (commit `88abc899`) said to open a draft PR as soon as any
branch differed from its base. Applied to every branch that produced PR noise: an integration
branch that must never merge and a deliberately-red evidence snapshot both got draft PRs and both
had to be closed with explanations. A draft PR is a **review surface**; remote backup is a
**push**. The rule is now scoped by branch kind. Push everything; open PRs only where a PR means
something.

**Real deliverable branches** — features, fixes, intended documentation, anything expected to
mature into a mergeable contribution: push immediately; open a draft PR after the first coherent
commit; push every signed checkpoint; keep draft until review-ready.

**QA / integration branches**: push remotely while active; **do not open a PR**; record the exact
component heads; serve the exact branch locally; delete only after a verified replacement exists.

**Temporary evidence / scratch branches**: push only when needed to protect decision-blocked work;
**do not open a PR**; label clearly as non-mergeable; delete once the evidence is represented in
final commits or tracked documentation.

**External forks**: push work to the user's fork, never upstream; do not open an upstream PR until
there is a coherent upstream contribution; a design-only or exploratory fork branch needs no PR;
never push to upstream without explicit authorization.

Never force-push without explicit authorization. A branch push does not preserve `.git/`
contents — that is why `RC_CHAIN_PROGRESS.md`, `pr-drafts/` and the 14 stashes were
unrecoverable. Before deleting any branch, prove the work exists elsewhere: check ancestry against
every production ref, check the tracked docs, and check that no unique required change lives only
there.

### Superseded original (2026-07-29) — kept for history

The first version of this policy was committed as `88abc899` **onto the QA integration branch**
rather than onto a deliverable branch, so it was reachable from no PR and would have been orphaned
when that QA branch was retired. That misplacement is itself an instance of the problem the
correction above fixes: tracked documentation is deliverable work and belongs on a deliverable
branch. Its text is preserved verbatim here so nothing is lost, and it is **superseded** — the
scoped rules above are the ones in force.

> Meaningful local work must never remain local-only again. PR19 was complete, green and signed,
> and it was lost because it was never pushed. PR15-PR18 survived only because they were on GitHub.
>
> 1. Push every newly created work branch immediately to an authorized GitHub remote.
> 2. Once the branch has any diff from its base, open a draft PR immediately.
> 3. Push every coherent signed checkpoint.
> 4. Keep the PR in draft until it is explicitly declared review-ready.
> 5. A draft backup PR is not authorization to merge.
> 6. Never force-push without explicit authorization.
> 7. For external repositories, push to the user's fork, not the upstream repository.
> 8. If GitHub cannot create a PR because the branch has no commits beyond its base, push the
> branch to the fork as the minimum backup and open the draft PR after the first commit.
> 9. Before ending any session, verify: the branch has an upstream, all commits are pushed, a
> draft PR exists when the branch differs from base, and the worktree is clean or every
> dirty file is explicitly reported.
>
> A branch push does not save `.git/` contents. `RC_CHAIN_PROGRESS.md`, `pr-drafts/` and the
> 14 stashes were lost for exactly that reason. Anything that matters and lives only in
> `.git/` must also be duplicated somewhere replicated.

Rule 2 is the part the correction narrows: it now applies to deliverable branches only.
157 changes: 157 additions & 0 deletions docs/handoffs/deferred-cover-validation-pr20.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
# Deferred: generalized authoritative cover validation — probable PR20

Deferred out of PR19 by decision on 2026-07-30. PR19 uses **2-C with 2-A's honesty**: Stabileo
exports the cover requirement it genuinely owns and reports containment as **`NOT_EVALUATED`**; the
CAD side measures achieved cover independently as a **geometric observation**, never a regulatory
verdict.

This document records what would be needed to make cover validation authoritative inside Stabileo.
Sections are marked **[FACT]** (measured in the current code), **[PROPOSED]** (architecture not yet
built) or **[OPEN]** (genuinely unresolved).

## Why this is deferred rather than done — [FACT]

`checkCover` exists in `web/src/lib/engine/detailing/collision.ts:612` and is unit-tested, but it has
**zero production callers**. Every reference in `web/src`:

| Reference | Kind |
|---|---|
| `engine/detailing/collision.ts:612` | its own definition |
| `engine/detailing/__tests__/bar-geometry.test.ts:8, 342, 347, 353, 362, 373` | tests only |

So Stabileo has **no post-hoc geometric containment verdict in production at all** — not for
footings, and not for beams or columns either. Cover is achieved **by construction**, as a placement
input:

```
// engine/detailing/floor-design.ts
footingCover: number; // Bottom cover in the footing, m
const available = input.footingThickness - input.footingCover - 0.05;
const inset = panel.cover + d / 2 + (layer.direction === 'y' ? d : 0);
```

Bars are *placed* at the correct cover arithmetically. Nothing afterwards measures whether the
realised 3-D geometry sits inside the concrete. That is a defensible design, and it is why wiring a
new authoritative check is a **product-behaviour change** that belongs in its own PR rather than
inside a POC slice.

## What PR20 must consider

### Element types — [FACT] that all six exist in the model

Cover is not one number. The model already carries distinct cover data for:

| Element type | Where cover lives today |
|---|---|
| **Footing** | `model/footing.ts` — `Footing.cover`, plus `floor-design.ts` `footingCover` |
| **Pedestal** | `model/footing.ts` — `Pedestal` (`B`, `L`, `height`) |
| **Slab** | `floor-design.ts` — `panel.cover` |
| **Wall** | `floor-transverse.ts`, `slab-wall-drawings.ts` |
| **Beam** | section `cover` on the design section |
| **Column** | section `cover`, plus `tieDia` affecting effective placement |

A single global scalar would be wrong for all six.

### Surface / face roles — [OPEN]

The current model does **not** distinguish cover by face. A generalized check would have to decide
which surface roles are real for each element type. Candidates that a reinforced-concrete detailer
would expect — **none of which currently exist in the code, and none of which should be invented
here**:

- top, bottom, side, end
- exposed vs. unexposed
- soil-contact (the classic footing case, where the bottom face typically demands more cover than
the sides)
- formed vs. cast-against-earth
- fire-exposed

**This is the central open question of PR20.** Introducing face roles touches the model, the
detailing placement arithmetic, the regulation lookup, the document/export surface and the UI. It is
not a small addition.

**No regulatory values are proposed here.** The applicable cover values must come from the
regulation via the existing PR16 provenance mechanism (`ClauseRef`, edition-aware lookup), not from
a table written into this document.

### The check itself — [PROPOSED]

`checkCover` currently takes `SectionPrism { halfWidth, halfHeight, origin, axis }` — a prism about
a member axis. **A footing pad is not that shape.** A generalized check needs a containment
abstraction that covers at least:

- a box with `B`, `L`, `thickness` and `rotationDeg` (footing, pedestal)
- a prism about a member axis (beam, column) — already supported
- a bounded plate region (slab, wall)

Whether that is one polymorphic solid abstraction or several per-family checks is **[OPEN]**.

### Arc handling — [FACT], already solved and must be reused

`BarSegment` stores the arc `centre` precisely because start/end/radius/sweep do not determine a
3-D arc. `COLLISION_CHORD_TOLERANCE = 0.0005` m governs sampling. The documented failure this
prevents: a Ø8 stirrup's 90° corner sat **5.9 mm** inboard and a 135° hook **12.3 mm** inboard when
arcs were linearly interpolated — larger than the bars being checked. **Any new containment check
must sample through the same arc-aware path**, or it will reintroduce exactly that error.

### Interaction with the existing collision path — [FACT]

`detectCollisions` is already wired into the floor coordinator (`coordinate-floor.ts`) and produces
`BarConflict { severity, barA, barB, at, clearance, required, shortfall, elementIds }`. A cover
check should produce a comparably structured result — `CoverBreach` already has the right shape
(`barId`, `at`, `actualCover`, `requiredCover`, `elementIds`) — so the two can share reporting,
review and supersession machinery rather than growing a parallel one.

### Risk to existing fixtures — [OPEN]

Wiring a previously-unused check into a mature detailing path may start failing existing production
fixtures. Those failures could be **legitimate** (real defects the check finds) or **spurious** (an
abstraction mismatch). Distinguishing them is part of PR20's work and is a substantial reason it
needs its own review cycle.

## What PR19 does instead — [FACT]

- Exports the cover requirement Stabileo genuinely owns, scoped by element and requirement identity,
as a **list**, never a global scalar — so PR20 can add per-face requirements without redesigning
the schema.
- Preserves the existing modelled value rather than hard-coding 50 mm.
- Reports the containment check as `authority: "none"`, `evaluationStatus: "NOT_EVALUATED"` with a
concrete `notEvaluatedReason`.
- Lets the CAD side measure achieved cover and report it as a geometric observation, explicitly
**not comparable** to a Stabileo verdict.

## The migration PR20 must be able to make without schema redesign

`RcCadHandoffV1` was shaped so that this transition needs no reinterpretation:

**Today**

```
check: { checkKind: "concreteCover", authority: "none",
evaluationStatus: "NOT_EVALUATED", notEvaluatedReason: "…" }
cad-review: measured 48.7 mm, status NOT_COMPARABLE
```

**After PR20**

```
check: { checkKind: "concreteCover", authority: "stabileo",
evaluationStatus: "EVALUATED",
findings: [ { barIdA, at, measured, required, shortfall } ] }
cad-review: measured 48.7 mm, status AGREEMENT (within the 0.5 mm band)
```

The fields that change are `authority`, `evaluationStatus` and the presence of `findings`. Nothing is
repurposed, nothing is overloaded, and `requirementId` keys stay stable across the transition.

## Open questions for PR20

1. Which surface roles are real for each element type, and where do they live in the model?
2. One polymorphic containment solid, or per-family checks?
3. Does the regulation distinguish cover by exposure in the editions Stabileo already supports, and
does PR16's provenance mechanism already carry enough to look it up?
4. How are legitimate new failures on existing fixtures triaged and communicated?
5. Does cover validation gate readiness/certification, or report as a warning first?
6. Is editable per-face cover a UI requirement, or is it derived from element and exposure?

**None of these is answered here. PR19 introduces no cover UI and no regulatory cover values.**
Loading
Loading