@structupath/pi-steel 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DATA_PROVENANCE.json +23 -0
- package/DATA_PROVENANCE.md +35 -0
- package/PUBLIC_DATA_POLICY.md +52 -0
- package/README.md +114 -33
- package/docs/assets/pi-steel-demo.gif +0 -0
- package/docs/assets/pi-steel-gallery.webp +0 -0
- package/package.json +35 -4
- package/pyproject.toml +28 -0
- package/requirements-dev.txt +5 -0
- package/requirements-render.txt +1 -0
- package/requirements-tested.txt +9 -0
- package/requirements.txt +7 -0
- package/scripts/check-data-provenance.py +140 -0
- package/scripts/check-public-data.py +401 -0
- package/scripts/doctor.py +127 -0
- package/skills/_shared/bootstrap.py +32 -0
- package/skills/_shared/pi_steel/__init__.py +47 -0
- package/skills/_shared/pi_steel/cli.py +167 -0
- package/skills/_shared/pi_steel/contracts.py +87 -0
- package/skills/_shared/pi_steel/geometry_verify.py +243 -0
- package/skills/_shared/pi_steel/parsing.py +205 -0
- package/skills/_shared/pi_steel/run_manifest.py +317 -0
- package/skills/_shared/pi_steel/validation.py +597 -0
- package/skills/_shared/schemas/estimate-package.schema.json +424 -0
- package/skills/_shared/schemas/nest-result.schema.json +443 -0
- package/skills/_shared/schemas/run-manifest.schema.json +145 -0
- package/skills/steel-estimate/SKILL.md +119 -0
- package/skills/steel-estimate/references/estimate-package-example.json +91 -0
- package/skills/steel-estimate/references/output-contract.md +47 -0
- package/skills/steel-estimate/scripts/acknowledge-finding.py +193 -0
- package/skills/steel-estimate/scripts/build-estimate-package.py +836 -0
- package/skills/steel-nest/SKILL.md +50 -23
- package/skills/steel-nest/references/FIXTURE_PROVENANCE.md +12 -0
- package/skills/steel-nest/references/example_job.json +21 -25
- package/skills/steel-nest/references/job_template.json +11 -9
- package/skills/steel-nest/scripts/nest.py +1276 -250
- package/skills/steel-rfq/SKILL.md +93 -175
- package/skills/steel-rfq/assets/company-profile.example.json +11 -5
- package/skills/steel-rfq/references/rfq-input.md +58 -0
- package/skills/steel-rfq/scripts/generate-rfq.py +1221 -0
- package/skills/steel-rfq/scripts/recalc.py +33 -10
- package/skills/steel-takeoff/SKILL.md +12 -8
- package/skills/steel-takeoff/assets/bom-template.csv +1 -1
- package/skills/steel-takeoff/references/takeoff-procedures.md +3 -1
- package/skills/steel-takeoff/scripts/calculate-weight.sh +5 -10
- package/skills/steel-takeoff/scripts/lookup-member.sh +2 -2
- package/skills/steel-takeoff/scripts/validate-bom.py +151 -196
- package/skills/steel-rfq/scripts/__pycache__/recalc.cpython-312.pyc +0 -0
|
@@ -1,179 +1,97 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: steel-rfq
|
|
3
|
-
description: "
|
|
3
|
+
description: "Compile a deterministic draft steel RFQ workbook from a validated canonical estimate package or an exact-header legacy workbook. Use for material quote lists, RFQ spreadsheets, or versioned nesting references. Produces artifacts only; it never sends, awards, or authorizes purchasing."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Steel RFQ
|
|
7
|
-
|
|
8
|
-
##
|
|
9
|
-
|
|
10
|
-
This skill
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
##
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
`
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
>
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
3. **FLAT BAR STOCK — [Grade]** (all flat bar material)
|
|
99
|
-
|
|
100
|
-
Each group gets a section header row: merged across all columns, medium blue background, white bold text.
|
|
101
|
-
|
|
102
|
-
**Data rows**:
|
|
103
|
-
- Alternate row shading: light blue (#D6E4F0) and white
|
|
104
|
-
- Vendor columns (I–N) always have yellow background (#FFF2CC) regardless of row
|
|
105
|
-
- Weight column (H) formatted as `#,##0`
|
|
106
|
-
- Price columns (I–J) formatted as `$#,##0.00`
|
|
107
|
-
- All cells have thin borders
|
|
108
|
-
|
|
109
|
-
**Filtering rules**:
|
|
110
|
-
- EXCLUDE any item where the description contains "BY OTHERS" (purlins, etc.)
|
|
111
|
-
- EXCLUDE any item where Qty = 0
|
|
112
|
-
- If the estimate has a "Stock Purchase" section (Section E or similar) with consolidated purchase items for plates/flat bar, use those instead of the individual connection plate items. The stock purchase items represent what's actually being ordered (full sheets, full bars), which is what the vendor needs to quote.
|
|
113
|
-
- Keep individual W-shape items because each shape/length combination matters for vendor stock
|
|
114
|
-
|
|
115
|
-
### Totals Row
|
|
116
|
-
- "TOTAL PURCHASE WEIGHT / PRICE" label merged A–G, right-aligned bold
|
|
117
|
-
- Column H: `=SUM(H[first]:H[last])` formula for total weight, green background (#E2EFDA)
|
|
118
|
-
- Column J: `=SUM(J[first]:J[last])` formula for total price, green background
|
|
119
|
-
|
|
120
|
-
### Nesting / Drop Reference Table
|
|
121
|
-
Below the totals (skip a row), add a reference section:
|
|
122
|
-
- Header: "NESTING / DROP REFERENCE (For Fabricator Use)" — dark blue bold text
|
|
123
|
-
- Three columns: Material | Nesting Plan | Drop Notes
|
|
124
|
-
- Column headers with medium blue background
|
|
125
|
-
- One row per material showing the nesting layout and expected drop from the estimate
|
|
126
|
-
- This helps cross-check vendor stock lengths against the cutting plan
|
|
127
|
-
|
|
128
|
-
### Standard Terms & Conditions
|
|
129
|
-
Below the nesting table (skip a row), add:
|
|
130
|
-
- Header: "TERMS & CONDITIONS" — dark blue bold text
|
|
131
|
-
- Include these standard terms, each on its own row, substituting the company name and payment terms from the company profile:
|
|
132
|
-
|
|
133
|
-
1. **Delivery**: All material to be delivered FOB jobsite unless otherwise agreed. Vendor to confirm freight costs separately.
|
|
134
|
-
2. **Mill Certifications**: Mill test reports (MTRs) required for all structural steel per AISC/AWS standards. Certs must accompany delivery.
|
|
135
|
-
3. **Payment Terms**: [payment_terms from profile] unless otherwise negotiated in writing.
|
|
136
|
-
4. **Material Standards**: All wide-flange shapes to meet ASTM A992. All plate and bar to meet grade specified on this RFQ (A572 Gr.50 or A36).
|
|
137
|
-
5. **Substitutions**: No substitutions without prior written approval from [Company Name]. If quoting alternate sizes, clearly note in the "Alternate Size" column.
|
|
138
|
-
6. **Quote Validity**: Quoted prices to remain firm for [quote_validity_days] days from date of quote unless otherwise stated.
|
|
139
|
-
7. **Inspection**: [Company Name] reserves the right to inspect material upon delivery and reject material not meeting specifications.
|
|
140
|
-
8. **Cancellation**: Orders may be cancelled without penalty if material has not shipped. Restocking fees, if any, to be stated in quote.
|
|
141
|
-
|
|
142
|
-
### Branding / Logo
|
|
143
|
-
If the company profile names a logo file and it exists in the skill's `assets/` directory, insert it in cell A1 area (top-left) and adjust the header text to not overlap. Otherwise use the text header as described above.
|
|
144
|
-
|
|
145
|
-
## Print Setup
|
|
146
|
-
- Orientation: Landscape
|
|
147
|
-
- Fit to width: 1 page
|
|
148
|
-
- Fit to height: 0 (auto)
|
|
149
|
-
- Print title rows: Row 8 (column headers repeat on each page)
|
|
150
|
-
|
|
151
|
-
## File Naming
|
|
152
|
-
Output file: `[ProjectName]_RFQ_Material_List.xlsx`
|
|
153
|
-
- Extract project name from the estimate file (look in "Project Info" sheet or the first rows of the takeoff)
|
|
154
|
-
- Replace spaces with underscores
|
|
155
|
-
- Example: `Cherokee_Boys_RFQ_Material_List.xlsx`
|
|
156
|
-
|
|
157
|
-
## Step-by-Step Workflow
|
|
158
|
-
|
|
159
|
-
1. Load the company profile (or collect it from the user — see Company Profile above)
|
|
160
|
-
2. Read the uploaded estimate file with pandas to understand its structure
|
|
161
|
-
3. Identify the takeoff sheet and parse all line items
|
|
162
|
-
4. Filter out "BY OTHERS" items and zero-quantity items
|
|
163
|
-
5. Group remaining items by material type (W-shapes → Plates → Flat Bar)
|
|
164
|
-
6. If there's a stock purchase section, use those for plates/flat bar instead of individual pieces
|
|
165
|
-
7. Build the RFQ spreadsheet using openpyxl following the format above
|
|
166
|
-
8. Add formulas for totals and verify the SUM ranges cover exactly the data rows
|
|
167
|
-
9. Add nesting/drop reference from the estimate notes — or, if the `steel-nest` skill has been run for this job, read its `rfq_nesting.json` output straight into the table
|
|
168
|
-
10. Add standard terms & conditions with profile values substituted
|
|
169
|
-
11. Insert logo if configured
|
|
170
|
-
12. Save the file, then run `python3 scripts/recalc.py <output.xlsx>` so formula values are computed (openpyxl writes formulas but never calculates them)
|
|
171
|
-
13. Verify no formula errors and present the file to the user
|
|
172
|
-
|
|
173
|
-
## Common Variations
|
|
174
|
-
|
|
175
|
-
**Multiple structures in one project**: Combine all materials into one RFQ, but note which structure each item belongs to in the Description column (e.g., "W12×65 Columns (Bldg A)").
|
|
176
|
-
|
|
177
|
-
**Plate stock with nesting**: When plates are purchased as full sheets and then cut, show the full sheet as the line item (that's what the vendor ships) and put the cutting plan in the nesting reference table.
|
|
178
|
-
|
|
179
|
-
**Mixed grades**: Group by material type first, then note the grade in each row. If a project has A992, A572, and A36, they all appear in the appropriate material type section with grade clearly marked.
|
|
6
|
+
# Steel RFQ Compiler
|
|
7
|
+
|
|
8
|
+
## Boundary
|
|
9
|
+
|
|
10
|
+
This skill creates a reviewable draft workbook. It does not contact vendors,
|
|
11
|
+
send RFQs, select a quote, approve substitutions, award work, or authorize a
|
|
12
|
+
purchase. Every workbook and manifest records `DRAFT — NOT SENT OR AWARDED`.
|
|
13
|
+
|
|
14
|
+
## Required inputs
|
|
15
|
+
|
|
16
|
+
- Canonical estimate-package JSON `1.0.0`, or the conservative exact-header
|
|
17
|
+
legacy XLSX contract in `references/rfq-input.md`.
|
|
18
|
+
- Explicit issue date.
|
|
19
|
+
- A runtime company profile with company name, city/state, and an approved,
|
|
20
|
+
hash-bound terms template.
|
|
21
|
+
- Optional versioned nesting handoff `1.0.0`.
|
|
22
|
+
|
|
23
|
+
Resolve the company profile from `PI_STEEL_CONFIG`, project-local ignored
|
|
24
|
+
`.pi-steel/company-profile.json`, then the platform user-config directory.
|
|
25
|
+
Never write runtime identity, terms, or logos into this installed skill.
|
|
26
|
+
|
|
27
|
+
The shipped `assets/company-profile.example.json` is deliberately unapproved.
|
|
28
|
+
Copy it to a runtime config location, supply reviewed terms and approval
|
|
29
|
+
metadata, recompute the exact UTF-8 SHA-256, then change status to `approved`.
|
|
30
|
+
|
|
31
|
+
## Deterministic scope and purchasing rules
|
|
32
|
+
|
|
33
|
+
- Canonical `intent` controls scope. Description text cannot exclude an item.
|
|
34
|
+
- `allowance`, `exclusion`, and `by_others` never become vendor quantities.
|
|
35
|
+
- Zero quantity in the legacy adapter maps to excluded scope.
|
|
36
|
+
- Consolidated purchased stock replaces fabricated pieces only through explicit
|
|
37
|
+
`dimensions.replaces_item_ids`.
|
|
38
|
+
- Lines remain traceable by source and item ID.
|
|
39
|
+
- Groups and nesting references remain separate by material, grade, thickness,
|
|
40
|
+
size, and stock identity.
|
|
41
|
+
- Missing identity, approved terms, supported versions, or valid input blocks
|
|
42
|
+
workbook generation.
|
|
43
|
+
|
|
44
|
+
## Workbook contract
|
|
45
|
+
|
|
46
|
+
The compiler owns:
|
|
47
|
+
|
|
48
|
+
- `RFQ Draft` and hidden `RFQ Metadata` sheets.
|
|
49
|
+
- Dark-blue title block, fillable vendor block, fixed A:N headers, grouped
|
|
50
|
+
purchase lines, yellow vendor-response cells, formulas, borders, widths, and
|
|
51
|
+
alternating row fills.
|
|
52
|
+
- Exact total formulas covering the deterministic material range.
|
|
53
|
+
- Versioned nesting/remnant reference rows with visible reference-only labels.
|
|
54
|
+
- Approved terms content and approval lineage.
|
|
55
|
+
- Landscape print setup, one-page width, repeated row-8 headers, and stable
|
|
56
|
+
project-derived filename.
|
|
57
|
+
|
|
58
|
+
A missing optional logo falls back to the text header and does not invent
|
|
59
|
+
branding.
|
|
60
|
+
|
|
61
|
+
## Run
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
python3 scripts/generate-rfq.py \
|
|
65
|
+
--input <estimate-package.json-or-exact-legacy.xlsx> \
|
|
66
|
+
--nest <optional-rfq_nesting.json> \
|
|
67
|
+
--issued-date <YYYY-MM-DD> \
|
|
68
|
+
--project-location "Example City, ST" \
|
|
69
|
+
--out <publication-root>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Each invocation publishes an isolated run with `run-manifest.json`,
|
|
73
|
+
`qa-report.json`, the draft `.xlsx` when gates pass, and
|
|
74
|
+
`workbook-semantic.json`.
|
|
75
|
+
|
|
76
|
+
Exit codes:
|
|
77
|
+
|
|
78
|
+
- `0`: draft RFQ ready for human review.
|
|
79
|
+
- `2`: draft generated with review-required warnings or reference-only nesting.
|
|
80
|
+
- `3`: blocked; diagnostics only, no workbook.
|
|
81
|
+
- `1`: usage or internal input error.
|
|
82
|
+
|
|
83
|
+
## Formula calculation status
|
|
84
|
+
|
|
85
|
+
The compiler always requests full recalculation on open. If LibreOffice is
|
|
86
|
+
available and succeeds, QA says `baked_via_libreoffice`. Otherwise QA says
|
|
87
|
+
`deferred_recalculate_on_open`; it never claims cached formula values were
|
|
88
|
+
computed.
|
|
89
|
+
|
|
90
|
+
## Verification before delivery
|
|
91
|
+
|
|
92
|
+
- Confirm the manifest outcome and artifact allow-list.
|
|
93
|
+
- Confirm workbook metadata remains draft-only.
|
|
94
|
+
- Confirm every purchase line is traceable and typed in scope.
|
|
95
|
+
- Confirm totals formulas span the intended material rows.
|
|
96
|
+
- Confirm nesting rows preserve material/grade/thickness/size boundaries.
|
|
97
|
+
- Report deferred formula caching and reference-only nesting visibly.
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
-
"company_name": "
|
|
3
|
-
"city_state": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
2
|
+
"company_name": "Example Fabricator",
|
|
3
|
+
"city_state": "Example City, ST",
|
|
4
|
+
"logo": null,
|
|
5
|
+
"terms_template": {
|
|
6
|
+
"template_id": "EXAMPLE-TERMS-UNAPPROVED",
|
|
7
|
+
"content": "ENTER SYNTHETICALLY APPROVED TERMS TEMPLATE",
|
|
8
|
+
"content_hash": "607418ebf6466ee2f5f45b7ea63603baba276b5f95860cd8a079dfa1d652fe6b",
|
|
9
|
+
"approver": "ENTER APPROVER",
|
|
10
|
+
"approval_date": null,
|
|
11
|
+
"status": "draft"
|
|
12
|
+
}
|
|
7
13
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# RFQ compiler input contract
|
|
2
|
+
|
|
3
|
+
The deterministic compiler accepts either:
|
|
4
|
+
|
|
5
|
+
1. A canonical estimate package at schema version `1.0.0`.
|
|
6
|
+
2. A legacy `.xlsx` workbook with a sheet named exactly `Steel Takeoff` and
|
|
7
|
+
these exact row-1 headers:
|
|
8
|
+
|
|
9
|
+
`Source_ID`, `Item_ID`, `Scope`, `Description`, `Material`, `Grade`,
|
|
10
|
+
`Thickness`, `Size`, `Qty`, `Currency`, `Purchase Weight`.
|
|
11
|
+
|
|
12
|
+
The legacy adapter is intentionally narrow. `Scope` must be exactly `IN SCOPE`,
|
|
13
|
+
`BY OTHERS`, or `EXCLUDED`; descriptions never control scope. Missing stable
|
|
14
|
+
IDs, renamed columns, inferred section headers, and ambiguous quantities are
|
|
15
|
+
rejected for explicit mapping outside the compiler.
|
|
16
|
+
|
|
17
|
+
Canonical filtering uses `intent`. Allowances, exclusions, and by-others items
|
|
18
|
+
never become vendor lines. A purchased-stock or hardware item replaces
|
|
19
|
+
fabricated items only when its `dimensions.replaces_item_ids` explicitly names
|
|
20
|
+
those canonical item IDs.
|
|
21
|
+
|
|
22
|
+
The optional nesting input is the versioned `rfq_nesting.json` object:
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"schema_version": "1.0.0",
|
|
27
|
+
"source_nest_result_version": "1.0.0",
|
|
28
|
+
"geometry_readiness": "geometry_verified",
|
|
29
|
+
"rows": []
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Unknown versions are blocked. Rows stay separate by stock identity, material,
|
|
34
|
+
grade, thickness, and sheet size.
|
|
35
|
+
|
|
36
|
+
The company profile is resolved in this order:
|
|
37
|
+
|
|
38
|
+
1. File named by `PI_STEEL_CONFIG`.
|
|
39
|
+
2. Ignored project file `.pi-steel/company-profile.json` beside the input.
|
|
40
|
+
3. Platform user configuration at `pi-steel/company-profile.json`.
|
|
41
|
+
|
|
42
|
+
Runtime profiles must not be saved under the installed package. The profile
|
|
43
|
+
requires company identity and an approved `terms_template` whose SHA-256
|
|
44
|
+
matches its exact UTF-8 content. Editing terms invalidates approval. A missing
|
|
45
|
+
optional logo uses the text header.
|
|
46
|
+
|
|
47
|
+
The command requires an explicit issue date:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
python3 scripts/generate-rfq.py \
|
|
51
|
+
--input estimate-package.json \
|
|
52
|
+
--nest rfq_nesting.json \
|
|
53
|
+
--issued-date 2026-07-28 \
|
|
54
|
+
--out published/
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Every workbook is marked `DRAFT — NOT SENT OR AWARDED`. The compiler contains
|
|
58
|
+
no send, award, vendor-selection, or purchase-authorization action.
|