A first run failed with "Permission denied (publickey)": s1 accepts only
the blog key (deploy@s1.b4l.co.th, SHA256:o4w7HL...) for the deploy user,
and the secret held a different key. The SSH step now strips CR, refuses
a secret that is not an unencrypted private key, and logs the key's
fingerprint for comparison with authorized_keys. The ssh host alias is
renamed so the masked VPS_USER value no longer hides it in the log.
site/ builds the internal test site: public/ served as is (landing page,
robots.txt, static sites) plus demo pages copied out of docs/ (the plant
operation page at /demos/plant-operation/). build.sh fails on dead
internal links and stamps version.txt.
.gitea/workflows/deploy-site.yml rsyncs site/dist to the buildfor.life
web server with the blog's two-directory rename swap, checks version.txt
on the server, purges Cloudflare when a token is set, and checks the
public URL. Secret names match the blog's workflow.
site/Caddyfile is the virtual host to append on s1 (noindex everywhere,
Cloudflare-only like the blog apex, www redirect). site/README.md has the
one-time setup: DNS, Caddy, web root, secrets, runner.
New docs/artist-platform.md: upload master and artwork with automatic
audio, artwork and rights checks; an itemised price calculator for every
customer (per-title vs per-copy lines, price-per-copy curve, lead time
from the production-timeline quote table, versioned price list); and
fan-funded campaigns that press and dropship per fan once the goal is
reached, refund otherwise. Covers goal maths, payments (charge into a
ring-fenced account, CNX as seller of record, legal opinion first; the
Qrates failure as the design rule), repress pre-orders, architecture on
the cnx-factory stack with the public side on a fleet machine, PDPA,
phasing (calculator public early as a run-size probe, campaigns only
after first releases ship), cost and open decisions.
Backlinks from README, process flow, production timeline, revenue model,
digital factory and roadmap items 1 and 20; total investment added-scope
table gains the platform line.
New docs/crane-workshop-tours.md: a 5 t single-girder EOT crane over the
whole production compartment (stops at the warehouse fire wall), a
machine door and crane-served workshop/machine bay at the ramp end, and
a glazed ground-level visitor corridor along the car-park elevation with
stations in process order, its own air and acoustic glazing so tours
need no PPE. Covers what each changes in the shell (crane-ready frame,
hook height under the 7.0 m eave, no full-height cross walls in the
crane zone, room lids and crane hatches), safety, costs and open
decisions.
Propagated: construction RFQ (crane-ready frame, new section 1c, machine
door, accessible 1:12 entrance now required), scale zone table (+210 to
280 m2, total ~1,400 to 2,000 m2), facility security, worker safety,
roadmap items 9 and 15, total investment added-scope table, README.
Sillitoe Audio Technology (Australia) sells a complete cutting system:
lathe, MMFB feedback cutterhead, cutting amplifier, Space / Time Control
automation with a virtual groove, vacuum and microscope, at a published
USD 125,000 ex tax and shipping. Vendor landscape gets the narrative and
an Agnew-or-Sillitoe comparison; supplier map, total investment basis,
roadmap item 13 and the digital factory's no-telemetry section (STC cue
sheet, Open Groove export, stylus hours) follow.
Rewrite docs/digital-factory.md against the fleet that already exists at
git.b4l.co.th/B4L/cnx-network-clan instead of a plant-only clan:
- The plant is one more site: gw-lpn-1 from the cnx.router module, plant
machines in the same inventory, reached over the existing ZeroTier mesh
(no VPS, no moon, no port forwards).
- Fleet pieces reused as-is: control for host metrics, journals and host
alerts; ns1/ns2 for the gateway wildcard cert; web01 as the public
proxy for the customer portal; clan borgbackup with a plant server.
- Process time series move from TimescaleDB to a plant-local
VictoriaMetrics (same modules and rules as control); PostgreSQL keeps
everything with identity. Object storage dropped for ZFS datasets.
- VLAN table on the fleet addressing convention (siteId 3 assumed, ids
above 40); OT segments as dual-homed islands behind the collectors;
stations reach the app only through the gateway Caddy proxy.
- New section listing every file that changes in the clan repo, the
modules/vinyl/* to write, and three router-module extensions (NTP
serving, static VLANs, second WAN).
- Gaps the plant closes for the fleet: Alertmanager delivery, off-site
backup destination, TSDB backup.
- Repository layout decided: infra in cnx-network-clan, app in
cnx-factory as a flake input, this repo stays documents.
README bullet updated to match.
New docs/digital-factory.md: every system needed for environmental,
machine, QC and genealogy data to land in one database keyed to one
record identity. Standing decision: all services run on NixOS machines
declared and deployed as a single clan.lol inventory (mesh, backups,
host monitoring, secrets from clan services).
Covers machine list and roles, VLAN zoning, Telegraf/MQTT acquisition
source by source with the RFQ clause for each, environment sensor zones,
QC instrument integration paths, the factory application modules and
entities, alerting tiers, backup and retention, security, procurement
clauses, build order aligned with the roadmap phases, rough cost and
open questions.
README index and layout tree updated; roadmap item 17 and the
traceability spec link to the new document.
The docs and the plant page had labelling as a finishing step after the
press. On a record press the bottom label, the cake and the top label go
in between the stampers every cycle and the mold bonds the paper into the
vinyl; the oven only pre-dries them. Corrected everywhere the process is
described:
- process-flow.md: labels are a parallel input to pressing with their own
row (print inspection, oven, lot per cycle); stage 6 loads label, cake,
label; stage 7 is trim, sleeve, shrink
- process-flow.drawio (+ regenerated png/pdf): label input now feeds
stage 6, not stage 7
- README vision list and the business plan source (regenerated docx/pdf):
pressing paragraph explains the pressed-in label, finishing no longer
claims to label
- plant-operation.html: label dry oven station feeds two label discs
into the press with every cake, the cake in the mold shows its labels,
the cycle log records the label lot, finishing is sleeve + shrink
docs/plant-operation.html: one self-contained static page showing the
whole plant running, from PVC intake and the material lab gate through
extruder, press cycle (load/close/steam/cool/open/eject), trimmer, 100%
optical inspection, sampled audio comparison, finishing, packaging
(matrix code vs barcode) and fulfillment. The metal path (audio intake,
mastering, cutting, silvering, father/mother/stamper, stamper prep) runs
above with the three artist gates; utilities (steam, cooling, air,
hydraulics, grinder/regrind, energy, traceability, HVAC) below with
live-looking tags.
Numbers are taken from the repo (Newbilt site requirements, scale.md,
quality-automation.md, process-flow.md). Every station is clickable for
what happens there and the checks that gate it. Two demo buttons show a
steam pressure dip holding the press and a new PVC lot held by the lab
until a test pressing releases it. README links the page.
Leased land instead of purchase, in-house cassette duplication, CD-R
duplication with CD replication shown as a separate investor decision,
Ploy Printing as packaging partner and intended co-investor, and a
dedicated section on traceability, metrology, QC and efficiency.
The project has a standing style rule against em dashes that was missed
when these docs were written. This removes the 42 occurrences where the
substitution is mechanical and cannot change meaning:
- table cells using an em dash as a placeholder, now a hyphen
- em dashes immediately followed by a conjunction or subordinator
(but, and, or, so, though, while, which, where, because, since),
where a comma is simply correct
115 remain. Those join independent clauses, where a comma would create a
splice and a colon often reads wrong, so each needs a judgement call
rather than a pattern. A blanket regex over them was attempted and
reverted: it produced double colons and broken sentences.
Both were flagged in the review and deferred; fixing them properly
changes what the model says.
Labour
- The 0.23-0.40 USD/record line implied 44,000-63,000 THB per head per
month, far above northern Thai production rates.
- Rebuilt from headcount and wages: 13-19 direct production staff
(operators, galvanics, QC, maintenance) at loaded northern Thai rates
gives 3.7M-5.4M THB/yr, or 0.08-0.16 USD per record. Build-up shown.
- Mastering and cutting engineers excluded as title-services labour;
admin and sales moved to overheads where they belong.
- Stamper amortisation widened to 0.03-0.12 to match the in-house
marginal cost assumed elsewhere on the page.
- Direct cost total is now 1.30-2.58 USD (43-85 THB).
Operating roll-up
- The old EBITDA and operating-profit figures did not reconcile with
their own components and showed no loss case anywhere. Replaced with
a three-scenario table built from the components, each column
internally consistent, with cash overheads and depreciation separated.
- The adverse case is EBITDA-positive but does NOT cover depreciation:
operating profit -0.32M USD at 1.0M records on the low price and high
cost. The previous figures quoted 0.6-1.2M and hid this entirely.
Utilisation and price realisation decide solvency, not just upside.
- The favourable case is not credible and that is a finding about the
cost table rather than the business: 69% EBITDA margin against
industry norms of 15-25%, and 47% even at the centre. The direct cost
table counts only per-record consumables and direct payroll. Named
what is missing (indirect labour, scrap above the reject allowance,
water and effluent, inbound freight, inventory carrying, sales
commission) and marked the adverse column as the honest one until
those lines exist.
- Payback restated per scenario: never / 2.3-4.4 yr / 1.0-1.8 yr. The
old "5 to 8 years" came from the pre-correction margin.
- FX sensitivity and the utilisation bullet updated to match.
The table is a sensitivity, not a forecast, and now says so.
A four-agent review audited arithmetic, cross-document consistency,
epistemic honesty and style. It found substantially more than the
manual pass in the previous commit. Errors that changed conclusions,
not decimals:
Arithmetic
- production-timeline: the headline lead times did not reconcile with
the stage table on the same page. Launch is 22-49 days (was 21-39),
mature 11.5-22 (was 14-20), repress 6.5-11.5. Including gates,
launch is 6-17 weeks, not 8-14.
- Consequence: at 17 weeks the launch configuration is at parity with
EU/US plants, not ahead of them. The page now compares quote to
quote rather than a stage sum to a quoted lead time, and says so.
- The galvanics turnaround saving is 1.5-5 weeks, not 3-5.
- scale.md Duplex capacity 300-600k/yr did not reproduce from its own
stated basis; corrected to 175-540k. production-timeline disagreed
with scale.md on the same fleet; both now agree.
- "300 units is under an hour of pressing" was out by an order of
magnitude on the semi-auto line: 5-8 hours.
- project-timeline carried two totals for the same quantity. Now
27-33 months throughout, with the Gantt's two ordering breaks fixed.
- scale.md: 300 kWp covers 28-45% of consumption, not 20-35%; roof PV
stated as both 150-200 and 247 kWp for the same roof; parking canopy
dimensions and PV disagreed with the RFQ.
- RFQ: fire tank stated 200 m3 where both its geometry (254 m3) and
its own mass (250 t) say 250. Drainage now gives total sealed area
66%, not the 46% paving figure, since that is what attenuation needs.
- Galvanics payback used only the top of the saving range: 1-5 years,
not 1-4.
Inference marked as inference
- The 22,000 THB stamper figure is an invoice RESIDUAL. It carries
lacquer cutting, test pressings, setup and margin, so it is an upper
bound on the stamper component, not a measurement. Everything derived
from it now says so, and a line-itemised invoice is the top question.
- The saving was also benchmarked against the wrong supplier: CNX buys
from Stamper Discs, not a Thai reseller. Stated as 175-665 USD until
that quote exists.
- The stamper-bottleneck hypothesis now names its alternatives. Jacket
print runs would produce the same symptom and would constrain CNX
equally, which would remove the competitive read entirely.
- Competitor capacity relabelled as nameplate times an assumed OEE,
with the assumed shift pattern stated; all rows on one 300-day basis.
- The fixed/variable decomposition keeps the shape and drops the point
estimates: the solve point inside the flat 1000-3000 tier is
arbitrary and moves the fixed component by nearly half.
- "Nobody in Thailand plates" reduced to "we have found no evidence",
with a desk check named as the action.
- Cut the USD 450-700k valuation of a competitor's presses entirely.
It extrapolated a semi-auto quote onto a different machine, ignored
the used market, and supported no decision.
- The collaboration payback divided capex by revenue where the same
page uses contribution elsewhere: 5-10 years, not 1-3.
Missing caveats added
- No financing is committed or modelled anywhere in this repo;
project-timeline previously asserted money was not a constraint.
- Leasing cannot pull the launch forward on its own, since the press
chain governs and construction has float against it.
- The whole competitive analysis is one buyer, one plant, one
afternoon, and the primary evidence is not archived in the repo.
- ResurRec is a competitor and may decline to buy from a new entrant.
Currency
- Base currency moves from EUR to USD and THB throughout. Rates at
5 Aug 2026: 1 USD = 33 THB, 1 EUR = 1.155 USD, 1 GBP = 1.35 USD.
EUR/THB lands at ~38, so existing THB research needed no change.
- Vendor quotes keep their original currency with a USD/THB equivalent
alongside, so they stay checkable against the source PDFs.
- Full vision ~4.7-8.9M USD; phased entry ~1.7-2.9M USD.
New documents
- production-timeline.md: order turnaround stage by stage. Launch
8-14 weeks, mature 5-10, repress 2-3. Quantifies the in-house
galvanics turnaround claim the repo had asserted without a number,
and flags artwork as an unmodelled fourth approval gate.
- project-timeline.md: calendar to first paying release, ~Q4 2028.
Critical path is BOI certificate to press order to build to
commissioning. Two findings: Newbilt build time is absent from the
repo yet carries ~40% of the schedule, and the BOI rule may be
over-serialised since duty exemption attaches at importation rather
than at contract signature.
First market data (ResurRec, Bangkok)
- Invoice-derived prices, a factory tour, and a confirmed fleet of one
Newbilt Classic 12" automatic plus one semi-automatic.
- Price ladder recorded at 300/500/1000-3000/3000+ units. Decomposes
to roughly 34-50k THB fixed per title and 535-780 THB variable per
unit, which is 4-7x the price this model assumes.
- The incumbent presses 230-350k records/yr but buys every stamper as
an import. That single constraint plausibly explains their 150-unit
floor, their flat discount ladder and their large-run lead time, and
it is what an in-house galvanics line attacks. Logged as an open
question on whether galvanics should move from phase 5 to phase 1.
- Inferences are marked as inferences; the whole set is one buyer and
one plant, and the model is deliberately left unrebased until a
second data point exists.
Corrections
- Gross margin arithmetic did not follow from its own inputs. Restated
as ~1.95 USD at the midpoint with the 0.75-3.15 spread shown; the
previous "40 to 55%" was not supported.
- Direct cost low total 1.50 to 1.45 USD; contingency THB high 40M
to 38M.
- README indexes the construction RFQ, which was missing.
The parametric model (docs/cnx_vinyl_parametric.FCStd) is now tracked. It
is the spreadsheet-driven Arch/BIM rebuild that supersedes the hard-coded
massing in factory_building_rough.FCStd, which is kept because the current
renders still come from it.
Site works. The two gates are consolidated into a single 10.0 m bi-parting
opening, with the wall plugged where the second one stood. The guard house
sits beside it clear of the entry corridor, and was raised out of the
ground - it had been modelled sunk half a storey. The fire water tank moved
to the north-west corner of the plot, taking utility-yard clearance from
5.6 m to 18.6 m; the fire pump house follows it. The site is now paved
continuously from the frontage through to phase 2: 4,387 m², split 1,608
heavy-duty and 2,779 general so the two can be priced apart.
Phase 1 envelope. The walls stopped flat at 8.2 m while the roof rose to
12.6 m, leaving the entire high-side wall and both gable triangles open -
about 366 m². Walls now follow the roof underside exactly. The rebuild also
starts the sandwich panel on top of the masonry dado, clearing a 31.9 m³
overlap that had been double-counting 425 m² of envelope. A vehicle ramp
(10.5 m at 1:10) and three stair flights are added, since with FFL at
+1.2 m the building had no means of access at grade.
Phase 2. Built from the design already documented in scale.md: 45 x 38 m,
two-bay sawtooth at 10.35/7.0 m with a 3.35 m glazed riser, bays falling
ESE. A three-storey office cube - canteen, office, office plus sleeping -
stands at the yard end of the west tooth, 1.65 m proud of the ridge. Its
walls and the hall walls are Arch Walls, and the yard glazing is Arch
Windows, so both carry IFC types and cut their own openings.
RFQ updated against the model throughout, with a new section on where
mineral-wool core is required instead of PIR, for compartmentation and for
acoustics.
Site model: two sealed dock positions on the north gable (depressed
12 m pit + 12 m ramp cut into ground and paving), water treatment
moved clear of the cooling tower, second car/staff gate on the NE
edge with access road to parking, guard house relocated between the
gates, perimeter wall rebuilt continuous on its 0.4 m inset line,
leftover door recesses filled on both envelopes, loading-apron
marking removed. Renders re-exported.
Docs: phase 1 contractor pricing request (PEB spec, PIR envelope,
dock, site works, exclusions, soil caveats).
setViewDirection leaves camera roll unconstrained, so the aerials came
out with a tilted horizon. The camera orientation is now built explicitly
with world +Z projected as the frame up-vector.
Two FreeCAD quirks had to be worked around. setCameraOrientation() goes
through an animated setter (UseAnimation defaults on), so saveImage fired
mid-transition and the roll drifted; setting the Coin camera node
directly avoids the animation entirely. The first call after a standard
view also needs a second application to take, so each render now verifies
up.z equals cos(elevation) before saving and retries if not.
Also tightened framing 20%, since fitAll was zooming out to include the
road strip that runs well past the parcel.
The first pass included two orthographic elevations and a low approach
view, which read the site edge-on and showed no roof. Dropped those.
The set is now six views that all look down: a straight-down site plan,
four aerials at 45 degrees from each corner, and one 35 degree hero shot.
Nine 2400px views of the site model in docs/renders: an isometric, a
site plan, dimetric and trimetric, four aerial obliques from each corner,
a low approach view from the road, and two orthographic elevations.
Also hardens the freecad MCP entry added in the previous commit. It ran
"uvx freecad-mcp" unpinned, which resolves and executes whatever version
is current at every launch. Now pinned to 0.1.20 and marked optional, in
line with the ruv-swarm and flow-nexus entries alongside it.
Models the plot and everything on it in FreeCAD, and writes up the
decisions the modelling forced.
Parcel geometry is traced from the DOL LandsMaps cadastral polygon and
reconciled against that portal's own measured edge lengths (40.86 + 26.61
/ 166.81 / 42.48 + 14.94 / 152.46 m), which the trace reproduces to within
about 1% with 1.67 m of closure error over a 444 m perimeter. Note the
mapped extent comes out near 9,570 sqm against a deed area of 8,266 sqm,
a ~16% gap that needs a surveyor before any offer.
On the site: 60x25 m production building on a 10 degree monopitch, a
45x38 m phase-2 building, roof and carport PV, fire and raw water tanks,
a detached boiler/chiller utility yard, perimeter wall and gate, guard
house, roofed staff parking, and the loading and fire-access roads.
Docs:
- scale.md: expansion headroom for a second building, and the detached
utility yard, which frees ~126 sqm inside the main shed
- sustainability.md: roof orientation study (rotating the building for
solar gains under 1 point and costs 4 m of clearance, so it stays
aligned to the plot), and a new water supply section
- facility-security.md: fire water supply behind the existing
suppression design
Figures marked as estimates are planning-grade, not engineering
calculations; the PV module spec is a generic placeholder, and zoning for
factory use on this plot is still unverified.
Three current gates (market validation, BOI, land title check) through
quotes, commitment, build, launch, and revenue-gated expansion; import
window correctly attributed to certificate issuance
Own land yields ~80-135 t/yr vs ~350-400 t/yr mature demand; forestry
classification check gates everything; staged electric-first path with
coppice planted now for the expansion-phase biomass boiler
Press cooling return (60 C) feeds heat pump into boiler feedwater; waste
heat runs label oven and HVAC dehumid reheat; solar thermal preheat;
steam accumulator; boiler does only the final lift. Heat pumps for the
final 180 C steam and ground-source in tropical Thailand both ruled out
with reasoning; northern Thailand LPG tank context documented
Steam, compressed air, cooling, water treatment, racking, HVAC, solar EPC
and BESS; baseline total 23.98M-41.63M THB, options priced separately;
all figures budgetary +/- 30%, basis marked per row
Group B base activity (plastics) with non-tax package and machinery duty
exemption; CIT value engineered via solar/BESS, smart-and-sustainable
automation, and R&D merit measures; NEC/Lamphun regional angle; BOI
approval sequenced ahead of incorporation and machinery orders
- docs/process-flow.md: mermaid chart plus stage table of every check and
the three artist approval gates, from audio intake to fulfillment
- docs/process-flow.drawio with PNG and PDF exports
- pressing-line.md: floor must carry multiple tons per m2 in machine areas
- README: process-flow entry in document index and layout tree
- docs/facility-layout.drawio: zoned floor concept (production, galvanics,
utilities, logistics, support) with material and stamper flow arrows
- PNG and PDF exports alongside the source
- facility-security.md: suppression subsection no longer splits the fire
safety bullet list; clean agent wording updated to FK-5-1-12
- README: vendor sections for Agnew Analog (lathe), Plating Power/Digital
Matrix (galvanics), Sibert (stamper prep), Stamper Discs (bridge stamper
service), Pheenix Alpha (automated presses)
- docs/suppliers/equipment-suppliers.md: full needs list and supplier map
across all nine areas of the production chain
- docs/: Newbilt equipment offer, site requirements, process schematic,
service rates, project cost overview, PVC supplier list, consultancy overview
- .gitignore excluding local tooling config and runtime state