Live API verification notes¶
Empirical findings from running midas-nx v0.8.0 against real MIDAS NX Open
API sessions (one Gen NX session, one Civil NX session, both connected via
the live cloud relay at moa-engineers.midasit.com, not mocked). This is
not sourced from the vendored manual — everything else in this repo is
typed strictly from docs/manual/*.md and treated as the single source of
truth; this file exists precisely because these findings are not in the
manual and shouldn't be silently baked into the SDK's typed contracts
(PRODUCTS, METHODS) without independent reproduction. See the caveat at
the bottom before acting on anything here.
Date: 2026-07-15. One MIDASIT account, one Gen NX process, one Civil NX
process, both freshly reset via /doc/new before testing.
Current live-session baseline (2026-09-16, author-confirmed): MIDAS Gen NX 2026 v2.1, Build 09/15/2026; MIDAS Civil NX 2026 v2.2, Build 09/15/2026. Both were read from their own About dialogs on 2026-09-16. The two products carry the same build date for the first time in this file's history - they have been patched separately all year - so do not infer one from the other next time either; read both. Record this baseline with every new live finding; it supersedes an endpoint's older build metadata only when that endpoint was actually exercised in this session.
The API reports no build. There is no /doc/*, /ope/* or /view/*
endpoint that returns one, and verify_connection() answers only user,
program, connectionID, keyVerified and status - confirmed 2026-09-06.
So every build string in this file and in docs/coverage.json is a human
reading the product's About dialog. A build string you did not read is not a
measurement; leave the field out rather than carry one forward from a
neighbouring entry. That is exactly how five 2026-09-06 entries came to claim
Builds 08/26 and 08/27 on machines running 09/02.
Method¶
- Read-only smoke test: every
DbResourcesubclass acrossdb/,design/,post/whoseMETHODSincludesGETand whosePRODUCTSincludes the product under test got a liveGETcall against a blank new document. No fixtures needed — a blank model returns an empty result for every valid endpoint (confirmed shape:{"message": ""}for zero-row tables,{"<KEY>": {}}for zero-row/db/*tables), so a non-2xx response reliably signals a real problem rather than "no data." - Write round-trip (Gen only): built a minimal model — 1 material
(
MATL, concrete C24), 1 section (SECT, 600×600), 2 nodes, 1 beam element, 1 fixed support — then exercised representative endpoints from each design-code chapter (ch24db/design.py, ch25steel_kds.py, ch26rc_kds/setup.py, ch27src_aiksrc2k.py) against it.
Read-only results¶
| Product | GET-capable & product-compatible classes tested | OK | Failed (all 404) |
|---|---|---|---|
| Gen | 253 | 233 (92%) | 20 |
| Civil | 293 | 273 (93%) | 20 |
Failure breakdown¶
Hyper-S (-M1) endpoints — 13, fail under Gen.
⚠️ Corrected 2026-07-26. The original text here said these were "absent from the Civil target set entirely (their
PRODUCTSis already{"gen"}-only in the SDK)" and explained the Gen 404s as the session not running in Hyper-S solver mode. Both halves were wrong. TheirPRODUCTSwas{"gen", "civil"}, so they were in the Civil target set, and re-running the sweep shows all 13 answering under Civil. Hyper-S is the solver MIDASIT introduced with Civil NX — it is a Civil NX feature, not a Gen mode — so the Gen 404s are correct behaviour and the SDK'sPRODUCTSwas the thing that was wrong. Fixed viaHYPER_S_ONLYindb/base.py. See the 2026-07-26 section below. The claim was never checked against a Civil run; it was inferred, and the inference was wrong in a way that a one-linesorted(cls.PRODUCTS)would have caught.
/db/ACTL-M1,/db/BCGA-M1,/db/BCGD-M1,/db/EIGV-M1,/db/HHCT-M1,/db/NLCT-M1,/db/NLNK-M1,/db/STCT-M1,/db/THGC-M1,/db/THIS-M1,/db/THOO-M1,/db/POGD-M1,/db/POLC-M1
Failed under Gen, succeeded under Civil (7) — current SDK PRODUCTS
says {"gen", "civil"} for all of these (no restriction documented in the
manual), but this session's evidence points to Civil-only in practice:
midas_nx.db.construction_stage.CamberConstructionStage(/db/CMCS)midas_nx.db.design.RebarCheckInput(/db/RCHK)midas_nx.db.misc_loads.PreCompositeSection(/db/PLCB)midas_nx.db.misc_loads.WaveLoad(/db/WVLD)midas_nx.db.project.Span(/db/SPAN)midas_nx.db.properties.section.EffectiveWidthScaleFactor(/db/EWSF)midas_nx.db.properties.section.SectionStressPoints(/db/STRPSSM)
Failed under Civil, succeeded under Gen (20) — same situation, opposite direction; evidence points to Gen-only in practice:
midas_nx.db.boundary.DiaphragmDisconnect(/db/DRLS)midas_nx.db.boundary.SeismicDeviceHystereticIsolator(/db/SDHY)midas_nx.db.boundary.SeismicDeviceIsolator(/db/SDIS)midas_nx.db.design.BeamRebar(/db/REBB)midas_nx.db.design.BraceRebar(/db/REBR)midas_nx.db.design.WallRebar(/db/REBW)midas_nx.db.project.Story(/db/STOR)midas_nx.db.static_loads.SoilProperty(/db/POSP)midas_nx.db.static_loads.StaticEarthPressure(/db/EPST)midas_nx.db.static_loads.StaticSeismicLoad(/db/SSEIS)midas_nx.db.static_loads.StaticWindLoad(/db/SWIND)midas_nx.design.rc_kds.rebar.ModifyBeamRebarData(/DESIGN/RC/KDS-41-20-2022/REBB)midas_nx.design.rc_kds.rebar.ModifyBraceRebarData(/DESIGN/RC/KDS-41-20-2022/REBR)midas_nx.design.rc_kds.rebar.ModifyColumnRebarData(/DESIGN/RC/KDS-41-20-2022/REBC)midas_nx.design.rc_kds.rebar.ModifyWallRebarData(/DESIGN/RC/KDS-41-20-2022/REBW)midas_nx.design.rc_kds.rebar.TorsionReductionFactor(/DESIGN/RC/KDS-41-20-2022/TRFT)midas_nx.design.rc_kds.setup.ModifyConcreteMaterial(/DESIGN/RC/KDS-41-20-2022/MATD)midas_nx.design.rc_kds.setup.UndergroundLoadCombinationType(/DESIGN/RC/KDS-41-20-2022/ULCT)midas_nx.design.src_aiksrc2k.SrcModifyMaterial(/DESIGN/SRC/AIK-SRC2K/MATD)midas_nx.design.steel_kds.UndergroundLoadCombinationType(/DESIGN/STEEL/KDS-41-30-2022/ULCT)
All URL paths above were double-checked character-for-character against the manual's own "Input URI" for each endpoint — none of these are SDK transcription bugs. The URLs are right; the routes just weren't reachable from the product tested against.
Write round-trip results (Gen)¶
- Model build (
MATL,SECT,NODE,ELEM,CONS): all 5 calls returned exactly the documented response shape, verified byte-for-byte against what was sent. - ch24–27 config-singleton
PUTendpoints (RcDesignCode,SteelDesignCode,SteelDesignCodeOption,ConcreteDesignCodeOption,SrcDesignCode,SrcDesignCodeOption): all succeeded, response echoed the payload under the documented top-level key (DCON,DSTL,DCO,DCORC,DSRC,SRCDCO). - ch24
DesignMemberAssignment.create(registers element 1 as design member 1): succeeded. - Operational nuance, not a bug: once a design member is registered,
the server auto-seeds a default per-member parameter record (e.g.
LENG) for that member ID in every currently-selected design-code namespace. Calling.create()(POST) on that ID afterward returns{"error": {"message": "Key Already Exist"}}inside a 200 response (not an exception —MidasClient.request()only raises on non-2xx status, so callers must check for an"error"key even on success). Calling.update()(PUT) instead succeeds and a subsequentGETconfirms the value round-trips exactly. Confirmed forsteel_kds.UnbracedLength,rc_kds.setup.UnbracedLength, andsrc_aiksrc2k.SrcUnbracedLength, all targeting the same RC element — this also confirms the server does real semantic validation rather than blindly persisting writes (steel/SRC-code member parameters were still accepted on a plain-concrete element in this test, so no rejection was observed there, but the "already exists" behavior itself is a genuine cross-code-namespace side effect worth knowing about).
Extended verification: Civil-only chapters + full analyze→results round-trip¶
Two more sessions were run after the initial pass above.
Civil write test — ch08 moving loads / ch17 bridge (previously untested)¶
Built a minimal Civil model (30 m single-span concrete beam: 1 material, 1 section, 2 nodes, 1 element, 1 fixed support), then:
MovingLoadCode.update(/db/MVCD,CODE="AASHTO LRFD"): succeeded.TrafficLineLanes.create(/db/LLAN) first attempt failed with a real server-side semantic validation error, not a schema rejection:"[Error] Line Lane Data (Name:Lane1) contains errors.(Item:Centrifugal Force ( 0.0 < Value < 1.0))". The manual documentsLANE_ITEMS.CENT_Fas merely "optional (AASHTO LRFD only)" — this session's evidence is that onceAASHTO LRFDis the selected moving-load code,CENT_Fis effectively required (must be a value in the open interval (0, 1); the SDK's implicit default of omitting the field, which the server reads as 0.0, is rejected). Retried withCENT_F: 0.1— succeeded, andGETread back every field including server-filled defaults (GROUP_NAME: "",SKEW_START/END: 0,WHEEL_SPACE: 0,OPT_AUTO_LANE: False,ALLOW_WIDTH: 0,FACT: 0,SPAN_START: False,ECCEN_VERT_LOAD: 0) — full round-trip confirmed once the semantically valid payload was sent. Not an SDK bug (the field genuinely is optional per the manual's schema, and the SDK correctly makes it optional in theTypedDict), but worth knowing if you hit the same error live: pass a nonzeroCENT_FwhenMVCD.CODEis"AASHTO LRFD".BridgeGirderDiagram.create(/db/GSBG) with a placeholderBODY_ELEM_GRUP_K: 1(no structure group with that ID actually existed): succeeded — the server did not validate the group reference exists at write time.
Gen full analyze → results round-trip (post/* chapters, previously only mocked)¶
Added a static load case (STLD, NAME="DL", TYPE="D") and self-weight
(BODF, FV=[0,0,-1]) to the Gen cantilever-column model from the first
pass, then:
doc.analyze()(/doc/ANAL) — first call (no loads yet) correctly failed with"[Error] Load information has not been entered for Analysis."; after adding the load case, succeeded ("MIDAS GEN NX command complete").post.result_1.get_reaction_table/get_displacement_table/ get_beam_force_table— first call usedload_case_names=["DL"]and got back{"message": ""}for all three (looked like "no data", but was actually a caller mistake).get_table's own docstring inpost/base.pyalready documents the fix: load case names need a type suffix, e.g."DL(ST)". Retried with["DL(ST)"]— all three returned full documented{FORCE, DIST, HEAD, DATA}tables.- The numbers are physically correct, not just structurally valid:
- Reaction at node 1 (base):
FZ = 28.243152— matches hand-calc self-weight of a 0.6×0.6×3.2 m C24 concrete column (0.36 m² × 3.2 m × ~24.5 kN/m³ ≈ 28.2–28.8 kN). - Displacement at node 2 (free top):
DZ = -0.000005m — negligible axial shortening under self-weight, correct sign (downward). - Beam force: axial force
-28.24 kNat the I-end (base), decreasing linearly to0.00at the J-end (free top) across the 4 reported stations — exactly the expected self-weight axial-force diagram for a vertical cantilever.
This confirms the full chain end to end: SDK request shape → real Gen NX
solve → SDK response parsing, for both the /db/* write side and the
/post/TABLE read side.
Civil full analyze → results round-trip, including moving-load envelope results (previously untested)¶
A later Civil session closed the remaining gap on the Civil side: static
analysis physically verified end to end, and — Civil's signature feature —
an actual moving-load analysis run and its (MV:max)/(MV:min) envelope
results read back and sanity-checked.
Static self-weight round-trip — physically verified¶
Built a 30 m, 2-span (3-node) simply supported... in practice fixed
against rotation at both ends (constraint string 1111100 restrains
RY at both supports, not a true pin) concrete girder (0.6×1.0 m
rectangular section, C24/KS01(RC)), added a DL self-weight load case,
ran doc.analyze(), then read back reactions/displacements/beam forces:
- Total self-weight reaction:
ΣFZ = 423.647281 kNacross both supports (211.823641each) — consistent with a uniformly distributed self-weight loadw = 423.647 / 30 = 14.12 kN/mon a0.6 × 1.0 msection. - Support moment
MY = ±1059.11825 kN·m— matches the fixed-end-moment formula for a fixed-fixed beam under UDL,wL²/12 = 14.12 × 30² / 12 = 1059.12— an exact hand-calc match. - Beam-force moment diagram across both elements' I/1/4/2/4/3/4/J stations
forms a consistent parabola between the two support end-moments and the
midspan value (
132.39), matching continuous-beam bending-moment theory.
Operational note, not a bug: one Material.create attempt with
STANDARD: "KS(RC)" failed with "Failed to get material data for:
C24" — the correct Civil concrete standard code turned out to be
"KS01(RC)", not "KS(RC)". The manual doesn't enumerate every valid
STANDARD string per material type/product, so this is a live-only
finding, not a schema contradiction.
Moving-load analysis — full chain verified, with real vehicle/lane data¶
Added MovingLoadCode (CODE="KOREA"), a Traffic Line Lane spanning both
elements, a DB-24 Korean standard vehicle, and a moving-load case
referencing both, then re-ran analysis:
Vehicles.create(/db/MVHL) initially no-op'd silently ({"message": ""}, not an error, and a subsequentGETconfirmed nothing was actually saved) whenVEH_DEFAULTwas sent as{}. The manual's own worked example forSTANDARD_CODE="KS-RB"always populatesVEH_DEFAULTwith explicitDYN_LOAD_ALLOWANCE/CENT_Fvalues even though the schema marks those fields "optional" — copying the manual's exact worked example (MVLD_CODE: 6,VEH_DEFAULT: {"DYN_LOAD_ALLOWANCE": 0, "CENT_F": false}) succeeded immediately. Worth knowing live: don't send an emptyVEH_DEFAULT: {}even though every one of its fields is individually documented as optional — populate it per the manual's worked example for yourSTANDARD_CODE.MovingLoadCase.create(/db/MVLD,TYPE=0general load referencing the vehicle + lane by name) — succeeded.doc.analyze()— succeeded in 2.0s (tiny model, no large-model delay here).get_beam_force_table(load_case_names=["MV1(MV:max)"])and["MV1(MV:min)"]— both returned full, real, non-degenerate envelope data: e.g. max positive midspan moment615.61–732.12 kN·m, min (most-negative) support moment-1702.53 kN·m(larger in magnitude than the plain self-weight case above, as expected — the DB-24 truck adds to the fixed-end moment at whichever support it's nearest). This is a believable, non-trivial moving-load envelope, not placeholder/zero data.
This confirms the full Civil-specific chain end to end: MVCD → MVHL →
LLAN → MVLD → doc.analyze() → post/TABLE with (MV:max)/(MV:min)
suffixes, previously only exercised as isolated writes (see the moving-load
write test above), not run through an actual analysis.
Operational quirk shared with the Gen findings: a confirmation dialog blocks the whole API session, not just one call¶
Partway through this session, MovingLoadCode.update (changing the active
moving-load code) triggered a Civil NX confirmation dialog ("changing
this will delete existing analysis results") that the user hadn't
dismissed yet. While that dialog sat open, every subsequent API call —
including totally unrelated ones like a plain GET /db/NODE — timed out
with no response, not just the call that triggered the dialog. After the
user dismissed the dialog, the session immediately became responsive
again, and a GET on the field that triggered it confirmed the change had
already persisted despite the client-side timeout.
This is the same shape of finding as the Gen CC-ANAL stall (an API call
blocks on an unacknowledged UI dialog, and the underlying change completes
and persists regardless of whether the HTTP response ever arrives) — but
milder and expected: a normal user-confirmation dialog is not a bug, and
it explains itself once you know to check for it. Worth knowing for
scripted/batch use of this API: any call that can trigger a confirmation
dialog (destructive/data-loss-risking changes) can make the entire session
appear hung until a human dismisses it, not just that one call.
⚠️ CONFIRMED — CC-ANAL (RC column code-check perform) reproducibly stalls Gen NX at "Converting Design Results 0%" (often requires a forced process kill)¶
STATUS UPDATE (2026-07-25):
CC-ANAL/BC-ANAL/WC-ANALran clean 4/4 — on the same build that hung here. This is not a "fixed in a newer build" story: both the reproductions below and the clean re-runs happened on Gen NX 2026 (v2.1), build 06/23/2026. The trigger is therefore something other than the build, and is still unidentified — so nothing in this section is retracted. See the re-verification section below.
While extending the same Gen session above to verify design-code check execution (as opposed to just config-singleton writes), the following sequence crashed/hung the Gen NX desktop application itself (not just an API error — the process stopped responding and required a manual restart):
design.rc_kds.setup.ModifyMemberType.create({1: {"TYPE": "COLUMN"}})— succeeded.design.rc_kds.rebar.ModifyColumnRebarData.create({1: {"ITEMS": [...]}})keyed by section number 1 (main bar D22×8, end/center hoop bars D10) — succeeded.- First
perform_column_check({"PERFORM_TYPE": "ALL"})(CC-ANAL) — failed cleanly with{"error": {"message": " Please perform analysis."}}(expected — design parameters changed after the last solve, invalidating results). - Re-ran
doc.analyze()— succeeded. - Retried
CC-ANAL— failed cleanly with{"error": {"message": "failed:LoadCombination"}}(also expected — no load combination existed yet, only a raw load case). - Added
db.load_combinations.LoadCombinationGeneral.create({1: {"NAME": "COMB1", "ACTIVE": "ACTIVE", "iTYPE": 0, "vCOMB": [{"ANAL": "ST", "LCNAME": "DL", "FACTOR": 1.2}]}})— succeeded. - Retried
CC-ANALa third time — this call never returned. Timed out client-side at both 30s (default) and 120s (explicitMidasClient(timeout=120)) withReadTimeoutError/ConnectionError— no HTTP response at all, not even a slow one. The user confirmed the Gen NX desktop application itself had stopped responding and needed a full restart.
Reproduction #2 — confirmed, with visual evidence¶
To rule out "messy session state" as the cause, the entire sequence was
redone from a fresh doc.new_project(), touching only RC design (no
steel_kds/src_aiksrc2k namespaces at all this time):
- Fresh minimal model (1 material, 1 section, 2 nodes, 1 element, 1
support, 1 static load case
DL, self-weight) +doc.analyze()— all clean. ModifyMemberType→COLUMN,ModifyColumnRebarData(same rebar payload as before),doc.analyze()again — all clean.CC-ANALbefore any load combination existed — failed cleanly and fast with{"error": {"message": "failed:LoadCombination"}}. Did not hang. This suggested the first hang might have been session-state related.- Manually written
db.load_combinations.LoadCombinationGeneralcombo —CC-ANALretried — failed cleanly and fast again with the same"failed:LoadCombination"message (the manually-enteredLCOM-GENentry apparently isn't recognized as a valid design combination by the RC check module — a separate, milder finding, see below). - Used
ope.generate_load_combination_concrete({"OPTION": "ADD", "DGNCODE": "KDS 41 20 : 2022"})instead — this is the right way to produce design-code-recognized combinations: it auto-generatedcLCB1(1.4(D),ACTIVE: "STRENGTH") andcLCB2(SERV:(D),ACTIVE: "SERVICE") in/db/LCOM-CONC. CC-ANALretried a third time, now with a real, code-recognized design combination in place — hung again, this time with a 40s explicit client timeout.- The user checked the Gen NX window directly and found a "Stop Design Thread" dialog, stuck at "Converting Design Results... 0%" with a "Stop Execution" button. Clicking Stop Execution did nothing — the dialog stayed frozen. The application had to be force-killed via Task Manager; there was no graceful recovery path.
Conclusion: this is a real, reproducible Gen NX application defect,
not session-state flakiness and not an SDK issue. CC-ANAL (RC column
code-check "perform") appears to spawn an internal "Design Thread" that
can deadlock during its "Converting Design Results" phase, and the
deadlock is unrecoverable from the UI (Stop Execution is on the same
stuck thread/message loop). The Open API call blocks synchronously
waiting for that thread, so from the SDK's perspective it just looks like
a network read timeout with no way to distinguish "still computing" from
"permanently stuck" short of an arbitrarily long timeout.
Reproduction #3 — confirmed a third time, on an unrelated large real-world model¶
To rule out "this only happens on a tiny synthetic 1-element model," the same pattern was tested against a separate, pre-existing production-scale Gen model (thousands of nodes/elements, real materials/loads/analysis results already present, different RC design code originally selected). Project-specific numeric details are intentionally omitted here — only the reproduction pattern matters:
- A read-only survey confirmed this model's active RC design code was
not KDS 41 20:2022, so its
rc_kds.setup(config-singleton) andrc_kds.rebar(member rebar) tables were empty for every member, despite the model already having real design-member registrations under a different code. CC-ANALon a real, verified-vertical concrete column element withPERFORM_TYPE: "ELEMS"(single element, not"ALL") — failed cleanly and fast:{"error": {"message": "failed:Rebar, BeamData"}}. No hang.- Assigned
ModifyMemberType(COLUMN) +ModifyColumnRebarData(same rebar shape as the earlier reproductions) for that element's section, re-randoc.analyze()(succeeded, no issue at this model's larger scale) — retriedCC-ANAL— failed cleanly and fast again:{"error": {"message": "failed:LoadCombination"}}(the model's 50+ pre-existing general load combinations were not recognized as valid design combinations, consistent with reproduction #2). No hang. - Ran
ope.generate_load_combination_concrete({"OPTION": "ADD", "DGNCODE": "KDS 41 20 : 2022"})— succeeded, auto-generated proper factored combinations from the model's real load cases. - Retried
CC-ANALa third time on the same single element — hung again, 40s client timeout, no HTTP response. The user confirmed Gen NX was frozen again and required another forced kill.
This is now the exact, minimal, deterministic trigger pattern across
three independent reproductions (one synthetic model, one real
production model tested twice): CC-ANAL hangs specifically once both
(a) the target element/section has member-type + rebar data assigned for
the KDS 41 20:2022 namespace, and (b) at least one load combination
exists that the KDS check module itself recognizes as a valid design
combination (i.e., one generated via ope.generate_load_combination_concrete
or equivalent, not a plain manually-written /db/LCOM-GEN entry). In
other words: it hangs at the exact moment the check has enough real data
to actually attempt the P-M-interaction calculation — every precondition
short of that fails fast and cleanly instead.
Do not call design.rc_kds.checks.perform_column_check (CC-ANAL)
against a live session with both preconditions satisfied, without an
escape plan (expect to force-kill Gen NX — "Stop Execution" does not
work). Given the shared "Design Thread" architecture across every other
perform_*_check/*-ANAL function in this SDK (perform_beam_check,
perform_brace_check, perform_wall_check in the same file;
perform_steel_code_check in steel_kds.py;
perform_src_beam_check/perform_src_column_check in
src_aiksrc2k.py; perform_optimal_design/OCHECK variants), treat
the entire "perform design check" family as carrying the same likely hang
risk once both analogous preconditions are met until each is
independently tested. This session did not attempt any of the others.
Reproduction #4 — cleanest case: a natively KDS-configured real model, no forced setup¶
A fourth session opened a separate, unrelated pre-existing Gen model whose
RC design code was already "KDS 41 20 : 2022" natively (not forced
onto it like reproductions #2/#3) — rc_kds.setup.ConcreteDesignCodeOption
and rc_kds.rebar.ModifyColumnRebarData already had real data (4 sections)
before any of this session's calls. This is the most realistic scenario
yet: a normal user, on a normal KDS-native model, checking one column.
CC-ANALon a real column element (PERFORM_TYPE: "ELEMS", single element) — failed cleanly:{"error": {"message": " Please perform analysis."}}.doc.analyze()via the API returned"MIDAS GEN NX command complete", but a subsequentget_reaction_table()call still reported"[empty] Cannot generate table data as there is no analysis result."— i.e. the API's "complete" acknowledgment did not reliably mean results were actually queryable yet on this larger model (4044 nodes). Re-running the analysis from the Gen NX GUI directly resolved this (reaction table then returned real data) — worth noting as a separate, milder finding: don't assumedoc.analyze()'s response means results are immediately queryable for large models; confirm with a cheap results call before proceeding, or retry.CC-ANALretried on the same element — the HTTP call hung again (40s timeout, no response), and the same "Stop Design Thread — Converting Design Results... 0%" dialog appeared. This time the user also checked Gen NX's internal message/log window while it was stuck, and it showed the entire check had already finished:
*** Start Code Checking by KDS 41 20 : 2022.
End preparing Design Informations.
End Design/Checking of Member.
Creating design result file...
End creating design result file.
End converting Design Results.
*** End Code Checking by KDS 41 20 : 2022
Every step, including "End converting Design Results" and the final "End Code Checking" line, had already logged as complete — while the progress dialog was still frozen at 0% on that same step. The user clicked Stop Execution; the dialog closed and the app recovered cleanly, no forced kill needed this time (unlike reproductions #1–#3, where an additional error popup appeared and the app had to be force-killed).
Revised diagnosis: this is very likely a stuck progress-dialog / stale completion-signal bug, not a genuine backend computation deadlock. The underlying KDS code check appears to actually finish — the message log says so explicitly, end to end — but something (the progress dialog's own close/refresh logic, and/or whatever signal the Open API layer itself waits on to consider the request "done" and return an HTTP response) never fires. That would also explain why the API call kept timing out even in this 4th case: it's plausibly blocked on the same stuck signal as the dialog, not on the design check itself. Reproductions #1–#3 didn't have this log checked at the time, so it's unconfirmed whether they were the same underlying issue or a genuinely different (deadlocked, not just signal-stuck) failure — worth checking the message log first thing if this is reproduced again.
Four for four on the stall itself; consequences vary. Every attempt
where the check had a real target element with real rebar data, a real
recognized load combination, and real analysis results triggered the same
"Converting Design Results... 0%" stall — including this cleanest case
with no artificial setup at all and, per the log, a design check that had
actually completed. That part is no longer a corner case; it's the
expected outcome of calling CC-ANAL for its actual intended purpose in
this Gen NX build. What differs is the outcome: an additional error popup
and a required forced kill 3 of 4 times, vs. a clean recovery via Stop
Execution (with the check apparently having already finished
successfully) the 4th time. Testing was stopped after this
reproduction — no further value in repeating it, and most attempts
still cost a forced restart or at least a stuck dialog.
Confirmed: the check result is actually there — CC-TABLE proves it¶
After reconnecting post-reproduction #4, get_column_check_table (CC-TABLE)
was called for the same element (371) that the "hung" CC-ANAL call had
targeted — it returned full, real design-check results:
CHK_STR: "OK", CHK_RBR: "OK", real P-M interaction ratios
(Rat_P: 0.468, Rat_M: 0.151), real assigned rebar ("28-6-D25"), real
shear/hoop-spacing checks — not placeholder or empty data. This
conclusively confirms the diagnosis above: the design check itself
genuinely completes and its results genuinely persist to the model, even
when the triggering CC-ANAL call times out with no HTTP response.
Practical workaround for callers: if perform_column_check (CC-ANAL)
times out or the connection errors, don't assume the check failed —
retry with get_column_check_table (CC-TABLE) for the same
element/section shortly after. The check very likely already ran to
completion; only the "done" acknowledgment got lost, not the work.
Reproduction #5 — retried with Gen NX run as Administrator: same result¶
To rule out a permissions/UAC-related cause, the user closed Gen NX, relaunched it with "Run as administrator," reopened the same natively-KDS-configured model from reproduction #4, and re-ran the full analysis from the GUI before retrying.
perform_column_check(CC-ANAL) on the same element (371) — the API call hung again, timing out client-side after 60s with no HTTP response (MidasConnectionError: ... Read timed out), and the Gen NX progress dialog stalled at "Converting Design Results... 0%" again, same as every prior reproduction.- The user waited briefly without clicking Stop, then clicked Stop Execution — the dialog closed and the app recovered cleanly, no forced process kill needed (matching reproduction #4's recovery behavior, not the forced-kill behavior of #1–#3).
get_column_check_table(CC-TABLE) for the same element immediately after — returned the identical full result set as reproduction #4 (CHK_STR: "OK",CHK_RBR: "OK",Rat_P: 0.468,28-6-D25, ...), confirming the workaround holds here too.
Conclusion: administrator privileges are not a factor. The stall, the Stop-Execution recovery path, and the CC-TABLE workaround are all identical running elevated vs. running normally — this rules out a UAC/file-permission explanation for the stuck dialog.
Build/localization confirmed: this is the English/international build,
not a Korean-localized one. All five reproductions were run against
Gen NX 2026 v2.1, English version — so the stall is not a
Korean-UI-localization artifact; it reproduces on the same build
international users install. What remains genuinely untested is the
design-code axis: every reproduction used KDS 41 20 : 2022
specifically. It's still an open question — not tested here — whether the
same "Converting Design Results 0%" stall occurs for non-Korean design
codes (AISC, Eurocode, etc., via steel_kds.py or other design/*
modules) or is somehow specific to the KDS check module's own
implementation. Don't generalize "every perform_*_check call hangs" past
KDS 41 20:2022 without independent testing of another code.
perform_wall_check (WC-ANAL) — tested, does NOT reproduce the stall¶
Using a sixth session (a separate, wall-heavy Korean production model, KDS
41 20:2022 native, with pre-existing real wall-check results already present
from prior GUI use — WID/Story/WallMark rows like 101/B1/RW1
with real CHK_STR: "OK" data), perform_wall_check was tested for the
first time:
- Single wall/story (
SELECTIONS: [{"WALL_IDS": {"KEYS": [101]}, "STORY": ["B1"]}]) — returned{"message": "success"}in 3.5s. No stall. - All walls/stories (
SELECTIONSomitted) — returned{"message": "success"}in 5.9s. No stall.
WC-ANAL does not reproduce the CC-ANAL stall, at least on this
model, in either single-target or full-scope form. This is useful negative
evidence: whatever's stuck in the column-check "Design Thread" progress
dialog is not a blanket property of every perform_*_check function in
this file — it may be specific to CC-ANAL (or to the member-based
ELEMS/SECTIONS-targeted check family: beam/column/brace, vs. the
WID+STORY-targeted wall check, which may run through different internal
code entirely). Don't assume perform_wall_check carries the same risk as
perform_column_check going forward.
perform_beam_check (BC-ANAL) — CONFIRMED to hang too, on two separate models, with a new crash variant¶
Same wall-heavy-model session, real beam rebar data already present
(ModifyBeamRebarData had entries for elements 11, 12, 13). Walked
the same precondition sequence as the CC-ANAL reproductions:
BC-ANALon element 11 before member type was registered in this design-code namespace — failed cleanly and fast:{"error": {"message": "failed:Rebar"}}(ModifyMemberType.get()was empty for this namespace even though rebar data existed — same "each precondition fails independently and cleanly" pattern as the column reproductions).ModifyMemberType.update({11: {"TYPE": "BEAM"}})— succeeded.BC-ANALretried — failed cleanly:{"error": {"message": " Please perform analysis."}}(member-type change invalidated prior results, same as CC-ANAL reproduction #1/#4).doc.analyze()via the API — timed out after 90s with no response. This one was just a genuinely long-running solve on this large model (4000+ nodes), not the progress-dialog bug — the user confirmed Gen NX's own progress UI was actively solving, not stuck. See the timeout-guidance note below. After the user re-ran analysis from the GUI and confirmed it completed,BC-ANALwas retried:BC-ANALretried a third time on element 11 — hung again, 60s client timeout, no HTTP response. This time the user reported the Gen NX app itself looked normal (no visible stuck dialog) — butget_beam_check_table(BC-TABLE) for that same element also then hung repeatedly (multiple retries, up to 30s each), whileBC-TABLEfor a different, nonexistent element (12 — actually absent from this model, confirmed by the clean fast"Element 12 does not exist."response) returned instantly. Basic connectivity (GET /db/NODE) also remained fully responsive throughout. This points to something specifically locked/stuck server-side scoped to that element's beam check state, even without a visibly stuck dialog — consistent with the "stuck signal, not a real deadlock" diagnosis, just manifesting without an obvious UI symptom this time.
A second, independent model was then opened to rule out anything
specific to the wall-heavy model: a real production Taiwan RC frame
("rahmen") structure, 315 nodes / 564 elements, active design code
TWN-USD112 (not KDS — so, like reproduction #3, the KDS module's own
MBTP/REBB tables were empty and had to be populated directly, which
the API allowed with no validation against the model's "actual" active
code, consistent with prior findings):
ModifyMemberType.update({1: {"TYPE": "BEAM"}})(element 1, a realTYPE: "BEAM"element, section 11) — succeeded.ModifyBeamRebarData.update({11: {"ITEMS": [...]}})(keyed by section number 11, matching element 1'sSECT) — succeeded.doc.analyze()— this model is much smaller; completed in 16.4s, and a subsequentget_reaction_table(load_case_names=["DL(ST)"])call confirmed real, queryable results immediately (no large-model delay this time).ope.generate_load_combination_concrete({"OPTION": "ADD", "DGNCODE": "KDS 41 20 : 2022"})— succeeded, generated a full set of KDS strength combinations (cLCB1..cLCB7+) from this model's real load cases (DL,LL,EXN,EXP,EYN,EYP,EZ,WX,WY).BC-ANALon element 1, all preconditions now satisfied on this fresh model — hung again, 60s client timeout, no HTTP response.- This time the user reported the exact text of the crash dialog for the
first time — "[Error] Failed to disconnect the work session due to an
unidentified error. Since you have not logged out, other PCs may have
limited access to the license. In order to properly terminate the
program, try to re-execute the program, press 'New Project' and then
close the program." — and the application crashed/closed. The user
confirmed this is the same popup that appeared during the earlier
forced-kill
CC-ANALreproductions (#1-#3) — it just hadn't been transcribed verbatim before (previously logged generically as "an additional error popup"). The user's stated rule: whenever this specific license-work-session-disconnect popup appears, the program always dies — there is no recovering from it. This is a different, worse outcome than the clean "Stop Execution" recovery seen in reproductions #4/#5 (where this popup did not appear at all).
This confirms BC-ANAL shares CC-ANAL's hang, on two independent
models (one forced-KDS-setup wall-heavy Korean model, one forced-KDS-setup
Taiwan RC frame model), both under the same precondition pattern
(member-type + rebar assigned in the KDS namespace, a KDS-recognized load
combination present, confirmed-queryable analysis results). Combined
with the earlier CC-ANAL reproductions, the observed outcomes now form
two consistent buckets rather than random variation: (a) the "Converting
Design Results" dialog gets stuck but recovers cleanly via Stop Execution,
no popup, no crash (CC-ANAL reproductions #4/#5) — the check likely did
finish and its results persist (confirmed via CC-TABLE); or (b) the
"Failed to disconnect the work session" license-error dialog appears
and the program crashes outright, unrecoverable (CC-ANAL reproductions 1
through 3, and this session's Taiwan-model BC-ANAL reproduction). This
raises the severity of the underlying MIDASIT bug report beyond "a stuck
progress bar" — outcome (b) is a licensing-visible crash that, per the
dialog's own text, may affect other PCs' access to the license until the
process is fully terminated.
This exact crash signature has a prior precedent — it isn't new to v2.1¶
A separate, earlier round of live MIDAS Gen NX Open API testing (same
account, a different local project, pre-v2.1 build) independently hit the
identical "Failed to disconnect the work session..." crash text —
from a completely different trigger: calling doc/new rapidly and
repeatedly (back-to-back x10, concurrent x5/x15). That round's writeup
retested the doc/new trigger specifically against the v2.1 build and
found it no longer reproducible, and closed it out as resolved,
concluding the original crash was "limited to a previous build or a
specific sequence." This session's CC-ANAL/BC-ANAL reproductions
show that conclusion was premature — the same crash signature, verbatim,
resurfaces under a different trigger (a design-check "perform" call) in
the same v2.1 build. This is valuable context for framing a MIDASIT bug
report: not a one-off, but a recurring session-teardown defect that keeps
resurfacing under different trigger conditions across builds and across
independent testing sessions — worth reporting as a class of bug rather
than a single reproducible steps list tied to one endpoint.
Useful diagnostic tool for next time: that same earlier round
identified GET https://moa-engineers.midasit.com:443/mapikey/verify
(note: base URL with the product path — /gen or /civil — removed) as a
live-verified health-check endpoint, undocumented in the vendored manual,
that reliably distinguishes "AWS relay server alive, Gen NX process alive"
(status: "connected") from "AWS relay alive, Gen NX process died"
(other endpoints then return HTTP 404 with "Client Disconnected" /
"client does not exist", while /mapikey/verify itself still resolves
against the relay). This wasn't used during today's reproductions — relied
on the user's visual confirmation of the Gen NX window instead — but would
give a definitive, scriptable way to confirm process death vs. a merely
slow/busy session in future reproductions, without waiting on manual
screen-watching.
perform_wall_design (WD-ANAL) — CONFIRMED to hang too, even though the sibling perform_wall_check (WC-ANAL) does not¶
Same wall-heavy model, same wall (WID 101, Story B1) already confirmed
clean under WC-ANAL. perform_wall_design (a different endpoint,
manual item #48, WD-ANAL — RC Wall Design Perform, distinct from
WC-ANAL's RC Wall Check Perform, item #63) was tested for the first
time:
- First attempt — failed cleanly and fast:
{"error": {"message": " Please perform analysis."}}. Unrelatedsteel_kds/src_aiksrc2kmember-type writes made earlier in this session (while probing whether other design-code modules share theCC-ANALbug — see above) apparently invalidated the model's analysis results, consistent with the established "any design-parameter write invalidates results" pattern. - Re-ran
doc.analyze()— completed in 151.3s (large model, expected per the timeout-guidance note below, not a stall). WD-ANALretried on the same wall/story — hung, 60s client timeout, no HTTP response. The user checked Gen NX and reported the app looked completely normal — no visible stuck dialog this time either.get_wall_design_table(WD-TABLE) for the same wall/story — returned full, real design results immediately (Pu: 126.106,Rat-Py: 0.748,phiVn: 1804.81,Rat-V: 0.634, real rebar"D13 @300"/"D10 @190",CHK: "OK"). Same workaround asCC-ANAL: the design computation completed and persisted; only the HTTP acknowledgment never arrived.
Separate schema finding, unrelated to the hang: the manual documents
WD-TABLE's response as {"data": {"COMPONENTS": [...], "ROWS": [{col:
val, ...}, ...]}} (with a worked example iterating data["ROWS"]), but
the live response above came back in the same {"Result Table": {"FORCE":
..., "DIST": ..., "HEAD": [...], "DATA": [[...], ...]}} HEAD/DATA shape
every other member-check table in this chapter uses. Confirmed by
re-reading the manual's own JSON Schema and worked example for this
endpoint side by side with the live response — this isn't a caller
mistake. get_wall_design_table's docstring now flags this.
This means the earlier "WID+STORY-targeted checks are safe" hypothesis
(based on WC-ANAL alone) was wrong — WD-ANAL is also WID+STORY-
targeted and still hangs. The safe/unsafe split isn't about the targeting
scheme (ELEMS/SECTIONS vs WID/STORY); perform_wall_check
(WC-ANAL) remains the only tested "perform" function in this file so far
that does not reproduce the stall — perform_column_check,
perform_beam_check, and now perform_wall_design all do, across every
model tested. What distinguishes WC-ANAL from the other three is still
unclear — possibly that a wall "check" only reads/verifies existing rebar
against demand, while WD-ANAL/CC-ANAL/BC-ANAL all compute and
write new required-design data back into the model (rebar layout,
member-check parameter records) — but this is a hypothesis, not confirmed.
Other design-code modules (steel_kds, SRC) — inconclusive, blocked by license/model limitations, not evidence either way¶
While looking for a fast way to test whether the CC-ANAL-style stall
extends beyond the RC-KDS module, two other design-code "perform check"
families were attempted on the same wall-heavy model and both were blocked
before reaching the actual "perform" call, for reasons unrelated to this
bug:
steel_kds.perform_steel_code_check: blocked at the load-combination step —ope.generate_load_combination_steelreturned{"error": {"message": "There is no license to use the specified Steel Design Code."}}. A real license limitation, not a bug; this account/model cannot exercise the steel design-check module at all.- SRC (
src_aiksrc2k): the design code itself is licensed (ope.generate_load_combination_srcsucceeded), butSrcBeamSectionData(the rebar-equivalent registration for SRC composite beams) returned{"error": {"message": "Unknown Error"}}on every attempt, andSrcModifyMaterialwrites didn't appear to persist (GETcame back empty afterward). Likely cause: every section in this model is a plain rectangular RC shape (SB) — SRC (steel-reinforced-concrete composite) design plausibly requires an actual composite section geometry that doesn't exist anywhere in this model, unlike the RC-KDS rebar overlay which worked on any section regardless of the model's "real" design code.
Neither result says anything about whether steel/SRC "perform check"
calls share the CC-ANAL stall — both were blocked upstream of the
precondition chain this file's other reproductions establish as necessary
(member type + rebar/section data + recognized load combination +
queryable analysis results). Testing this properly would need a model with
real steel or SRC composite members, not a forced setup on an RC-only
model. Left as a genuinely open question.
Timeout guidance for doc.analyze() on large models — a separate, milder finding¶
While waiting on step 4 above, it became clear a plain client-side read
timeout on doc.analyze() is not by itself evidence of a hang — on a
4000+ node model, analysis can legitimately take longer than
MidasClient's default 30s timeout (observed: still running past 90s,
with the user confirming Gen NX's own progress UI showed it actively
solving, not stuck). Don't conflate this with the CC-ANAL stuck-dialog
bug — that one is confirmed via the message log to have a specific
"finished but dialog didn't update" signature; a slow doc.analyze() on a
big model is just... slow. Pass a larger MidasClient(timeout=...) for
big-model analysis calls rather than treating a timeout as failure.
Practical takeaway for this SDK: nothing to fix in midas-nx itself —
every request shape sent was correct per the manual (confirmed by the
clean, correctly-shaped {"error": ...} responses on every call that
didn't hang, across four separate reproductions on three different
models), and the SDK has no way to add a client-side guard against a
server-side dialog/signal bug it can't see. This is a confirmed,
reproducible Gen NX application defect worth reporting to MIDASIT
directly — most usefully framed as "the KDS column-check progress dialog
gets stuck at 'Converting Design Results 0%' even after the message log
shows the check completed, and the Open API call that triggered it never
receives a response either," together with this file's exact precondition
pattern (member-type + rebar assigned, plus a KDS-recognized design load
combination present, plus confirmed-queryable analysis results) —
reproduced 4 for 4 times that all conditions were met, across a trivial
synthetic model, a production-scale model (twice), and a natively
KDS-configured production model.
Repeatable smoke test — scripts/live_smoke.py (2026-07-22)¶
Everything above was run by hand, one call at a time. This session turned
the core write → analyze → read round trip (new project, unit, material,
section, node, element, support, load case, self-weight, doc.analyze(),
reaction/displacement/beam-force tables, checked against a hand-calc) into
scripts/live_smoke.py, then ran it fresh against both a live Gen NX and a
live Civil NX session (same MIDASIT account, both freshly reset via
/doc/NEW). Both runs succeeded end to end and reported
reaction_matches_hand_calc: true. Confirmed builds (via each app's
About/도움말 dialog): MIDAS Gen NX 2026 (v2.1), build 06/23/2026 and
MIDAS Civil NX 2026 (v2.1), build 06/05/2026 — the same v2.1 line as
the English-build Gen NX used in the CC-ANAL/BC-ANAL reproductions
above, now with an exact build date on record for the first time.
docs/coverage.json now tags the ten endpoints this script exercises
(/doc/NEW, /doc/ANAL, /db/UNIT, /db/MATL, /db/SECT, /db/NODE,
/db/ELEM, /db/CONS, /db/STLD, /db/BODF) with a "live_verified"
field carrying this date and both builds; ROADMAP.md surfaces the count
and a Gen/Civil build matrix generated from it (PLAN.md's D4).
New findings from this run, beyond what's already recorded above:
- The
/post/TABLEresponse's top-level key is not stable across sessions. Earlier findings in this file saw it as"Result Table"; this session got back the literal string"empty"for the same reaction/displacement/beam-force calls (withtable_nameleft at its default""). Don't hardcode either key —scripts/live_smoke.py's_find_head_data()scans the response's values for the first dict containing both"HEAD"and"DATA"instead, which is robust across whatever this key turns out to be call-to-call. - A 200 response can carry an
{"error": ...}body even from aDbResource.create()call, and this is easy to miss if a caller only checks the HTTP status.live_smoke.py's first draft didn't check for this and silently treated a failedConstraint.create()as successful — the fix (checking for an"error"key in every 2xx body) is the same pattern already noted above for design-code "already exists" responses; worth treating as a general rule for everyDbResource/doc.*call, not just the design-code family. - Gen's concrete
STANDARDcode for C24 is"KS01(RC)", same as Civil — confirmed by first trying the plausible-looking"KS(RC)"on Gen, which failed with{"error": {"message": "Unknown Error"}}(an unhelpful message with no hint about the actual problem being the standard-code string), then retrying with"KS01(RC)", which succeeded immediately. The manual doesn't enumerate validSTANDARDstrings per product, so — as with the original Civil finding above — this is a live-only data point, not a schema contradiction. - Physically-grounded cross-check, both products: a 0.6×0.6 m, 3.2 m
tall C24/KS01(RC) cantilever column's self-weight reaction came back as
FZ = 27.113426 kNon both Gen and Civil (byte-identical, same model) — about 4% below a naive hand-calc using a generic 24.5 kN/m³ unit weight (0.36 m² × 3.2 m × 24.5 ≈ 28.22 kN), implying MIDAS's actualC24/KS01(RC)preset unit weight is closer to27.113 / (0.36 × 3.2) ≈ 23.53 kN/m³. Useful reference point for anyone else hand-calc-checking a KS01(RC) C24 model;scripts/live_smoke.pyuses a 5% tolerance for exactly this reason rather than an exact-match assertion.
STATUS UPDATE (2026-07-25) — CC-ANAL/BC-ANAL ran clean on the same build that hung¶
The *-ANAL design-check stall documented at length above — the single
most severe finding in this file, reproduced across three models and five
attempts, and the reason every perform_* docstring in design/ carried a
"treat as a hang risk" warning — did not reproduce in a later round of
live use. Critically, this is not a "fixed in a newer build" story.
Source of this finding. Unlike the rest of this file, this did not come
from a dedicated SDK test session. It comes from QuickRebar NX
(rebar-repair.vercel.app), a separate production web tool by the same
author that drives the same Gen NX Open API endpoints over HTTP. Its own
project notes record a live re-test on 2026-07-25 that ran:
CC-ANAL— including the whole-modelPERFORM_TYPE: "ALL"variant, the exact shape that reproducibly killed the app in the reproductions aboveBC-ANAL— the beam equivalent, also previously confirmed to hangWC-ANAL— the wall check, which never reproduced the stall anyway
4 out of 4 clean, with the app staying connected throughout.
PERFORM_TYPE: "ALL" re-checks an entire model in roughly 2 seconds. The
tool now ships BC-ANAL wired to a user-facing "Gen NX 재검토" button,
followed by a BC-TABLE read of CHK_STR / Rat-N / Rat-P / Rat-V —
i.e. this is not a one-off lab result but an endpoint running in a
deployed tool against real users' models.
⚠️ The build did not change — so the trigger is still unidentified¶
The About dialog was checked on 2026-07-25 and reports MIDAS Gen NX 2026
(v2.1), build 06/23/2026 — byte-for-byte the same build recorded for the
CC-ANAL/BC-ANAL reproductions above and for the 2026-07-22 smoke test.
The same binary both hangs and does not hang.
That rules out the most comforting explanation (a vendor patch) and leaves the actual variable unknown. Plausible candidates, none of them tested:
- Model state. The reproductions established a precondition chain
(member type + rebar + a KDS-recognized load combination, the last one
generated via
ope.generate_load_combination_concreterather than a hand-written/db/LCOM-GEN) and hung at the exact point the check had enough real data to attempt the P-M calculation. Whether the QuickRebar models satisfied that same chain was never checked. - Call sequence. The reproductions ran the check immediately after API-side writes of member-type/rebar data; the tool's flow may differ in ordering or in how much settles first.
- Client/transport. Python
requestsfrom a local machine vs. Nodefetchfrom a Vercel serverless function — different timeouts and connection handling against the same relay. - Genuine intermittency in the trigger. The defect was already known to be intermittent in its consequences (forced kill 3 of 5 times, clean "Stop Execution" recovery the other 2). Intermittency in the trigger itself was assumed absent, but four clean runs do not disprove it.
Nothing in the reproduction sections above is retracted. The correct reading is "this is not universal and not always triggered," not "this is fixed."
What this does and does not license¶
| Endpoint | Earlier status (build 06/23/2026) | 2026-07-25 (same build) |
|---|---|---|
CC-ANAL (column check) |
hung 5/5 | ✅ clean 4/4 |
BC-ANAL (beam check) |
hung on 2 models | ✅ clean |
WC-ANAL (wall check) |
never hung | ✅ still clean |
WD-ANAL (wall design) |
hung | ❓ not re-tested |
BRC-ANAL, steel CODE-ANAL, SRC *-ANAL, OCHECK |
never tested | ❓ not re-tested |
One further limit on the evidence: KDS 41 20:2022 only. Every test on
both sides of this — the original reproductions and the re-verification —
used the KDS RC design code. Nothing here says anything about the steel
(steel_kds.py), SRC (src_aiksrc2k.py), or non-Korean code paths.
Keep the defensive pattern — this is now the main takeaway¶
Because the trigger is unidentified rather than removed, the defensive pattern is not optional hygiene; it is the actual mitigation. The production tool wraps these calls this way, and the SDK's docstrings recommend the same:
- Short timeout on the
*-ANALcall (the tool uses 25s). - Read the
*-TABLEback regardless of whether*-ANALreturned. This was the confirmed workaround during the hang era — a timed-out check had usually completed and persisted anyway — and it remains the correct shape for a call whose HTTP acknowledgment is known to be unreliable. - Prefer reading
*-TABLEalone when possible. Design results the user already computed in Gen NX's own GUI are readable with no perform call at all. That path never carried any of this risk and is still the zero-risk option.
Why the docstrings kept the history¶
The perform_* docstrings in design/ now lead with this re-verification
rather than the old "never call this" rule, but they retain a compressed
version of the reproductions. That is deliberate, and the same-build
finding above is why: this exact crash signature ("Failed to disconnect
the work session...") has now resurfaced twice under different triggers
— once via rapid doc/new calls on a pre-v2.1 build, once via *-ANAL on
v2.1 — and was declared resolved after the first. Treating "did not
reproduce" as "fixed" is the mistake this file has already recorded once,
and the first draft of this very section repeated it by assuming a newer
build was responsible before the About dialog was actually checked.
2026-07-26 — read-only sweep reproduced on a real model, same build¶
Re-ran the whole GET surface with the new scripts/live_readonly_sweep.py
(read-only; safe against an open document, unlike live_smoke.py) against a
real production model — 710 nodes, 1272 elements, 60 sections, with
analysis results already present — on the same build as the 2026-07-22
session (Gen NX 2026 v2.1, build 06/23/2026).
| 2026-07-22 (blank model) | 2026-07-26 (710-node model) | |
|---|---|---|
| GET-capable Gen resources swept | 253 | 253 |
| Answered | 233 | 233 |
| Failed (all 404) | 20 | 20 |
Civil NX 2026 (v2.1), build 06/05/2026 was swept the same day and also reproduced exactly — 293 swept, 273 answered, 20 404s. The Civil session had a near-empty document (2 nodes, 1 element), so unlike the Gen run it is a same-conditions repeat, not a different-model one.
The failing 20 are the same 20 endpoints, all MidasNotFoundError 404:
the 13 Hyper-S -M1 routes plus CMCS, EWSF, PLCB, RCHK, SPAN,
STRPSSM, WVLD. Run twice in the same session, byte-identical both times.
What this does and does not settle:
- Model state is eliminated as an explanation. The two sessions differ in everything about the document — empty vs. a real analyzed structure — and the failure set did not move by one endpoint.
- License tier is not. Same MIDASIT account, same license/edition, same
build. Per this file's own caveat below, that is not yet the "different
account" trigger, so
PRODUCTSwas left unchanged for the 7 Gen-fails/Civil-succeeds classes. This section is the second data point; a third from a different account or license would be the one to act on. - Results recorded per endpoint in
docs/coverage.json(live_verified), taking the count from 10/390 to 235/390.
Hyper-S is Civil NX only — the SDK's PRODUCTS was wrong¶
Running both products the same day made this unmissable:
Hyper-S (-M1) endpoint family |
Gen NX 2026 v2.1 | Civil NX 2026 v2.1 |
|---|---|---|
Implemented -M1 endpoints |
13/13 → 404 | 13/13 → answered |
Undocumented -M1 stubs |
8/8 → 404 | 8/8 → answered |
/db/ACTL-M1 returned a populated row under Civil, not just an empty table,
so these are live routes rather than registered-but-inert ones.
Confirmed by the project author: Hyper-S is the name MIDASIT gave the
solver introduced with the Civil NX release. It is a Civil NX product
feature, so the Gen 404s were correct all along and the SDK's
PRODUCTS = {"gen", "civil"} was the defect. All 21 -M1 rows (13
implemented + 8 stubs) are now Civil-only, via a dedicated HYPER_S_ONLY
constant in db/base.py and a parametrized guard in
tests/db/test_hyper_s_products.py.
This one is expected to change again. The author notes Hyper-S may reach
Gen NX in a future release. That is why it is its own constant rather than
CIVIL_ONLY: when it happens, widen HYPER_S_ONLY and re-run
scripts/live_readonly_sweep.py --product gen to confirm, instead of
treating the current state as permanent.
Note this changes the Gen failure accounting for the better. Of the 20 Gen
404s, 13 were never SDK-callable errors at all — they were Civil-only
endpoints the SDK wrongly offered to Gen clients. With PRODUCTS corrected,
a Gen sweep covers 240 endpoints with 7 unexplained 404s (CMCS,
EWSF, PLCB, RCHK, SPAN, STRPSSM, WVLD), and a Gen client now
raises ProductMismatchError before issuing a doomed request.
The 8 "un-transcribable" Hyper-S stubs are introspectable after all¶
docs/coverage.json carries 8 -M1 rows as planned, not implemented,
because the manual gives a URL, methods and a Zendesk link but no JSON
Schema — and this project's v1.0.0 gate has been waiting on exactly that.
Against a live Civil session, all 8 answer a plain GET, and 5 return a
field-level schema from /info/db/...:
| Endpoint | /info/db/... |
Top-level fields |
|---|---|---|
/db/STYP-M1 |
schema | STYPE, GRAV, TEMP, ALIGNBEAM, ALIGNSLAB, MASS_CONTROL |
/db/MATL-M1 |
schema | MATL_NAME, MATL_TYPE, DAMP_RAT, PARAM |
/db/IMFM-M1 |
schema | CONCRETE, STEEL |
/db/EPMT-M1 |
schema | NAME, MODEL_TYPE, TRESCA, VMISES, MOHRCL, DRUCKER, MASONRY, CONCDMG |
/db/IEHG-BEAM-M1 |
schema | INEL_PROP_NAME |
/db/IEHG-TRUSS-M1 |
404 | GET works, no schema route |
/db/IEHG-GL-M1 |
404 | GET works, no schema route |
/db/IEHG-PSS-M1 |
404 | GET works, no schema route |
/db/STYP-M1 and /db/MATL-M1 also returned real data ({"STYPE": "3D",
"GRAV": 9.806, ...}, {"MATL_NAME": "C24", "MATL_TYPE": "CONC", ...}).
This does not make them transcribed — server introspection is a different
source from the manual, and DbResource.info()'s docstring already frames it
as a fallback rather than a substitute. But the v1.0.0 gate's premise, that
these are "genuinely not transcribable without depending on an external,
non-versioned source", no longer holds: the server itself is the source, and
it is the same server the SDK talks to. Deciding whether that clears the gate
is a call for the author, not something this file should assume.
The {"message": ""} zero-row shape is the common case, not an edge case¶
Of the 233 endpoints that answered, 176 returned {"message": ""} and only
57 returned the keyed {"<KEY>": {...}} shape — on a fully populated model.
A zero-row table is the normal state for most endpoints because a given model
uses a small fraction of the API surface. This matters more than it looks:
DbResource.items() assumed the keyed shape and raised AttributeError on
the string value, so before v0.12.0 that helper failed on roughly three
quarters of the endpoints it was supposed to serve. Fixed in v0.12.0.
/post/TABLE's unstable top-level key, explained¶
Earlier sessions recorded the response key varying between TABLE_NAME,
"Result Table", and "empty" with no known trigger. It is simply the
default: omit or blank TABLE_NAME and the server keys the response
"empty"; pass a name and you get that name back. Same call, same 78 rows
of real data, both ways:
get_story_drift_table(STORY_DRIFT_X) -> keys=['empty'] rows=78
get_story_drift_table(STORY_DRIFT_X, table_name="Drift") -> keys=['Drift'] rows=78
"empty" is not an error marker — it carried a full table here. Matching on
shape (post.base.unwrap_table(), v0.12.0) remains the right approach, since
this doesn't explain the "Result Table" sighting, but "empty means no data"
is a wrong inference to guard against.
HTTP 200 with an error body — reproduced deliberately¶
Sending an unknown TABLE_TYPE returns HTTP 200 with:
This is the failure mode the client silently returned as a result until
v0.12.0; it now raises MidasResultError. Confirmed against the live server,
not just reasoned from the docs.
Two practitioner traps found while probing¶
- An invalid load-case name is not an error.
get_reaction_table( load_case_names=["NoSuchCase(ST)"])returned{"message": ...}with zero rows — after 23 seconds. Nothing distinguishes "wrong case name" from "genuinely no results" in the response, so validate case names against/db/STLDbefore trusting an empty table. - Unfiltered result tables can exceed a sane timeout. The beam-force
table for all 1272 elements timed out at 30s; the same table filtered to a
single load case returned 6350 rows in 2.2s. The displacement table came
back at 4.1 MB / 39760 rows. Pass
load_case_namesrather than raising the timeout.
2026-07-26 — write verification on Civil NX, and a table-destroying bug¶
First session with permission to create, modify and delete freely on Civil NX
2026 (v2.1), build 06/05/2026. scripts/live_crud_check.py was written for it:
create → read back → update → read back → delete → confirm gone, per resource.
Read sweeps prove an endpoint answers; only this proves the SDK's write
shapes are the ones the server accepts.
🛑 DbResource.delete([id]) was deleting the entire table¶
The single most serious defect found so far, and it was invisible to every
mocked test in tests/.
For /db/NODE this also takes out every element attached to those nodes, so
one delete() call empties a model. It surfaced by accident: the CRUD run
deleted one throwaway node, and the seeded model was gone afterwards.
The SDK was following the manual exactly. 03_DB_Node_Element.md documents
DELETE /db/NODE with {"Assign": {"4": None}}, and db/base.py had reasoned
carefully about None vs {} across chapters. Both forms behave the same way
live, and neither one respects the ids:
| Request | Result |
|---|---|
DELETE /db/NODE + {"Assign": {"3": null}} |
table emptied |
DELETE /db/NODE + {"Assign": {"3": {}}} |
table emptied |
DELETE /db/NODE + {"Assign": {"2": {}, "3": {}}} |
table emptied |
DELETE /db/NODE/3 |
only node 3 removed, and returned |
The per-id URL is undocumented — db/base.py explicitly declined to invent it
("no documented per-ID URL filtering across the manual, so we don't invent
one"). It works, and it is the only form that does what delete() claims.
Verified on /db/NODE, /db/STLD, /db/LDGR and /db/MATL; deleting an id
that doesn't exist is a harmless no-op returning {"message": ""}.
Fixed in v0.14.0: delete() issues one DELETE {endpoint}/{id} per id, and
the whole-table behaviour is kept under the name delete_all().
Two more "a 200 is not success" variants¶
v0.12.0 taught the client to reject a 2xx carrying {"error": ...}. Writing
turned up two cases that slip past it:
/doc/ANALreports a failed solve as{"message": "MIDAS CIVIL NX Analysis failed."}— the samemessagekey a successful call uses for"... command complete", with noerrorobject anywhere. Every result table then comes back empty with nothing explaining why.doc.analyze()now inspects that message; the check is deliberately not in the client, sincemessageis the normal success carrier elsewhere./doc/SAVEASreturns{"message": "... command complete"}for a save that did not happen. Given a path NX rejects it raises a modal "잘못된 경로가 있습니다" dialog, blocks the session until someone clicks it, and then answers with the success string. No file on disk. There is no way to tell success from failure from the response — check the filesystem.
Note also that error bodies arrive under 201 as well as 200
(POST /db/CONS → 201 + {"error": ...}), so any check keyed on the status
being exactly 200 misses them.
verify_connection() cannot detect a blocked session¶
While a dialog was up, /mapikey/verify answered {"status": "connected"}
in milliseconds while every /db/* call timed out. The health check is served
by the relay, not by the blocked application. It tells you the process is alive
and the key is valid — it does not tell you the app can currently answer.
Field-level findings from the round trips¶
/db/CONS'sCONSTRAINTmust be exactly 7 characters. Six is rejected outright; eight is accepted and silently truncated to seven, giving a support that was never requested with no error raised./db/STLDignores the"Assign"key and renumbers. Posting under key7produced record2(NO: 2), the next free slot./db/NODEhonours the key exactly (posting under77yields node77). So the ID-keyed convention is not uniform, and code that writes a record and then reads it back by the key it sent will miss for load cases.create()is not an upsert. Re-posting an existing key returns201with{"error": ...}"Key Already Exist".
Round-trip results: Civil 10/10, Gen 9/9 (/db/MVCD is Civil-only and
correctly skipped there) across /db/GRUP, /db/BNGR, /db/LDGR,
/db/NODE, /db/SKEW, /db/STLD, /db/CNLD, /db/BMLD, /db/CONS and
/db/MVCD — all create/read/update/delete once the payloads above are right.
The four that failed on the first run were all bad test fixtures (deleted
prerequisites, a 6-character constraint), not SDK defects; that is worth
stating plainly, because a checker that cries wolf gets ignored.
The Gen run doubles as confirmation that the per-id delete fix works there
too, without needing a separate assertion: the /db/CNLD, /db/BMLD and
/db/CONS cases attach to seeded node 1, element 1 and node 2, and they run
after the /db/NODE case deletes node 101. Under the old whole-table
delete, that one call would have taken the seed with it and all three would
have failed — which is exactly how the bug was found on Civil.
2026-07-26 — /doc/NEW killed Gen NX once, and nothing explains it¶
Read the follow-up sections before acting on this one. The framing here — that the old
doc/newconcurrency trigger had returned — did not survive testing, and every hypothesis raised below was subsequently eliminated, including by reopening the very model involved. The crash is real and the mitigation stands; the cause is unidentified.
A single /doc/NEW against Gen NX 2026 (v2.1), build 06/23/2026 with a
real 710-node / 1272-element analyzed model open produced the license
work-session crash dialog and killed the application:
[Error] Failed to disconnect the work session due to an unidentified error.Since you have not logged out, other PCs may have limited access to thelicense. In order to properly terminate the program, try to re-execute theprogram, press 'New Project' and then close the program.
The API side reported it correctly and immediately: POST /doc/NEW -> 404:
Client Disconnected, surfaced as MidasNotFoundError. No hang, no timeout —
the SDK's only involvement was issuing one documented call.
This reopens a trigger this file had closed. The section "This exact crash
signature has a prior precedent" records that the doc/new trigger was
retested against v2.1, found no longer reproducible, and closed out as
"limited to a previous build or a specific sequence". That conclusion is now
wrong twice over: it was already questioned by the *-ANAL reproductions, and
here the original doc/new trigger itself reproduces on the current build.
Two things are different from the earlier doc/new reproductions, and both
make this worse, not better:
- It was one call, not a burst. The earlier round needed back-to-back x10 or concurrent x5/x15 to trigger it. This was a single request.
- The document mattered.
/doc/NEWhad been called perhaps a dozen times earlier the same day against small scratch documents on Civil NX with no incident. The one that crashed was the first against a large, analyzed, loaded-from-disk model.
That points at document teardown of a real model, not at call frequency. It is
one occurrence, so treat the size/state correlation as a hypothesis worth
testing deliberately rather than an established cause — but the "resolved"
label on the doc/new trigger should not be restored without a reproduction
attempt on a comparable model.
Practical consequence, unchanged from the earlier findings: once this
dialog appears the program always dies, and the license stays checked out
until the process is properly terminated — which per the dialog means
re-running the program, pressing New Project, and closing it cleanly. Do not
point /doc/NEW at a session holding a model that matters.
2026-07-26 — narrowing the /doc/NEW crash, and /doc/SAVEAS looks broken¶
What the /doc/NEW crash is not¶
Four controlled runs against Gen NX 2026 (v2.1, build 06/23/2026), each building the document through the API so only one variable moves:
Document under /doc/NEW |
Result |
|---|---|
| 2-node scratch | ✅ 3.1s |
| 710 nodes / 1339 elements, API-built | ✅ 3.6s |
| 750 nodes / 1300 elements, API-built, solved, reactions readable | ✅ 4.1s |
| 710 nodes / 700 elements, saved then reopened from disk | ✅ 4.1s |
| 710 nodes / 1272 elements, the user's real model, opened from disk, solved | 🛑 crash |
Four candidate causes tested and all four eliminated: the product being
Gen, model size, the presence of analysis results, and the document being
disk-backed. The last of those was the leading hypothesis after the first
three fell, and it did not survive contact with a controlled test — a document
saved via /doc/SAVEAS and reopened via /doc/OPEN tore down cleanly.
What still separates the one document that crashed:
- Content, not size. It carried 60 sections, 3 materials, structure and boundary groups, story data, load combinations, rebar data, and 190 design members each for RC/steel/SRC. Every test model had one material, one section and no design data at all.
- Session history. That session had served two full 253-endpoint read sweeps plus dozens of ad-hoc probes over several hours before the crash. The clean runs were minutes old.
Both are testable; neither is cheap, since each attempt costs a crash and a license recovery. Recorded as the two surviving hypotheses rather than picked between.
The session hypothesis, and why it is now the leading one¶
The project author proposed a mechanism for the second one that fits the evidence better than anything model-side: the server retains a record of the existing session, and a later request is read as a second client connecting, so the session/licence layer refuses the teardown. Three things support it:
- The dialog only ever talks about sessions and licences. It says nothing about the model — which is what you would expect given that four model-side variables have now been eliminated by experiment.
- The original documented trigger was literally concurrency. The earlier
pre-v2.1 round reproduced this crash with
doc/newcalled concurrently x5/x15. That was filed here as an obsolete build-specific quirk; under this hypothesis it is the same defect seen from the other end, and the "resolved" label was hiding a mechanism rather than a fixed bug. - NX runs on a separate machine, reached through MIDASIT's relay, so there really is distributed session state to get out of sync — this was not understood when the earlier notes were written.
What does not yet fit: Gen and Civil were both connected on the same account
(sjj0507@midasit.com, distinct connectionIDs) during the four clean
/doc/NEW runs as well as the crash, so two products sharing an account is
not sufficient on its own.
The one session-level difference that survives: the crashed session was the original long-lived connection — hours old, two 253-endpoint sweeps and dozens of probes deep — while every clean run happened on a freshly restarted NX process minutes old.
Tested: the historical concurrency trigger does NOT reproduce¶
Run against a trivial empty document on the same build, reproducing the pre-v2.1 pattern exactly, each phase followed by a health check:
| Phase | Result |
|---|---|
10 back-to-back /doc/NEW, no pause |
10/10 fine |
5 concurrent /doc/NEW, separate clients |
5/5 fine (18.6s) |
15 concurrent /doc/NEW, separate clients |
15/15 fine (59.5s) |
Session stayed healthy throughout, same connectionID, app responsive after
every phase. So concurrency alone does not do it, and the earlier round's
doc/new-burst trigger really does look fixed on v2.1 — the "resolved" label
was right about that pattern, even though the endpoint can still crash.
This corrects the framing in the section above, which read the single-call crash as evidence that the concurrency trigger had returned. It had not. What they share is the endpoint and the crash text, not the route to it.
Where that leaves the two hypotheses: the session-age one is weakened (an
idle-but-old session is still untested, but burst load on a fresh one is
clean), and model content is now the leading candidate by elimination.
Every clean run — including 30 /doc/NEW calls across these phases — was
against a document with one material, one section and no design data.
Tested: the model is innocent, and so is session load¶
The decisive test was run — the user reopened the exact model that crashed, on the same build, same account, same machine:
nodes 710 · elements 1272 · materials 3 · sections 60 · constraints 44
load cases 5 · load combos 6 · structure groups 3
RC design members 190 · beam rebar 31
/doc/NEW -> {"message": "MIDAS GEN NX command complete"} (3.7s)
session survived
No crash. Model content is eliminated too.
Session load was then tested on its own: two full read sweeps back to back
(~480 calls) followed by /doc/NEW — the shape of what preceded the original
crash. Also clean, 4.5s.
So every variable isolated so far is eliminated:
| Hypothesis | Verdict |
|---|---|
| Product being Gen | ✗ |
| Model size | ✗ |
| Analysis results present | ✗ |
| Document loaded from disk | ✗ |
| Request concurrency (10 serial / 5 / 15 parallel) | ✗ |
| Model content (the very model that crashed) | ✗ |
| Accumulated session load (~480 calls) | ✗ |
What this most likely is¶
This now matches the pattern already recorded in this file for CC-ANAL /
BC-ANAL: reproducible five times out of five, then clean on the same build
with nothing changed. Two different endpoints, the same crash text, the same
inability to pin a trigger. Reading them as one intermittent defect in
session teardown explains more than any per-endpoint story does — and it
is consistent with everything eliminated above, all of which is about the
document rather than the session.
Untested combinations remain (rich model and heavy session load together — yesterday's actual state; or wall-clock session age measured in hours rather than call count). But the useful conclusion for this SDK does not depend on resolving that:
- Treat
/doc/NEWand*-ANALas calls that can kill the application, regardless of what the document holds. There is no precondition to check. - The mitigation is unchanged and is not going to improve: don't point them at a session holding work that isn't saved, and expect to restart the product and recover the licence when it happens.
- For a vendor report, the honest framing is a class of intermittent
session-teardown failure across
/doc/NEWand*-ANAL, with this file's elimination table attached to show what it is not. That is more useful than a steps-to-reproduce list nobody can run.
🧭 Every path in this API belongs to the machine running NX, not yours¶
The single most useful thing learned today, and it cost five failed
/doc/SAVEAS attempts to notice.
The API is reached through MIDASIT's relay at moa-engineers.midasit.com, so
the NX process answering your calls may be on a different computer entirely
— it was here. Every path-valued field is therefore resolved on that machine:
/doc/SAVEAS,/doc/OPEN,/doc/IMPORT*,/doc/EXPORT*EXPORT_PATHon every/post/TABLEcall and every design report/image call- image capture paths in
/view/*and/ope/*
Writing to C:/Users/<your-windows-account>/Documents/... fails when that
account exists only on your machine. The failure is quiet in the worst way:
| Path sent | Response | What actually happened |
|---|---|---|
C:/Users/Dennis/Documents/x.mgbx (local account) |
command complete, 58.2s |
modal "invalid path" dialog on the NX machine, blocking until dismissed |
C:/Users/sjj0507/Documents/x.mgbx (NX machine's account) |
command complete, 0.4s |
saved |
Both answers are byte-identical. The only signals are the latency — a
blocked dialog inflates it — and, decisively, whether the file is really
there. Checking os.path.exists() from the calling script proves nothing; it
is looking at the wrong filesystem. /doc/OPEN on the path you just wrote is
the check that works, since it asks the same machine.
The manual repo's examples/javascript/auto-save-before-analysis.html already
warns about this — "%USERPROFILE% 같은 환경변수는 MAPI 서버(Gen NX 프로세스)가
인식하지 못합니다" — and derives the folder from the account name in
/mapikey/verify's user email (sjj0507@midasit.com → sjj0507). That is
the right pattern: ask the server who it is, then build the path.
Two corrections to earlier drafts of this file, kept because the reasoning error is instructive:
/doc/SAVEASis not broken. It was writing files correctly the whole time, to a machine this script could not see.- Its response is still not proof of success — but the reason is the dialog, not the endpoint.
Same lesson for .mgbx: the manual's example still shows the pre-NX .mcb,
and Gen NX 2026 writes .mgbx. That turned out not to be what was failing
here, but the example extension is stale regardless.
2026-07-26 (later) — 🛑 POST /db/NMAS kills Civil NX, deterministically¶
The first crash in this file with a reproducible one-call trigger. Read it
alongside the /doc/NEW section above, whose "cause unidentified, survives
every hypothesis" conclusion it partly supersedes: the license dialog those
sections treat as an unexplained session-teardown symptom can now be produced
on demand.
Civil NX 2026 (v2.1), build 06/05/2026. Four reproductions, no exceptions.
The call times out, every subsequent /db/* call times out, and the
application raises
[Error] Failed to disconnect the work session due to an unidentified error. Since you have not logged out, other PCs may have limited access to the license.
and exits — holding the license until the product is re-run, New Project is
pressed, and it is closed properly. A second dialog names it outright:
"Program will be closed due to an unexpected problem."
Where NX puts its crash-recovery file varies with the document, and one of the
two locations it chose is unusable. Twice it tried
C:\Program Files\MIDAS\MIDAS CIVIL NX\DgnPlugIn\_restore.mcb and was
refused, since a standard account cannot write there; on the fourth
reproduction it wrote to the user's Downloads folder successfully. So
auto-recovery is not universally broken here — but it fails silently in the
Program Files case, which is worth knowing before relying on it. That is an
install-level problem, separate from the crash.
The three reproductions, and why the third one settles it¶
| # | Preceding activity | /doc/NEW? |
Idle | Outcome |
|---|---|---|---|---|
| 1 | full core + boundary tiers; /db/SDSP create→update→delete completed immediately before |
yes | none | died on /db/NMAS |
| 2 | verify_connection, GET /db/NODE (10 nodes), GET /db/NMAS ({}) |
no | ~32 min | died on /db/NMAS |
| 3 | /doc/NEW, seed model, GET /db/NODE, control POST /db/CNLD (0.1s), GET /db/CNLD |
yes | none — 20s-old session | died on /db/NMAS |
| 4 | POST /db/NODE, POST /db/SKEW, POST /db/CONS, GET /db/NMAS, GET /db/NODE — five calls at 0.08–0.17s each, all within the 1.3s before |
no | none | died on /db/NMAS |
Two competing explanations were raised. Both are excluded by the table.
An idle work-session timeout, since a ~32-minute absence sat in front of reproduction 2. It does not survive the evidence.
- In run 2 itself, three
/db/*calls succeeded after the idle gap and one of them returned all ten nodes. Those are answered by the application, not the relay, so the work session was alive. - The narrower variant — "the first write after a long idle is what dies" —
is excluded by run 1, where
/db/NMASwas nowhere near the first write: 100+ calls including dozens of writes had already succeeded, and/db/SDSPhad just completed a full round trip. - Run 3 then removes the confound entirely: a 20-second-old session, a control write to a sibling static-load endpoint succeeding in 0.1s, then this one call taking the session down.
A blocking save-changes dialog, since /doc/NEW raises one on a document
with unsaved changes, and this file already records that any modal dialog
freezes the whole API session rather than the one call. Reproduction 4 was run
specifically to test it: no /doc/NEW anywhere in the run, so nothing
could raise that dialog, and it worked on node ids 9001/9002 so the open
document was left alone. Three writes and two reads returned in 0.08–0.17s
each inside the 1.3 seconds before the call — which also excludes a dialog
raised by anything else, because a modal would have frozen those five too.
POST /db/NMAS died exactly as before.
The dialogs that appear afterwards are consistent with the crash rather than an explanation of it: NX raises the license and "unexpected problem" dialogs on its way out.
GET /db/NMAS and /info/db/NMAS are unaffected. Nothing about the payload is
unusual — three unit masses on a plain seeded node — and /info/db/NMAS lists
exactly the fields being sent. This is a product defect, not a wrong request
shape in this SDK.
verify_connection() reports "connected" throughout¶
Worth restating because it was measured twice in a row here, 0.5s each time,
while GET /db/NODE timed out at 15s in between. The health check is served by
the relay. It confirms the key is valid and the connection record exists; it
tells you nothing about whether the application can answer.
What was done about it¶
NodalMassPayloadindb/static_loads.pycarries the warning, with the recommendation to useLoadsToMass(/db/LTOM) where the mass can be derived from loads instead.scripts/live_crud_check.pyquarantines the case:Case.crashesmarks it, it is skipped by default and reported asSKIP, and running it needs an explicit--include-crashers. It is also last in its tier, so opting in costs only that one case rather than the seven that sat behind it in run 1.- The checker now aborts the whole run the moment a failure looks like a lost
session (
client does not exist, or a read timeout) instead of grinding through the remainder. Run 1 spent two 30s timeouts and six 404s reporting "failures" against an application that had already exited.
Untested on Gen NX. Do not assume it is Civil-only, and do not assume it is version-specific on this evidence alone.
2026-07-26 (later) — write verification, tiers 2-6: 40 of 43 cases confirmed¶
scripts/live_crud_check.py grew from 11 cases to 43, grouped into six tiers
ordered by what a modelling script actually reaches for. Confirmed live on
Civil NX 2026 v2.1 the same day: 40/43, across five runs. The three that
are not confirmed each have a recorded reason, and none of them is an SDK
defect: /db/NMAS crashes the product, /db/TDMT refuses every payload
server-side, and /db/TMAT cannot be reached without /db/TDMT.
Superseded later the same day, and the numbers below are the v2.1 state, not the current one.
/db/TDMTwas not refusing anything server-side — theCODEvalue was wrong; it and/db/TMATboth round-trip, taking this to 42/43 on v2.2. See the two later sections.
Newly proven round trips (create → read → update → read → delete → read):
| Tier | Endpoints |
|---|---|
props |
/db/THIK /db/ESSF /db/SECF /db/TSGR /db/TDME |
boundary |
/db/NSPR /db/GSTP /db/GSPR /db/ELNK /db/RIGD /db/MCON /db/FRLS /db/OFFS /db/SSPS — 9/9 first time out |
static |
/db/SDSP /db/LTOM /db/NBOF /db/FBLD /db/PSLT /db/PRES /db/ETMP /db/NTMP — 8/8 once /db/NMAS was quarantined out of the way |
stage |
/db/STAG /db/TMLD /db/CRPC /db/CMCS |
moving |
/db/LLAN /db/MVHL /db/MVHC /db/MVLD |
Still unconfirmed: /db/NMAS (quarantined, above), /db/TDMT (below) and
/db/TMAT (blocked by /db/TDMT).
The quarantine paid for itself immediately: the seven static cases that had
never been reached — they sat behind /db/NMAS in the crashed run, and were
never evidence of anything — all passed once it was skipped and moved last.
Six on the first attempt, /db/PRES after the fix below.
🛑 /db/SECF is keyed by section id, and the SDK said element id¶
db/properties/section.py documented /db/SECF ("Section Manager -
Stiffness") as keyed by element id. It is keyed by section id.
| Request | Response | Stored |
|---|---|---|
POST /db/SECF {"Assign": {"3": {...}}} (element 3) |
200, no error | nothing |
POST /db/SECF {"Assign": {"1": {...}}} (section 1) |
200 | the record, echoed back in full |
The wrong-key form is silent — no error object, no message, nothing to notice except reading back and finding an empty table. Since this project's TypedDicts are explicitly documentation rather than runtime validation, a wrong comment here is the defect; corrected in the docstring, with the evidence.
The fixture found it on purpose: the case was deliberately keyed to element 3
with a note saying a "missing after write" failure would mean the key was a
section id, because the manual's worked example keys it 9001 right next to
/db/STRPSSM's 9003, and /db/STRPSSM is section-keyed.
/db/MVHL stores a user-defined vehicle when asked for one [superseded]¶
VEHICLE_LOAD_NUM must be 1 for a standard-DB vehicle. Send 2 and NX
discards VEHICLE_TYPE_NAME and STANDARD_CODE and stores a user-defined
"Truck/Lane" vehicle instead, with a 200 and no error:
sent {"MVLD_CODE": 6, "VEHICLE_LOAD_NAME": "KR(SRB)_DB-18",
"VEHICLE_LOAD_NUM": 2, "VEHICLE_TYPE_NAME": "DB-18",
"STANDARD_CODE": "KS-RB", "VEH_DEFAULT": {"DYN_LOAD_ALLOWANCE": 0, ...}}
stored {"MVLD_CODE": 6, "VEHICLE_LOAD_NAME": "KR(SRB)_DB-18",
"VEHICLE_LOAD_NUM": 2, "USER_LOAD_TYPE": "Truck/Lane",
"VEH_DEFAULT": {"UNIFORM_LOAD": 0, "PL": 0, "PLM": 0, "PLV": 0}}
With VEHICLE_LOAD_NUM: 1, DB-18, DB-24 and DL-24 all store correctly
under STANDARD_CODE: "KS-RB". This joins /db/CONS truncating an 8-character
CONSTRAINT and the empty-VEH_DEFAULT no-op as a silent data-corruption
shape: the only defence is to read the record back and compare.
Superseded 2026-09-03. The observation reproduces exactly and the record above is what the server stores. The conclusion drawn from it does not hold:
VEHICLE_LOAD_NUMis the endpoint's branch discriminator,2selects the user-defined vehicle, and discardingVEHICLE_TYPE_NAMEandSTANDARD_CODEis that branch behaving as documented - the KSCE-LSD15 article added a"VEHICLE_LOAD_NUM": 2User Defined example on 2026-07-30, three days after this was written. Sent properly, branch 2 loses nothing. This is not a data-corruption case and does not belong beside/db/CONS. See the 2026-09-03 entry at the end of this file for the measured branch table and for what is wrong, which is requiredness.
Also resolved: /db/MVHC's VEHICLE_LD_NAMES takes the vehicle's
VEHICLE_LOAD_NAME ("KR(SRB)_DB-24"), not the type name ("DB-18") the
manual's worked example shows.
⚠️ /db/PRES's documented default DIRECTION is rejected¶
DIRECTION is documented (manual and SDK alike) as defaulting to "NORMAL".
On a 4-node PLATE with FACE_EDGE_TYPE: "FACE" — the commonest pressure load
there is — Civil NX 2026 v2.1 rejects it:
Omitting DIRECTION fails identically, which confirms the default is
applied and the default is unusable. Working values on that same element:
DIRECTION |
Result |
|---|---|
LZ (element local z — normal to the plate), LX, GZ |
accepted |
VECTOR with VECTORS: [0, 0, -1] |
accepted |
NORMAL |
(Item:Load Direction) |
NORMAL_PLANE, NORMAL_ELEM, GLOBAL_Z, LOCAL_Z |
Wrong Field |
The two error strings separate the cases again: "NORMAL" earns the specific
"Load Direction" complaint rather than the generic Wrong Field that the
invented spellings get, so it is a recognised enum value — presumably valid
for some other ELEM_TYPE/FACE_EDGE_TYPE pair. For plate faces, pass "LZ".
Two smaller notes from the same endpoint: the server echoes FORCES back with
five entries where the manual's example sends four, and /info/db/PRES gives
its maxItems as 5; and /info/db/PRES carries a PSLT_KEY field (a
/db/PSLT reference) that the manual chapter does not document.
Also on /db/PSLT: the manual spells ELEM_TYPE "Plate/PlaneStress(Face)"
in its worked example and "Plate/Plane Stress (Face)" in its Specifications
prose. This section originally concluded the unspaced form was "the one the
server accepts" — that was wrong, and it was inferred from the CRUD case
passing with the unspaced form without ever sending the spaced one. Both are
accepted (checked on v2.2, see the final-verification section). The manual's
inconsistency is cosmetic.
⚠️ The manual's only documented time-dependent-material code name is rejected¶
"KDS2016" — the value in the manual's worked example, its Python example and
its NAME field for both /db/TDMT and /db/TDME — is not accepted by Civil
NX 2026 v2.1. Probed against /db/TDME:
CODENAME |
Result |
|---|---|
CEB-FIP(2010), CEB-FIP(1990), Ohzagi |
accepted |
ACI |
accepted once A/B are supplied |
KDS2016, KDS(2016), KDS, KCI-2007, Korea Standard |
Wrong Field |
KDS-2016 |
recognised, but still rejected even with A/B |
The two error strings are diagnostic and worth knowing:
"Wrong Field"— the code name is not one the product knows."[Error] Time Dependent Material(Comp. Strength) input data contain errors."— the name was recognised; the code's own conditional fields are missing.
⚠️ /db/TDMT looked server-side broken and was not — see the correction below¶
Recorded as written at the time, because the reasoning error is the useful
part. /db/TDMT answered 201 + {"error": {"message": "Wrong Field"}} to
the manual's worked example, to every code name /db/TDME accepts, to each
documented field removed in turn, and to a bare {"NAME": "C"}; PUT
behaved the same; /info/db/TDMT listed every field being sent; and an
{"Argument": ...} body was refused with a different, correct error. From
that this file concluded "looks server-side".
That conclusion was wrong. Nothing about it was server-side — the CODE value
was simply not one this endpoint accepts, and "Wrong Field" is what it says
when it cannot resolve CODE. Resolved further down: "Wrong Field" from
these endpoints means the code name is unknown, not that a field name is
wrong, and the message being about "Field" is actively misleading. The
lesson worth keeping: an exhaustive-looking elimination sweep over the fields
proves nothing when the bad value is in a field you never varied.
Fixture design rules, and why they earned their keep¶
Two rules, both paid for by the first run:
- Seed at the lowest free key, let the case take the next one. Definition
tables disagree about honouring the
"Assign"key —/db/NODEhonours it,/db/STLDand/db/TDMErenumber to the next free slot (posting/db/TDMEunder keys 10/15/16/18 produced ids 1/2/3/4). Seeding first and taking the next sequential key makes both behaviours land on the same id. Where a record is referenceable by name — groups, spring types, lanes, vehicles — the fixtures use the name and the question never arises. - Seed steps are per-case dependencies, not per-tier. The first run
blocked all 7
propscases behind the one/db/TDMTseed failure, though only/db/TMATneeded it. Four of those seven pass. A checker that reports 6 false blockages out of 7 gets ignored, which is the whole point of separating regression (a confirmed case broke → SDK defect suspect, exit 1) from unverified (never passed → triage the fixture, exit 3) from blocked and skipped.
The classification held up: across three runs every single failure resolved to
a fixture defect, a documented-value defect, or a product defect — and none to
an SDK behaviour defect. The one SDK defect found was a wrong docstring
(/db/SECF), which no amount of round-tripping would have caught if the case
had been keyed correctly by accident.
2026-07-26 (later still) — Civil NX v2.2: nothing changed¶
The user upgraded to MIDAS Civil NX 2026 (v2.2), build 06/18/2026 — a version bump, not a reinstall of the crashing build — and the whole checker was re-run against it.
The 40 confirmed round trips are unchanged¶
live_crud_check.py --product civil gave a byte-identical verdict on v2.2:
40/43, zero regressions, the same three exceptions. That is worth having
on its own — it is the first evidence in this project that the SDK's write
shapes survive a Civil NX version change, and the endpoints in
docs/coverage.json now cite v2.2 as their verified version. (The same 40
passed on v2.1 build 06/05/2026 earlier the same day; the nx_versions field
holds one build per product, so it names the newer one.)
🛑 /db/NMAS reproduction #5 — the upgrade did not fix it¶
Same protocol as reproduction #4, deliberately: no /doc/NEW anywhere in the
run, control writes immediately before, node ids 9001+ so the open document is
untouched.
[ 0.6s] OK POST /db/NODE 9001-9005 (fixture) (0.11s)
[ 0.7s] OK CONTROL POST /db/SKEW 9001 (0.11s)
[ 0.8s] OK CONTROL POST /db/CONS 9002 (0.11s)
[ 0.9s] OK CONTROL GET /db/NODE (t-0) (0.08s)
[ 15.9s] FAIL POST /db/NMAS 9001 (15.01s) read timeout
[ 31.4s] FAIL GET /db/NODE (15.47s) read timeout
The probe was written to keep going if the call had survived — five more
POSTs, a PUT, a DELETE and a read-back — precisely so that a clean
result would not rest on one lucky call. It never got there.
This is now five reproductions across two versions. It matters because of
the precedent this file already records: CC-ANAL/BC-ANAL were reproducible
five times out of five and then ran clean on the same build with nothing
changed, and /doc/NEW's crash never got a trigger at all. /db/NMAS is not
that. It is deterministic, it is one call, the payload is three unit masses on
a plain node, and a vendor version bump did not touch it.
Practical consequence: do not wait for this to be fixed by upgrading, and the vendor report is worth actually sending — see the crash section above for the evidence to attach.
/db/TDMT is not version-specific either¶
Still 201 + {"error": {"message": "Wrong Field"}} on v2.2, for the manual's
own worked example. Whatever is wrong with that endpoint survived the same
upgrade, which removes "stale build" as an explanation and makes it worth
reporting alongside the crash rather than sitting on it.
2026-07-26 (later still) — /db/TDMT solved: the code-name enums differ¶
/db/TDMT and /db/TDME sit next to each other in chapter 04, take a code
name each, and do not share a code-name enum. That is the whole answer, and
it cost most of a session to find because a Wrong Field error pointed at the
fields rather than at the value.
Probed live on v2.2 with the CEB-FIP field set (MSIZE/CTYPE) and the ACI
field set (VOL/CMETHOD), 16 candidate names each:
CODE on /db/TDMT |
Result |
|---|---|
European |
accepted with either field set |
AASHTO |
accepted with either field set |
ACI |
accepted with VOL/CMETHOD |
Russian |
recognised — "input data contain errors", so it wants other fields |
CEB-FIP, CEB-FIP(2010), CEB-FIP(1990), CEB-FIP(1978), CEB FIP |
Wrong Field |
Ohzagi, KDS-2016, KDS2016, Korea, KCI-USD12, JTG3362-2018 |
Wrong Field |
So MIDAS calls the CEB-FIP-based creep/shrinkage model "European" on this
endpoint, and every CEB-FIP spelling is rejected — while /db/TDME accepts
CEB-FIP(2010)/CEB-FIP(1990)/Ohzagi and rejects European-flavoured
guesses. The manual's chapter blurb for /db/TDMT — "CEB-FIP(2010/1990/1978),
ACI, KDS 등" — describes a set of names the endpoint does not take. Stored
records come back with CODE upper-cased ("European" → "EUROPEAN").
The two error strings are the same diagnostic pair seen on /db/TDME, and they
are the fastest way to triage this class of endpoint:
"Wrong Field"→ the code name is unknown. Vary the value, not the fields."[Error] ... input data contain errors."→ the name is recognised; the code's own conditional fields are missing or wrong.
With CODE: "European", /db/TDMT round-trips, and /db/TMAT — which links a
/db/TDMT and a /db/TDME record by name — round-trips after it. That
takes the checker to 42/43 confirmed, leaving only the /db/NMAS crash.
One more self-inflicted fixture defect on the way there, worth recording
because it is the exact rule this file lays out two sections up: /db/TMAT's
update pointed TDMT_NAME at TDMT_CRUD, the record the /db/TDMT case
creates and deletes, so the update earned a Wrong DB Name for a reason that
had nothing to do with /db/TMAT. Fixed by seeding two creep/shrinkage records
(TD_SEED, TD_SEED_2) that outlive the tier and switching between them.
What this changes about the vendor report¶
/db/TDMT comes off the product-defect list and moves to the manual team:
the endpoint works, its documented code names don't. What is worth reporting as
a product-side issue is the error text — "Wrong Field" for an unrecognised
value sends the reader to inspect field names, which is what happened here.
2026-07-26 (later still) — v2.2 re-check of the v2.1-only findings¶
Three findings had only ever been seen on v2.1 (build 06/05/2026) and were about to be sent to MIDASIT on that basis. Re-run on v2.2 (build 06/18/2026) before sending. Two hold, one does not.
| Finding | v2.1 | v2.2 |
|---|---|---|
/db/CONS silently truncates an 8-character CONSTRAINT to 7 |
reproduces | reproduces |
DELETE {endpoint} + ID-keyed "Assign" empties the whole table |
reproduces | reproduces |
/db/MVHL no-ops on an empty VEH_DEFAULT: {} |
reproduces | does not reproduce |
/db/CONS — and the response lies too¶
The truncation is unchanged, and re-checking it turned up something the original write-up missed: the POST response echoes the 8-character string back, while the stored record holds 7.
POST /db/CONS {"Assign": {"3": {"ITEMS": [{"ID": 1, "CONSTRAINT": "11111111"}]}}}
response -> {"CONS": {"3": {"ITEMS": [{"ID": 1, "CONSTRAINT": "11111111"}]}}} 8 chars
GET -> {"3": {"ITEMS": [{"ID": 1, "GROUP_NAME": "", "CONSTRAINT": "1111111"}]}} 7
So the immediate response cannot be used to detect it either — a separate GET is the only signal. Six characters is still rejected outright, so the asymmetry is the real complaint: too short errors, too long is silently cut.
DELETE — measured on v2.2, and it is as bad as recorded¶
before NODE 10, ELEM 4
DELETE /db/NODE {"Assign": {"21": null}} one node named
after NODE 0, ELEM 0 the model is gone
before STLD ['1', '2']
DELETE /db/STLD {"Assign": {"1": {}}} one load case named
after STLD []
DELETE /db/NODE/502 the per-id form
-> {"NODE": {"502": {...}}}, 501 and 503 untouched
One detail worth having: the response body returns every record it deleted,
so the response does reveal the over-deletion — after the fact. delete()
already uses the per-id URL, so nothing changes in the SDK.
/db/MVHL's empty VEH_DEFAULT — fixed, so it comes out of the report¶
On v2.2 the record saves and VEH_DEFAULT comes back populated with
{"DYN_LOAD_ALLOWANCE": 0, "CENT_F": false} — the product now fills the
defaults instead of discarding the write. Removed from the vendor report's
silent-write-failure list, since sending a claim that does not reproduce on the
current build costs credibility for the ones that do; kept in the report's
appendix as a note that it appears resolved, and the VehicleDefaultParams
docstring now scopes the warning to v2.1.
This is the argument for re-checking before reporting rather than after: the same sweep that confirmed two findings retired a third and sharpened one of the two.
2026-07-26 (final) — every vendor-report claim re-checked in one pass¶
Before sending anything to MIDASIT, all 16 claims were re-run against a single
v2.2 session (build 06/18/2026) in ascending order of severity — the
documentation items first, then the response conventions, then the silent
write failures, then the destructive DELETE, and the crash last. Ordering it
that way matters: the crash ends the session, so anything after it would go
unverified.
14 of 16 reproduced. The two that did not are the useful part.
❌ Retracted: /db/PSLT's ELEM_TYPE spelling was never a defect¶
Both "Plate/PlaneStress(Face)" and "Plate/Plane Stress (Face)" are
accepted. The earlier claim that only the unspaced form works came from the
CRUD case passing with that form — the spaced form was never sent. That is an
inference dressed up as a finding, and it is exactly the failure mode this file
already records for /db/TDMT: do not conclude anything about an enum from
one value working. Removed from the vendor report.
⚠️ A-4 failed its own check, not the claim¶
The assertion required two probes to both return an error body, and one of them
(POST /db/CONS with a 3-character CONSTRAINT on a node that does not exist)
returned 201 with no error at all. The claim itself is confirmed by the other
probe — POST /db/TDMT → 201 + {"error": {"message": "Wrong Field"}} —
and by PUT /db/TMAT → 200 + Wrong DB Name earlier the same day. Bad
test, good finding; the report's example list was corrected rather than the
claim.
That stray 201-with-no-error on a nonexistent node is itself suspicious as
another silent no-op, but it was not checked with a follow-up GET and is not
claimed anywhere.
/mapikey/verify is stale, not permanently wrong¶
Worth correcting because the report said it reports "connected" for a dead
application. It does — but not forever. Measured immediately after two crashes:
"connected". Measured after this crash, roughly 30 seconds later and after
two 15s timeouts had elapsed: "disconnected". So the relay's connection
record catches up; there is a window in which it lies. The report now says
that instead.
Confirmed unchanged on v2.2¶
/db/TDMT's code-name enum (B-1), /db/TDME's (B-2), /db/SECF's section
key (B-3), /db/PRES's rejected "NORMAL" default and its 5-entry FORCES
(B-4, B-7), /db/MVHC's VEHICLE_LD_NAMES — which rejects a vehicle type
name with Unknown Error (B-5) — /db/STLD's renumbering, where a POST under
key 7 produced id 3 (B-6), the "Wrong Field" vs "input data contain
errors" split (A-6), all three silent write failures (A-3a/b/c), DELETE
emptying /db/NODE from 10 nodes and 4 elements to zero from a single named id
(A-2), the per-id form working correctly (A-2b), and POST /db/NMAS killing
the application — reproduction #6 (A-1), with the three control calls
immediately before it all returning normally.
2026-07-27 — 🛑 four of the seven "documentation defects" were ours, not MIDASIT's¶
Before sending the vendor report, every B-item was re-checked against the
official Zendesk articles (support.midasuser.com, JSON Manual section
30087500371097) fetched that day — not against E:\AI Study\MIDAS-API.
That distinction is the whole finding. The vendored manual is a curated
transcription; section B had been written against it, so wherever the
transcription was wrong, we were about to accuse MIDASIT of our own error.
B-1 /db/TDMT CODE — retracted. The official article
(Creep/Shrinkage)
documents a complete, exact 28-value enum: CEB_FIP_2010, CEB,
CEB_FIP_1978, ACI, PCA, COMBINED, AASHTO, JSCE_12, JSCE_07,
JSCE, JAPAN, INDIA_IRC_18_2000, INDIA_IRC_112_2011, EUROPEAN,
AS_5100_5_2017, AS_5100_5_2016, AS_RTA_5100_5_2011, AS_3600_2009,
NEWZEALAND, RUSSIAN, CHINESE, JTG, CHINA_JTG3362_2018, KDS_2016,
KSI_USD12, KSCE_2010, KS, USER_DEFINED.
The 16 values swept on 2026-07-26 were NAME values read as CODE values.
In the official example, "NAME": "CEB-FIP(1990)" sits directly above
"CODE": "CEB" — NAME is the free-text label, CODE is the enum. Every
"rejected CEB-FIP spelling" recorded above was a string the official article
never proposes for that field. "European" was not a discovery; EUROPEAN
is documented, and the match is case-insensitive.
B-2 /db/TDME CODENAME — retracted. The official article
(Compressive Strength)
gives "KDS-2016". "KDS2016", the value probed and reported as rejected,
appears in neither official article — it is a vendored-copy error.
So the two endpoints do differ, and interestingly: /db/TDMT takes
UNDERSCORED_UPPERCASE tokens, /db/TDME takes the display string
(CEB-FIP(2010), KDS-2016, European). Both are documented correctly and
in full. That the SDK's own seeds already use CODENAME: "CEB-FIP(2010)" and
pass live is confirmation, not coincidence.
B-3 /db/SECF — retracted. The official article is titled Section
Manager - Stiffness and never states what the "Assign" key means; it just
uses 9001/9002 as example keys. "Keyed by element id" was our own
docstring, already corrected in db/properties/section.py. The live finding
(section id is the right key) stands; the accusation does not.
B-7 /db/PRES — retracted. The official Specifications row reads
"FORCES" Array [Number, 5], and all four official examples carry five
entries. PSLT_KEY is present in the official JSON Schema. Both halves
described the vendored chapter, not the source.
B-4 /db/PRES DIRECTION — narrowed, not retracted. Footnote ¹⁾ of the
official article carries an availability matrix that documents the live
behaviour exactly: for "PLATE" + "FACE", Normal is - while Local x/y/z,
Global X/Y/Z and Vectors are O. What survives is much smaller: the
Specifications row still marks DIRECTION Optional, default "NORMAL",
which cannot hold for the one combination where NORMAL is unavailable —
hence omitting the field fails.
B-5 and B-6 stand, B-6 rephrased as an omission: the official /db/STLD
article marks "NO" Read Only and never says what the "Assign" key does,
so renumbering contradicts no published statement — it is undocumented, which
is a weaker and more accurate claim.
The rule this produces¶
Never cite the vendored manual as "the documentation" in anything sent
outside. It exists to be corrected; E:\AI Study\MIDAS-API's own CLAUDE.md
says it deliberately normalizes official typos and marks them ⚠️. For an
internal decision it is the right source. For a claim about MIDASIT's
documentation, fetch the article and quote it. Four of seven claims died on
contact with the source, and the two that survived got weaker.
Still open: a live re-test with the official values (CODE: "CEB_FIP_2010",
"KDS_2016" on /db/TDMT; CODENAME: "KDS-2016" on /db/TDME). It was not
possible on 2026-07-27 — the relay answered client does not exist, no
session. The retractions do not depend on it (dropping an unverified
accusation is the safe direction), but if any official value does fail,
that is a genuine product defect and a new A-item.
2026-07-29 — Gen NX v2.1 (build 07/28/2026): props/boundary/static/stage get their first Gen CRUD run, /db/CMCS corrected to Civil-only¶
(Dated 2026-07-27 in an earlier draft of this section — wrong. This work
happened in the same conversation as the section above but after a real
multi-day gap; git's own commit timestamps settled it: 7f63ea6 and
456d4fa, the two commits from this session, are both stamped 2026-07-29.)
New Gen NX install, new MAPI key, scripts/live_crud_check.py --product gen
(no --include-crashers). Correction to get right before it goes stale:
this was not the checker's first exposure to Gen NX — the core tier's own
comment already says "the baseline proven live on 2026-07-26 (Civil 10/10,
Gen 9/9)", and that 2026-07-26 Gen pass is what let /db/TDMT and
/db/TDME inherit confirmed=True in the first place. What today actually
added: the props, boundary, static and stage tiers ran against Gen
for the first time (27 endpoints), on top of core repeating clean. Of
those, /db/TDMT//db/TDME are worth calling out specifically — they use
the seeds already fixed in the 2026-07-27 section above
(CODE: "European", CODENAME: "CEB-FIP(2010)"), so this is the first
live confirmation of those specific values on a Gen session, not just
Civil. /db/NMAS stayed quarantined; not run.
First pass: 36/38 confirmed cases passed. /db/CMCS came back a
REGRESSION — confirmed=True in the checker, but that flag was earned on
Civil NX runs only; the stage tier had never touched Gen before today.
Before treating it as an SDK defect: /db/CMCS is one of the 7 endpoints
already flagged twice in this file (2026-07-22, 2026-07-26) as "manual says
gen+civil, but 404s under Gen in practice" — and both those were GET-only
read sweeps, deliberately left unactioned pending a third, independent data
point per this file's own caveat.
This run is that third point, on a different session (new build, new day)
and with stronger evidence than either prior one — an actual POST
attempting to create a record, not just a GET against an empty table. Same
account as before (sjj0507@midasit.com), so it doesn't clear the
stricter "different account" bar floated in the 2026-07-26 section, but it
does satisfy the caveat's actual rule below ("different session" is listed
as sufficient), and three same-account reproductions across seven days and
three separate sessions is not a coincidence worth waiting out further.
Action taken: CamberConstructionStage.PRODUCTS changed from
{"gen", "civil"} to CIVIL_ONLY in db/construction_stage.py, the
live_crud_check.py case given products=("civil",) so a future Gen run
skips it instead of false-flagging, and its mocked test switched from
gen_client to civil_client. The other 6 endpoints in that original list
(EWSF, PLCB, RCHK, SPAN, STRPSSM, WVLD) were not exercised by
live_crud_check.py, so this run added no new evidence for them — but see
2026-07-29's read-only sweep below, which closed that gap the same day.
Re-run after the fix: 36/37, clean — 0 regressions, 0 unverified failures,
0 blocked, /db/CMCS correctly filtered out for a Gen client rather than
skipped-and-counted. docs/coverage.json updated in bulk for all 36 passing
endpoints: live_verified.products gained "gen",
live_verified.nx_versions.gen set to "MIDAS Gen NX 2026 (v2.1), build
07/28/2026", date bumped to 2026-07-29. /db/CMCS's own entry instead
dropped "gen" from top-level products (now ["civil"], matching
PRODUCTS) and its live_verified note records the three-session Gen 404
history.
2026-07-29 (later) — 🛑 POST /db/NMAS also crashes Gen NX: not a Civil-specific defect¶
With the user's explicit go-ahead, --include-crashers --tier static was run
once against the fresh Gen NX v2.1 (build 07/28/2026) session — the first
time this case has ever touched Gen. It crashed on the first attempt:
POST /db/NMAS -> 404: Client Disconnected (Hint: either the product isn't
connected ... or the id you asked for doesn't exist in the current model)
A follow-up GET /db/NODE a few seconds later confirmed the session was
actually gone, not just this one call rejected: 404 {"error": {"message":
"client does not exist"}} — the exact string Civil NX gives after this same
crash. The user restarted Gen NX, pressed New Project, and reconnected;
GET /db/NODE on the new session returned 200 {"message": ""} (empty
document), confirming recovery.
This settles the question left open in the 2026-07-26 Civil section: the crash is not a Civil NX peculiarity. Six reproductions on Civil (two versions) plus one on Gen (first-ever attempt, different build entirely, different product) is the same failure on both of MIDASIT's NX flagship products through what must be a shared write path. Not re-running this again — one clean reproduction on Gen matching Civil's exact signature is enough; further attempts just burn licenses for no new information.
Updated everywhere this was recorded as Civil-only: CLAUDE.md,
NodalMassPayload's docstring in db/static_loads.py, the crashes= note
on the case in live_crud_check.py. The vendor report's A-1 needs the same
correction before it's sent — "Civil NX 한정" understates it.
2026-07-29 (later) — full read-only re-sweep on the new Gen NX build closes the remaining 6¶
With the NMAS-on-Gen question settled, the user asked what else the new Gen
NX patch was worth re-checking. scripts/live_readonly_sweep.py --product
gen — the same read-only GET sweep from 2026-07-22 and 2026-07-26 — was
re-run against Gen NX 2026 v2.1, build 07/28/2026, a session and build
distinct from both prior ones.
239 GET-capable resources swept, 233 ok, 6 errors — the exact same 6, byte
for byte: EWSF, PLCB, RCHK, SPAN, STRPSSM, WVLD, all
MidasNotFoundError 404 with the identical hint text. No drift, no new
failures, no fixes from the patch. (CMCS wasn't part of this sweep at
all — it's correctly excluded now that its PRODUCTS is Civil-only.)
That is the third independent reproduction this file's own caveat asked for
on these 6 — same bar /db/CMCS cleared a few hours earlier, same account,
different session and build each time (2026-07-22, 2026-07-26, 2026-07-29).
Action taken: all 6 classes' PRODUCTS changed from {"gen", "civil"}
to CIVIL_ONLY — RebarCheckInput (db/design.py), PreCompositeSection
and WaveLoad (db/misc_loads.py), Span (db/project.py),
SectionStressPoints and EffectiveWidthScaleFactor
(db/properties/section.py) — each with the same dated docstring note as
CamberConstructionStage. Their 6 mocked tests switched from gen_client
to civil_client (they were asserting a request shape against a product
that, per this finding, can't actually take that request).
docs/coverage.json's top-level products for all 6 corrected to
["civil"] to match, and their live_verified.method notes now record the
three-session history the same way /db/CMCS's does.
This closes out the "20 Gen 404s" accounting from the 2026-07-26 section
above for good: 13 were Hyper-S (corrected in v0.13.0), and these final 7
(CMCS plus these 6) are now all confirmed Civil-only after three
independent sessions apiece. Nothing in that original list of 20 remains
unexplained.
2026-07-29 (later still) — /db/NMAS reproductions #2 and #3 on Gen NX: 9/9 overall, confirmed on a real production model¶
The user asked to go back to /db/NMAS one more time, specifically on Gen
NX. Two more reproductions followed, back to back, each requiring the full
license-recovery cycle (restart, New Project, close properly) before the
next could run.
Reproduction #2 (Gen, scratch document): scripts/live_crud_check.py
--product gen --tier static --include-crashers, same throwaway-model setup
as the first Gen crash. This time the script's own _session_lost check
caught it inline and aborted the run immediately, rather than needing a
follow-up probe:
FAIL /db/NMAS create=FAIL
!! ABORTED: the product stopped answering at /db/NMAS — MIDAS NX is hung or
gone, so nothing after this point was tested
error: "POST /db/NMAS failed: ... Read timed out. (read timeout=60.0)"
A 60s timeout on the call itself this time, rather than the first crash's
immediate 404 Client Disconnected — a different wire-level symptom, same
outcome.
Reproduction #3 (Gen, real production model): the user opened an actual
work file — not a scratch document — and asked to GET /db/NMAS against it
first (safe; returned {"message": ""}, no masses defined). Then,
explicitly confirming the model was already saved, asked to POST it.
Rather than risk the model's own node numbering, this run reused the
established protocol from docs/vendor_repro_nmas.py (control writes/reads
immediately before the target call, node ids 9001+ so nothing in the real
model is touched, no /doc/NEW anywhere):
[ 1.0s] 201 POST /db/NODE 9001,9002 (0.56s)
[ 1.4s] 201 POST /db/SKEW 9001 (0.47s)
[ 1.9s] 201 POST /db/CONS 9002 (0.49s)
[ 2.3s] 200 GET /db/NMAS (target table) (0.41s) {"message": ""}
[ 2.7s] 200 GET /db/NODE (0.40s)
[ 18.1s] TIMEOUT POST /db/NMAS 9001 (15.35s)
[ 18.5s] 404 GET /mapikey/verify (0.39s)
[ 33.8s] TIMEOUT GET /db/NODE (15.34s)
Same shape as every prior reproduction: three control calls immediately before the target call all returned normally in under 0.6s each, the target call itself timed out, and everything after was dead. This is the first Gen NX reproduction against real production data, which matters the same way the Civil real-model evidence did earlier in this file: it rules out "only happens on synthetic/throwaway test data" as an explanation. The user had saved the model beforehand, so the crash cost a restart cycle, not work.
Running total after this section: 9/9 — six on Civil NX, three on Gen NX,
zero survivals. Every file that recorded this as "Civil NX" or cited a
specific reproduction count has been updated: CLAUDE.md,
NodalMassPayload's docstring in db/static_loads.py, the crashes= note
in live_crud_check.py. The vendor report's A-1 gets this as its strongest
piece of evidence yet — see below.
2026-07-29 (still later) — /db/NMAS reproduction #10, on a freshly updated Civil NX build¶
The user installed a new Civil NX build the same day — v2.2 (build 07/28/2026), one build newer than the v2.2 (06/18/2026) build already on record — and asked for a fresh round of checks before trusting it, ending with a repeat of the NMAS reproduction to see if the build update happened to fix it.
Read-only sweep first (293 GET-capable Civil resources, 273 ok / 20 error).
All 20 errors were 404, on both GET and the schema-only /info/db/...
probe (a control call, Node.info(), succeeded on the same session) — that
rules out "no data in this model" as the explanation, since a schema probe
doesn't touch model data at all. The 20: /db/STOR, /db/SWIND,
/db/SSEIS, /db/POSP, /db/EPST, /db/DRLS, /db/SDHY, /db/SDIS,
/db/REBB, /db/REBR, /db/REBW, plus 9 design-chapter endpoints —
/DESIGN/RC/KDS-41-20-2022/{MATD,REBB,REBC,REBR,REBW,TRFT,ULCT},
/DESIGN/SRC/AIK-SRC2K/MATD, /DESIGN/STEEL/KDS-41-30-2022/ULCT. 11 of
these had previously been live_verified as ok specifically on Gen NX
(2026-07-26) and had never been probed live on Civil before — so this reads
as a first-time signal that these may actually be Gen-only (the SDK
currently declares PRODUCTS={"gen","civil"} for all 20), not a build
regression; coverage.json shows no prior Civil live_verified entry for any
of them. Not acted on — per the caveat below, one session's evidence isn't
enough to flip a PRODUCTS frozenset; the trigger to revisit these 20 is an
independent reproduction (different session/account, or a fresh Civil
document via live_crud_check.py's throwaway-model setup) confirming the
same 404s. Separately, scripts/check_manual_drift.py found the
vendored manual repo two commits stale — the Story Drift X_DIR/X-DIR
contradiction (21_POST_StoryTables.md) was officially corrected by the
vendor (unified on the underscore spelling, type confirmed Object), so
post/story.py's StoryDriftVerticalLine(s)Selection TypedDicts and their
tests were updated to match and the hyphen fallback was dropped;
vendored_at_commit bumped to aeca67553dd078e2057f2ab5e87fe3391775e6ac
and re-confirmed has_diff: false. The other stale file
(04_DB_Properties.md's TDMT/TDME KDS2016 correction) needed no code
change — the SDK already had the corrected values. Then
scripts/live_crud_check.py --product civil (all six tiers, /db/NMAS
auto-skipped): 42/42 non-quarantined cases passed, matching the existing
42/43-confirmed baseline with zero regressions from the build update.
Finally, with the user's explicit go-ahead, --tier static
--include-crashers:
PASS /db/ETMP create=ok read_back=ok update=ok read_updated=ok delete=ok read_deleted=ok
PASS /db/NTMP create=ok read_back=ok update=ok read_updated=ok delete=ok read_deleted=ok
FAIL /db/NMAS create=FAIL
!! ABORTED: the product stopped answering at /db/NMAS — MIDAS NX is hung or
gone, so nothing after this point was tested
error: "POST /db/NMAS failed: ... Read timed out. (read timeout=60.0)"
Same shape as every prior reproduction: a plain throwaway model, seven calls
that all passed immediately before it, then a 60s timeout on the POST
/db/NMAS call itself and the session gone. The 07/28/2026 Civil build
does not fix this.
Running total after this section: 10/10 — seven on Civil NX (across three
version/build combinations), three on Gen NX, zero survivals. Updated the
same three files as the prior count bump: CLAUDE.md, NodalMassPayload's
docstring in db/static_loads.py, the crashes= note in
live_crud_check.py.
2026-07-29 (later yet) — /db/NMAS reproduction #11: a from-scratch minimal model rules out the "floating substructure" hypothesis¶
Before reproduction #10 (above), the user raised a legitimate structural-
engineering objection: every single reproduction to date had written the
mass to, or alongside, a node with no restraint and no connecting element —
vendor_repro_nmas.py's node 9001 gets a SKEW (a local-axis rotation, not
a restraint) but no CONS and no element, so it is a literally free-
floating point in space; live_crud_check.py's seed model targets node 3
(which is connected, via the beam chain back to node 1's fixity), but the
same model also permanently carries an entirely unrestrained, disconnected
plate (nodes 5-8) and, during the static tier, an unrestrained floating
node pair (21/22) left over from the boundary tier. A structural model
with an unrestrained, disconnected substructure has a singular stiffness
matrix (rigid-body modes with no associated stiffness) — if POST
/db/NMAS triggers any internal mass-matrix or modal bookkeeping, an
iterative solver hitting that singularity hanging instead of erroring out
cleanly is a real, previously-documented class of defect in commercial FEA
software. This was a serious enough alternative explanation to test before
trusting the vendor report's framing.
Test: build a deliberately minimal, structurally clean model directly
on the (already-blank, from the prior reproduction) open document — no
/doc/NEW — with nothing floating anywhere: node 1 (fixed, CONS
"1111111"), node 2 (free), one BEAM element connecting them, one
material, one section. The mass target, node 2, is unrestrained itself but
fully connected via the beam — a textbook, kinematically determinate
cantilever, not a mechanism, and the only thing in the document.
[ 0.7s] OK Unit (0.29s)
[ 0.8s] OK Material (0.12s)
[ 0.9s] OK Section (0.10s)
[ 1.0s] OK Node 1,2 (0.15s)
[ 1.2s] OK Element (beam 1-2) (0.16s)
[ 1.3s] OK Constraint (fix node 1) (0.12s)
[ 1.4s] OK GET /db/NMAS (target table) (0.09s) {"message": ""}
[ 1.5s] OK GET /db/NODE (0.08s)
[ 48.3s] ERROR POST /db/NMAS node 2 (46.85s) 404: Client Disconnected
[ 48.3s] OK GET /mapikey/verify (0.01s)
[ 48.3s] ERROR GET /db/NODE (0.01s) 404: client does not exist
Died identically. The user watched it happen on screen this time (a
first for this investigation) and captured the exact sequence: the
in-app dialog read verbatim [Error] Failed to disconnect the work session
due to an unidentified error. Since you have not logged out, other PCs may
have limited access to the license. In order to properly terminate the
program, try to re-execute the program, press 'New Project' and then close
the program. — matching every prior paraphrase of this dialog exactly —
followed by a second, previously-undocumented dialog: Program will be
closed due to an unexpected problem. The recovered file is saved in
[C:\Program Files\MIDAS\MIDAS CIVIL NX\MIDAS CIVIL NX\DgnPlugIn\_restore.mcb],
itself followed by an access-denied error for that exact path — the
crash-recovery autosave attempted to write under Program Files and was
denied, the same class of unchecked-write-permission issue as A-7 in the
vendor report (a different endpoint's report path), now also seen in the
crash handler itself. The model tree, visible on screen right before the
crash, confirmed the model was built exactly as intended: 2 nodes, 1 beam
element, 1 material, 1 section, 1 support — nothing else.
This rules out model topology as an explanation. A model with no
disconnected or unrestrained component anywhere, built from exactly the
fields the manual documents, dies the same way as every messier fixture
before it. The defect is in /db/NMAS's write handling itself, not
triggered by a singular stiffness matrix elsewhere in the document.
Running total after this section: 11/11 — eight on Civil NX (three
version/build combinations, one of them this minimal-model run), three on
Gen NX, zero survivals. Updated CLAUDE.md, NodalMassPayload's
docstring in db/static_loads.py, the crashes= note in
live_crud_check.py, and docs/vendor_report_ko.md's A-1 section (which
now cites this reproduction explicitly as the rebuttal to a "malformed
model" explanation).
2026-07-29 (later still) — /db/NMAS reproduction #12: calling-machine location doesn't matter either¶
The user set up a second machine for this investigation: "A PC" runs Gen NX
itself plus a Codex CLI instance, both on the same host/LAN; this repo and
every prior reproduction had been run from a separate dev machine ("B PC"),
reaching Gen NX only through the public relay
(moa-engineers.midasit.com). Codex on A PC built its own client on top of
this SDK and called POST /db/NMAS — and it did not crash. That result, on
its own, would have reopened everything: eleven reproductions had already
ruled out idle timeouts, modal dialogs, and model topology, but never
whether the request's network path (same-LAN-as-the-product vs. a remote
relay round trip) was the actual variable.
Before trusting it, the target node needed to be checked. Asked for the
exact call, the user reported the response was [Warning] DTO_NMAS.999999
The command is ignored because the specified node does not exist in the
model — node 999999 was never created in the open document. Every prior
reproduction (this file's and docs/vendor_repro_nmas.py's alike) creates
the target node with POST /db/NODE immediately before writing its mass,
specifically so the write reaches the actual crash-prone code path rather
than an earlier existence check. A's "success" was a clean, correct
rejection of bad input — evidence the validation layer works, not evidence
the write path is safe.
To settle it, docs/vendor_repro_nmas.py --product gen (unmodified, the
same script already used for reproduction #3 against a real production
model) was run from B PC once more, immediately after getting the Gen
MAPI-Key:
[ 0.9s] 201 POST /db/NODE 9001,9002 (0.51s)
[ 1.3s] 201 POST /db/SKEW 9001 (0.44s)
[ 1.8s] 201 POST /db/CONS 9002 (0.46s)
[ 2.2s] 200 GET /db/NMAS (대상 테이블) (0.41s) {"message": ""}
[ 2.6s] 200 GET /db/NODE (0.40s)
[ 18.0s] TIMEOUT POST /db/NMAS 9001 (15.37s)
[ 18.4s] 404 GET /mapikey/verify (릴레이만 응답)
[ 33.7s] TIMEOUT GET /db/NODE (15.35s)
Died identically — and the user immediately confirmed Gen NX on A PC had also gone down ("죽음"), from a call made on B PC. That is the decisive part: A PC and B PC were both looking at the same live Gen NX session the whole time, so a crash triggered from B PC killed the process A PC was using. Calling-machine location cannot be the variable — there was only ever one process, and it dies regardless of which machine's HTTP request reaches it, as long as the target node actually exists.
Running total after this section: 12/12 — eight on Civil NX, four on Gen
NX, zero survivals. Updated CLAUDE.md, NodalMassPayload's docstring in
db/static_loads.py, the crashes= note in live_crud_check.py, and
docs/vendor_report_ko.md's A-1 section with a fourth excluded hypothesis
(calling-machine location).
2026-07-29 (final) — /db/NMAS's actual root cause: omitting rmX/rmY/rmZ¶
A PC's Codex instance built its own client on this SDK and reported one
more data point: POST /db/NMAS with {"mX": 1.0, "mY": 1.0, "mZ": 1.0,
"rmX": 0.0, "rmY": 0.0, "rmZ": 0.0} — all six fields, not just the three
this file's every prior reproduction sent — succeeded, verified with a GET
and cleanly deleted afterward. That is a real difference in payload shape,
not a location or SDK-version effect (the previous section had already
shown A PC and B PC hit the identical Gen NX session), so it needed
isolating properly rather than accepted at face value.
First check: same session, immediately after A PC's success, from B PC.
docs/vendor_repro_nmas.py --product gen (unmodified — omits rmX/rmY/rmZ,
same as every prior reproduction) was run right away and died on the same
live session A PC had just used successfully:
[ 0.9s] 201 POST /db/NODE 9001,9002 (0.51s)
[ 1.3s] 201 POST /db/SKEW 9001 (0.44s)
[ 1.8s] 201 POST /db/CONS 9002 (0.46s)
[ 2.2s] 200 GET /db/NMAS (대상 테이블) (0.41s) {"message": ""}
[ 2.6s] 200 GET /db/NODE (0.40s)
[ 18.0s] TIMEOUT POST /db/NMAS 9001 (15.37s)
Same live process, same account, minutes apart: full fields survived,
omitted fields died. That is close to conclusive on its own, but the two
calls used different HTTP clients (A PC's Codex-built client vs. this
repo's requests-based script), so a same-tool, same-session A/B was still
worth doing before rewriting the payload contract.
Same-session A/B, one script, two nodes, Gen NX (after a restart):
--- 1) node 9101, full fields (mX,mY,mZ,rmX=0,rmY=0,rmZ=0) ---
[ 3.7s] 201 POST /db/NMAS 9101 (full fields) {"NMAS": {"9101": {...,"rmX":0,"rmY":0,"rmZ":0}}}
[ 4.1s] ...GET /mapikey/verify, GET /db/NODE - both fine, session alive
--- 2) node 9102, omitted fields (mX,mY,mZ only) ---
[ 0.5s] 200 GET /db/NODE (pre-check) - confirmed alive first
[ 15.9s] TIMEOUT POST /db/NMAS 9102 (omitted fields) - died
[ 16.3s] 404 GET /mapikey/verify (relay only)
[ 31.8s] TIMEOUT GET /db/NODE
One script, one session, one node created fine, mass written with all six fields — survives. A second node, mass written with three fields omitted — kills the exact session that had just survived the first call, seconds earlier. There is no cleaner isolation than that.
Symmetric confirmation on both products, same day, after both were restarted: a single script ran the identical two-step protocol (full fields on node N, then omitted fields on node N+1, in the same session) against Civil NX and then Gen NX in sequence:
| Product | Full fields (rmX/rmY/rmZ=0.0) |
Omitted fields |
|---|---|---|
| Civil | survived (201, GET /db/NODE fine after) |
died (15.41s timeout, then GET /db/NODE timeout) |
| Gen | survived (201, GET /db/NODE fine after) |
died (15.46s timeout, then GET /db/NODE timeout) |
The user independently confirmed both products' UI showed the crash dialog after their respective "omitted fields" call, and neither did after the "full fields" call moments earlier.
Root cause: /db/NMAS crashes when rmX/rmY/rmZ are absent from the
payload — an uninitialized-value read or missing-default bug server-side
for those three fields specifically — not a defect in nodal-mass writes in
general. Re-checked against the official article directly (not the
vendored copy, per this file's own "fetch the Zendesk article" lesson from
the 2026-07-27 section-B correction):
support.midasuser.com/hc/en-us/articles/35952994344985-Nodal-Masses's
Specifications table documents rmX/rmY/rmZ as Optional with Default
0, exactly as the vendored manual said — so every omitted-fields request
this investigation sent was fully spec-compliant, and the server crashing
on it is unambiguously a defect, not a documentation gap or a caller
mistake. The server apparently doesn't apply that documented default
safely when the fields are missing, but is fine when a caller supplies it
explicitly. This explains every prior reproduction (this file's,
docs/vendor_repro_nmas.py's, and live_crud_check.py's fixtures all
omitted these fields) without contradicting any of it — the crash was
always real, just narrower in scope than "the whole endpoint is broken"
implied.
Fix applied: NodalMass.create()/.update() in db/static_loads.py
now merge {"rmX": 0.0, "rmY": 0.0, "rmZ": 0.0} under any item that
doesn't set them, before sending — exactly the documented default, made
explicit because the server can't be trusted to apply it itself. Verified
live through the SDK (not just raw requests): a NodalMass.create() call
passing only mX/mY/mZ succeeded and the session stayed alive, and
scripts/live_crud_check.py --product gen --tier static --include-crashers
completed /db/NMAS's full create→read→update→read→delete→read round trip
cleanly (9/9 for the tier). The case is un-quarantined and confirmed=True
in live_crud_check.py as of this session.
Updated everywhere this was recorded: CLAUDE.md, NodalMassPayload's
docstring in db/static_loads.py (now describes the fix, not just the
symptom), live_crud_check.py (case un-quarantined, module docstring's
"42 of 43" corrected to all 43), and docs/vendor_report_ko.md's A-1
(rewritten to lead with the root cause and the workaround).
2026-07-29 — the 20 Civil 404s independently reproduced, PRODUCTS corrected¶
The caveat below asked for independent reproduction — different account,
different session — before touching PRODUCTS for the 20 endpoints found
404ing on the Civil v2.2 (07/28/2026) sweep. That arrived the same day: a
separately run validation sweep (docs/Codex Report/midas_nx_0.14.0_civil_*
and ..._gen_*, removed 2026-09-17; git history at fa1332b), executed from a different machine/session against the
same day's freshly patched Civil and Gen builds, landed on the exact same
20 Civil endpoints (db_and_design_404_endpoints in its JSON summary) and
the exact same 7 Gen endpoints (CMCS, EWSF, PLCB, RCHK, SPAN,
STRPSSM, WVLD — the latter three already CIVIL_ONLY/HYPER_S_ONLY in
the SDK, so unsurprising; the rest confirm the existing accounting). Both
tools also agree the 20 Civil 404s are 404 at the /info schema level too,
not just the GET route.
That satisfies this file's own reproduction bar, so all 20 are now declared
GEN_ONLY (new constant in db/base.py, same pattern as HYPER_S_ONLY):
the 11 db/* endpoints (STOR, SWIND, SSEIS, POSP, EPST, DRLS,
SDHY, SDIS, REBB, REBR, REBW) and the 9 design-chapter endpoints
(/DESIGN/RC/KDS-41-20-2022/{MATD,REBB,REBC,REBR,REBW,TRFT,ULCT},
/DESIGN/SRC/AIK-SRC2K/MATD, /DESIGN/STEEL/KDS-41-30-2022/ULCT). Guarded
by a parametrized test, tests/db/test_civil_v22_gen_only_products.py,
mirroring test_hyper_s_products.py.
The independent sweep also surfaced three endpoints not previously in this
file's list, all looking like the same pattern but not yet independently
reproduced twice, so PRODUCTS was deliberately left unchanged for them:
/db/REBC(ch24, POST-only, no GET) — its/infoschema answers on Gen, 404s on Civil./ope/STORY_PARAMand/ope/STORY_IRR_PARAM— GET succeeds on Gen, 404s on Civil.
2026-07-29 (later same day) — live re-verification with both products open¶
With Civil NX and Gen NX both connected in the same session, re-ran every
classification claim above directly through the SDK (MidasClient(...,
strict_product=False) on both clients, so the SDK's own PRODUCTS guard
couldn't short-circuit the call — the point was to hit the real server, not
re-confirm the guard against itself):
| Family | Classification | Probed | Result |
|---|---|---|---|
GEN_ONLY (the 20 corrected above) |
civil GET fails, gen GET ok | 20/20 | 20/20 matched, byte-identical to the Civil v2.2 sweep and the independent Codex sweep |
HYPER_S_ONLY (13 implemented -M1 endpoints) |
civil GET ok, gen GET fails | 13/13 | 13/13 matched, no change since 2026-07-26 |
Both families are now confirmed a third time (GEN_ONLY) or a second time
(HYPER_S_ONLY, unchanged since first confirmed) with zero mismatches.
The 3 previously-unconfirmed candidates also confirmed this session — this is their second independent reproduction, so this file's own bar for acting is now met:
/db/REBC(ch24, POST-only):.info()answers on Gen, 404s on Civil./ope/STORY_PARAM: GET succeeds on Gen, 404s on Civil./ope/STORY_IRR_PARAM: GET succeeds on Gen, 404s on Civil.
Action taken: db.design.ColumnRebar (/db/REBC) is now PRODUCTS =
GEN_ONLY, guarded in the same test_civil_v22_gen_only_products.py test
(now 21 endpoints). docs/coverage.json updated to match.
/ope/STORY_PARAM and /ope/STORY_IRR_PARAM are documented as Gen-only in
get_story_check_parameter's and get_story_irregularity_check_parameter's
docstrings in ope.py, but not enforced — plain doc.py/ope.py/
view.py functions have no PRODUCTS gate anywhere in this SDK (they're
functions, not DbResource subclasses), so a Civil call against either
still reaches the server and 404s there rather than raising client-side.
Adding a product-gate mechanism to that whole module family would be a
bigger design change than this session's scope — flagged for a future
decision, not done here.
Final classification as of this session (all three families now
independently confirmed at least twice, zero open mismatches):
GEN_ONLY = 21 endpoints (the 20 above + /db/REBC), HYPER_S_ONLY = 13
implemented + 8 undocumented-stub -M1 endpoints (unchanged), CIVIL_ONLY
= the ch08/ch17 bridge/moving-load chapters plus the 7 endpoints corrected
2026-07-29 morning (CMCS and friends) — unchanged, not re-probed this
session since the user's request was specifically the Gen-only and
Hyper-S-only families plus the 3 unconfirmed candidates.
2026-07-29 (later still) — STORY_PARAM/STORY_IRR_PARAM against a real production Gen NX model, and a manual defect found in the process¶
The prior session's Gen NX GET check for /ope/STORY_PARAM//ope/STORY_IRR_PARAM
ran against whatever model happened to be open — good enough to confirm the
route answers, not enough to confirm it answers meaningfully. With a real
production model open (/ope/PROJECTSTATUS: 4044 nodes, 4686 elements, 11
stories, 441+494+108 load combinations across three design codes — not a
scratch model), re-ran the GET calls directly:
GET /db/STOR -> 11 real stories (B1, 1F..9F, Roof) with populated
wind/seismic eccentricity and torsional data
GET /ope/STORY_PARAM -> {"COUNTRY_CODE": "NTC2018"}
GET /ope/STORY_IRR_PARAM -> {"COUNTRY_CODE": "NTC2018",
"STORY_DRIFT_METHOD": "Drift at the Center of Mass",
"STORY_STIFFNESS_METHOD": "1 / Story Drift Ratio"}
Both endpoints answered with real, previously human-configured values (not
defaults or an empty shape), settling the "does this route actually work on
Gen, not just technically respond" question the user raised. No analysis run
was needed — both endpoints are pre-analysis configuration (country code and
calculation-method selection used by later story-drift/irregularity result
tables), not analysis output, so /doc/ANAL was never called this session.
Found in the process: a real manual defect, not just a confirmation.
StoryIrregularityCheckParameterArgument in ope.py had documented
STORY_DRIFT_METHOD/STORY_STIFFNESS_METHOD/SEISMIC_BEHAVIOR_FACTOR as
space-stripped ("Max.DriftofOuterExtremePoints", "1/StoryDriftRatio",
"3orbelow"), reasoning the manual's own worked JSON example was more
concrete evidence than the Parameters table's space-containing rendering.
The live GET above returned the space-containing form
("Drift at the Center of Mass", "1 / Story Drift Ratio") for a
real, human-set value — directly contradicting that worked example, and
matching both the Parameters table and the sibling post/story.py
STORY_DRIFT endpoint's own already-live-confirmed convention (see that
file's STORY_DRIFT_METHOD comments, chapter 21_POST_StoryTables.md).
Corrected ope.py's docstring/comment and tests/test_ope.py's example
values to the space-containing form as canonical. Not runtime-enforced
either way — TypedDicts here are documentation, not validation — but this
is exactly the "manual's worked example is the outlier, live evidence and
the Parameters table agree" pattern this project has hit before (KDS2016,
Story Drift X_DIR/X-DIR).
2026-07-29 (still later) — the mirror-image finding: 32 of 47 "Civil-only" endpoints answer on Gen too¶
Asked to also re-verify the plain CIVIL_ONLY family (excluding Hyper-S,
already reconfirmed above) with both Civil NX and Gen NX open at once.
Enumerated all 47 non-Hyper-S CIVIL_ONLY DbResource classes and probed
each with MidasClient(..., strict_product=False) on both clients (same
methodology as the GEN_ONLY/HYPER_S_ONLY re-check above — bypass the
SDK's own guard to see what the server actually does).
32 of the 47 answered on Gen NX too — not the expected 404. Checked
/info/db/... schema for all 32: every one resolves a full JSON Schema on
Gen, the same evidentiary bar this file has used everywhere else to call a
route "genuinely exists" rather than "coincidentally didn't error." Content
of the 32 GET responses:
/db/LCOM-CONC(Load Combinations - Concrete Design): 494 real, populated rows — matching this exact production model's own/ope/PROJECTSTATUScount ('Load Comb(Concrete)': 494). Unambiguous: this is a real, working, populated Gen NX feature, not an artifact.- The other 31 returned
{"message": ""}(the standard empty-table shape) — ambiguous on GET alone, but the matching/infoschema on all 31 is the same signal this file already treats as sufficient elsewhere.
The 32: IMPF, LCOM-CONC, LCOM-STLCOMP, LLAN, LLANch, LLANid,
LLANop, LLANtr, MLSP, MLSR, MVCD, MVCT, MVCTbs, MVCTch,
MVCTid, MVCTtr, MVHC, MVHL, MVHLtr, MVLD, MVLDbs, MVLDch,
MVLDeu, MVLDid, MVLDpl, MVLDtr, SINF, SLAN, SLANch, SLANop,
THGC, ULFC.
This directly contradicted db/base.py's own CIVIL_ONLY docstring,
which cited /db/LCOM-CONC and "the entire ch08/ch17 bridge/moving-load
chapters" as the canonical example of this constant's use — that example
turned out to be wrong.
The remaining 15 stayed genuinely Civil-only (404 on Gen, both GET and
by extension the route): CAMB, CJFG, CMCS, CRGR, DYFG, DYLA,
DYNF, EWSF, GCMB, GSBG, PLCB, RCHK, SPAN, STRPSSM, WVLD —
7 of these are the ones already corrected 2026-07-26 after independent Gen
404s, so no surprise there; the other 8 (bridge girder/camber-control trio
plus the railway/concurrent-group set) are newly reconfirmed, not new
corrections.
Decision, made with the user (not unilateral): given the scale (32
endpoints) and that it contradicts documented domain framing the author
themselves wrote, this was raised as an explicit question rather than
auto-applied. The user's read on it: the API clearly does respond
("분명히 통신이 되는데 only라고 쓴 것은 아닌 것 같음" — "it clearly
communicates, so writing 'only' doesn't seem right"), and whether an
engineer should actually drive bridge/moving-load features from a Gen NX
session is a separate, per-project judgment call ("목적에 따라 다르겠지만
엔지니어가 판단해서 사용해야 할 것 같음") — not something PRODUCTS
should gate. Confirmed: apply the same evidentiary bar used for
GEN_ONLY/HYPER_S_ONLY and correct all 32.
Action taken: all 32 classes' PRODUCTS = CIVIL_ONLY override removed
(back to the class default, gen+civil) across db/moving_loads.py (23),
db/analysis_control.py (5, the MVCT family), db/load_combinations.py
(2), db/dynamic_loads.py (1, THGC), db/bridge.py (1, ULFC).
docs/coverage.json updated to match (24 of the 32 needed a products
fix; 8 already said ["gen","civil"] there despite the SDK's PRODUCTS
disagreeing — the manual-derived coverage metadata had actually been right
and the SDK's own class attribute was the stale one). Five tests
(test_*_is_civil_only in test_analysis_control.py, test_dynamic_loads.py,
test_load_combinations.py ×2, test_moving_loads.py) that asserted a
ProductMismatchError on the Gen client were rewritten to assert the call
now succeeds instead. Module-level docstrings in moving_loads.py,
bridge.py, and the CIVIL_ONLY constant itself in db/base.py corrected
to stop citing the wrong example and to record the finding.
During this session's live probing, the user observed a brief popup on
the Civil NX side ("Civil에 뭔가 거부되었다는 팝업") — normal again by
the time it was reported, popup already dismissed, no session hang.
Everything run against Civil in this session was GET/.info() only (no
POST/PUT/DELETE), so the trigger isn't identified yet. The user was
re-attempting to reproduce it with a screenshot at the time of this note;
if a cause is confirmed, record it here rather than assuming GET is
unconditionally safe against this server the way this file has assumed
throughout.
2026-07-29 (final) — GET /db/CAMB can trigger the same Program Files write-permission dialog as crash recovery, confirmed A/B¶
While reproducing the CIVIL_ONLY sweep above for the user to watch, a modal
popup flashed on the Civil NX side mid-run: "...5 FCM General.mcb
액세스가 거부되었습니다" (access denied), for the product's own bundled
tutorial file at C:\Program Files\MIDAS\MIDAS CIVIL NX\MIDAS CIVIL
NX\Tutorial\5 FCM General.mcb. The user had that FCM tutorial model open at
the time. The API call itself still answered normally — this is the same
"HTTP success, modal dialog on the side" pattern this file has documented
before (see the crash-recovery _restore.mcb case and the /doc/SAVEAS
case in CLAUDE.md).
Isolated the trigger with a controlled A/B, same session, same call, one variable changed:
| Document location | GET /db/CAMB (FCM Camber Control) |
Popup |
|---|---|---|
C:\Program Files\...\Tutorial\5 FCM General.mcb |
{"message": ""} |
Yes |
Same file, moved to Downloads |
{"message": ""} |
No |
Confirmed: /db/CAMB — a plain read GET, not a write, not a crash — can
still trigger this dialog, whenever the open document sits in a
write-protected location. This generalizes the previously-known
crash-recovery-only case (_restore.mcb under Program Files, first seen
during the Gen NX hang investigation) into a broader pattern: some
GET-shaped commands apparently attempt to write an auxiliary/cache file next
to the document even to answer a read, and when that write is denied by
Windows, the dialog surfaces regardless of the command's nominal read/write
classification. Recorded as vendor report A-7's second, independently
reproduced trigger (docs/vendor_report_ko.md).
Practical implication for this SDK and its scripts: GET is not
unconditionally side-effect-free against this server the way this file has
assumed throughout — a document living under Program Files (or any other
path a standard account can't write to) is the actual risk factor, not the
HTTP method. scripts/live_readonly_sweep.py's docstring claim ("SAFE TO
RUN AGAINST AN OPEN MODEL... issues GET only") still holds for data
safety (no mutation, no discarded work) but should not be read as "will
never pop a dialog" — advise users to keep working documents off
Program Files-style paths before a sweep, the same advice already given
for A-7's crash-recovery case.
2026-07-29 (last) — full CRUD re-run on the newest Civil build, 43/43 clean including NMAS¶
With the user's FCM model already saved aside as a disposable copy, ran
scripts/live_crud_check.py --product civil --include-crashers against the
same live Civil NX session (this discards the currently-open document via
/doc/NEW, same as always — the FCM file itself was unaffected since it
was saved separately first). All 6 tiers, all 43 resources, full
create→read→update→read→delete→read round trip: 43/43 PASS, zero
failures, including /db/NMAS (create=ok read_back=ok update=ok
read_updated=ok delete=ok read_deleted=ok) — the first full Civil-side CRUD
confirmation of the omitted-rmX/rmY/rmZ fix from earlier today, not
just the Gen-side one already recorded above. Also ran a fresh
live_readonly_sweep.py --product civil --record-coverage against the FCM
model itself (before the CRUD run): 273/273 GET-capable resources answered,
zero 404s — a clean end-to-end confirmation that today's GEN_ONLY/
CIVIL_ONLY corrections match live behavior with no regressions.
Followed by scripts/live_crud_check.py --product gen --include-crashers
against the same-day Gen NX session: 37/37 PASS, zero failures,
including /db/NMAS again. The 6 missing cases versus Civil's 43 are
/db/CMCS (stage tier) and the whole moving tier (4 cases) — both
declared products=("civil",) inside the checker script itself, which
wasn't updated for today's CIVIL_ONLY→gen+civil corrections above.
Worth widening in a future session (MVCD/LLAN/MVHL/MVLD are now
confirmed to work on Gen too), but out of scope for this one.
2026-07-29 (very last) — /db/MVCD's Gen availability is per-CODE, not unconditional¶
Tried to widen scripts/live_crud_check.py's moving tier to also run on
Gen NX, since today's finding above showed the whole ch08 chapter answering
there. The checker's own discipline caught a real nuance immediately: its
/db/MVCD seed (CODE: "KOREA") came back REGRESS — a live 201 carrying
[Error] Errors detected in Moving Load Code Data.(Item:Unavailable moving
load code).
Isolated with a quick sweep of every documented CODE value against Gen:
KOREA -> [Error] ... Unavailable moving load code
CHINA -> [Error] ... Unavailable moving load code
KSCE-LSD15 -> [Error] ... Unavailable moving load code
AASHTO STANDARD -> created ok
AASHTO LRFD -> created ok
EUROCODE -> created ok
BS -> created ok
So /db/MVCD genuinely creates and round-trips on Gen NX — for the
US/Euro/UK codes. The Korea/China-specific codes 201 with an error there,
presumably a licensed-module gate scoped to the region code rather than a
route-level product restriction. This doesn't contradict the GEN_ONLY
finding above (route + /info both legitimately resolve on Gen) — it
refines it: route existence and per-value availability are different
questions, and GET/.info() alone can only answer the first.
Action: live_crud_check.py's core-tier /db/MVCD case now uses
"AASHTO STANDARD"/"AASHTO LRFD" instead of "KOREA"/"AASHTO LRFD", so
it runs unmodified and confirmed on both products (43/43 Civil, 38/38 Gen
after the change). The moving tier's other three cases (LLAN/MVHL/
MVHC/MVLD) stay Civil-only in this checker, since their fixture chain
is Korea-standard throughout (vehicle STANDARD_CODE: "KS-RB") and hasn't
been rebuilt around a Gen-available code — that fixture work is unstarted,
not evidence those routes are Civil-only (they aren't, per the GEN_ONLY
finding). PRODUCTS on the SDK classes themselves is unchanged by this —
this section is entirely about the checker script's fixture coverage, not
a source-level correction.
2026-07-29 (truly last) — /db/REBW's manual section doesn't match the live server at all¶
With a second real production Gen NX model opened (KDS/Korean-code
building, 4044 nodes, 4686 elements — the same model from this file's
STORY_PARAM/STORY_IRR_PARAM section above), re-ran the readonly sweep
(--record-coverage, 265/265 GET-capable Gen resources, zero errors) and
then spot-checked populated design-chapter data for manual drift, the same
way /db/STAG//db/TDNA were checked against the Civil FCM model earlier.
/db/REBW (ch24, "Modify Wall Rebar," 102 real rows) came back completely
unrecognizable against its own documented schema:
Documented (manual's own JSON Schema, matches this SDK's old WallRebarItem):
CREATE_SUB_WALL_ID, SUB_WALL_ID, STORY: {FROM, TO},
VERTICAL_REBAR: {NAME, DIST}, HORIZONTAL_REBAR: {NAME, DIST},
USE_END_REBAR, END_REBAR: {NAME, NUM, DIST},
BE_HORIZONTAL_REBAR: {NAME, DIST}, BOUNDARY_ELEMENT_LENGTH,
CONCRETE_FACE_TO_CENTER_OF_REBAR: {DW, DE},
USE_MODEL_THICKNESS, THICKNESS
Live GET /db/REBW:
{"ID": 0, "bUSE_MODEL_THICK": true, "THICK": 0, "DW": 0.05, "DE": 0.05,
"VER_BAR": {"NAME": "D16", "DIST": 0.2},
"HOR_BAR": {"NAME": "D13", "DIST": 0.25},
"END_BAR": {"NAME": "", "DIST": 0}, "NUM_END_BAR": 0,
"BE_HOR_BAR": {"NAME": "D10", "DIST": 0.2}, "BE_LENGTH": 0}
Every field is renamed (and DW/DE flattened out of any nesting), and
STORY doesn't exist as {FROM,TO} at all. Two checks isolated this to
/db/REBW specifically, not a systemic ch24 problem:
/db/REBB(ch24's sibling, "Modify Beam Rebar") matched its own documentation exactly —vMAIN_BAR_TOP,SHEAR_BAR,SKIN_BAR_NAME, all present as documented, real data./DESIGN/RC/KDS-41-20-2022/REBW(ch26, the KDS-specific sibling for the same physical walls, same 102 rows) also matched its own documentation exactly —VERTICAL_REBAR,HORIZONTAL_REBAR,CONCRETE_FACE_TO_CENTER_OF_REBAR: {DW,DE}, all present, long-form.
GET /info/db/REBW confirmed the abbreviated shape is the server's own
stated schema, not a GET-only quirk — it documents bUSE_MODEL_THICK,
VER_BAR, HOR_BAR, END_BAR, NUM_END_BAR, BE_HOR_BAR, BE_LENGTH,
and vSTORY_NAME: [string] (a story-name array, not a {FROM,TO} range)
as the Argument schema. Confirmed it's also the real write contract, not
just read: picked one existing wall (id 101), backed up its exact current
value, sent a PUT using the info-confirmed field names changing
VER_BAR.DIST from 0.2 to 0.99, verified the change landed on a fresh
GET, then restored the original value and verified the restore matched
byte-for-byte. Full round trip, real data, real Gen NX session.
Conclusion: docs/manual/24_DB_Design.md's /db/REBW section (and by
inheritance this SDK's old WallRebarPayload/WallRebarItem) documents a
schema the live server doesn't implement. A user following the manual's
worked example would have every field silently ignored or rejected — this
isn't a cosmetic drift, it's the whole payload contract. /db/REBB and the
ch26 KDS sibling being correct rules out "the whole rebar family is
misdocumented" — this looks like a defect isolated to /db/REBW's specific
manual section.
Checked against the official source directly — not just the vendored
copy. Per this file's own standing rule (never cite the vendored manual
repo as "the documentation" in anything sent externally), searched
MIDASIT's Zendesk Help Center API directly: the dedicated article for this
endpoint is
59359110968345 — "Modify Wall Rebar Data"
(distinct from
59236271208729,
the correct ch26 KDS-specific article). It documents the same long-form
names as the vendored copy (VERTICAL_REBAR, HORIZONTAL_REBAR,
CONCRETE_FACE_TO_CENTER_OF_REBAR, STORY: {FROM,TO}, ...). This rules
out a vendored-repo transcription error — the official MIDASIT
documentation itself doesn't match its own server's implementation. Direct
HTML fetches of Zendesk pages 403 for this tool; the JSON Help Center API
(/api/v2/help_center/en-us/articles/<id>.json) and article search
(/api/v2/help_center/articles/search.json?query=...) work and are the
way to reach a specific official article when a chapter's combined
reference article is too large to fetch in full.
Fix applied: WallRebarItem/WallRebarPayload in db/design.py
rewritten to the server-confirmed shape (ID, bUSE_MODEL_THICK, THICK,
DW, DE, VER_BAR, HOR_BAR, END_BAR, NUM_END_BAR, BE_HOR_BAR,
BE_LENGTH, vSTORY_NAME), with a docstring explaining the manual
mismatch and citing this section. The now-unused StoryRange/
WallEndRebarSpec/ConcreteFaceToCenterOfRebar helper TypedDicts were
removed (ch26's RcWallStoryRange/RcWallEndRebarSpec/
RcWallConcreteFaceToCenterOfRebar are separate, correct, untouched).
tests/db/test_design_setup.py's WallRebar create test updated to the
corrected field names. This is a real correctness fix — the old TypedDict
would have led a caller straight into the exact defect this session found.
Worth reporting to MIDASIT: see docs/vendor_report_ko.md.
2026-07-29 (later same day) — the 8 Hyper-S -M1 stubs, implemented from /info/db/...¶
Per the author's decision on the v1.0.0 gate's item (a) ("1번으로 해서 진행" —
go with option 1), pulled full GET /info/db/... JSON Schema bodies for all
8 previously-unimplemented Hyper-S stub endpoints against a live Civil NX
2026 (v2.2, build 06/18/2026) session, using a direct MidasClient(...,
strict_product=False) probe (not scripts/live_readonly_sweep.py this
time — the session disconnected from the relay partway through, before the
script itself could run; the direct probe's results were already captured).
5 of 8 resolved a full schema:
| Endpoint | GET | /info |
|---|---|---|
/db/STYP-M1 |
real populated row (STYPE: "3D", GRAV: 9.806, ...) |
full schema |
/db/MATL-M1 |
real populated row (MATL_NAME: "C24", MATL_TYPE: "CONC", PARAM[0].P_TYPE: 0) |
full schema |
/db/IMFM-M1 |
{"message": ""} (empty table) |
full schema |
/db/EPMT-M1 |
{"message": ""} (empty table) |
full schema |
/db/IEHG-BEAM-M1 |
{"message": ""} (empty table) |
full schema |
/db/IEHG-TRUSS-M1 |
{"message": ""} (empty table) |
404 |
/db/IEHG-GL-M1 |
{"message": ""} (empty table) |
404 |
/db/IEHG-PSS-M1 |
{"message": ""} (empty table) |
404 |
The 3 IEHG-{TRUSS,GL,PSS}-M1 endpoints answer GET (empty table on this
model) but their own /info/db/... route 404s — no schema route exists for
them specifically, unlike their sibling IEHG-BEAM-M1.
Two of the five resolved schemas turned out to have a genuinely different wire shape from their non-Hyper-S sibling, not just a product gate on an identical schema:
/db/MATL-M1'sPARAM[].P_TYPEis 0-indexed (Standard:0, Isotropic:1, Orthotropic:2) and nests user-defined fields under aUSER_DEFINEDsub-object, vs. non-Hyper-S/db/MATL's 1-indexedP_TYPEwith flat fields (ELAST,POISN, ... directly on the param object)./db/IMFM-M1nests fields underCONCRETE/STEELsub-objects with different names entirely (UN_CONC_NAME,CONF_CONC_NAME) vs. non-Hyper-S/db/IMFM's flatCONC_NAME/CONFINED_CONC_NAME.
/db/EPMT-M1's MODEL_TYPE is also an int (Tresca:0, VonMises:1,
MohrCoulomb:2, DruckerPrager:3, Masonry:4, ConcreteDamage:5) vs.
non-Hyper-S /db/EPMT's string codes ("TR"/"VM"/"MC"/...), and adds
two sub-objects (DRUCKER, MASONRY, CONCDMG) the non-Hyper-S variant's
chapter never documented at all.
Fix applied: implemented all 8 as proper DbResource subclasses —
StructureTypeHyperS (db/project.py), MaterialHyperS /
InelasticFiberMaterialLinkHyperS / PlasticMaterialHyperS
(db/properties/material.py), InelasticHingePropertyHyperS{Beam,Truss,
GeneralLink,Pss} (db/properties/hinge.py). Each payload TypedDict is
documented in its own docstring as /info-derived rather than
manual-transcribed. The 3 IEHG-* classes without their own /info route
carry an explicit ⚠️ docstring caveat that their single-field shape
(INEL_PROP_NAME) is assumed by sibling analogy to IEHG-BEAM-M1, not
independently confirmed — if that assumption is ever wrong, it'll surface
as a "Wrong Field" response on a real write, per this file's own
"Wrong Field usually means a bad value, not a bad field name" note (which
doesn't apply here since these would be genuinely wrong field names, an
exception worth remembering if it comes up).
docs/coverage.json updated: all 8 endpoints marked "status":
"implemented" with a live_verified entry citing this direct-probe method
(distinct from the sweep script's own live_readonly_sweep.py method
string, since the sweep script itself didn't get to run). Coverage is now
398/398 (100%). tests/db/test_hyper_s_products.py's family-size assertion
updated 13→21. This resolves the v1.0.0 gate's item (a) — see PLAN.md.
Two corrections caught by /code-review on 2026-07-30, after v1.0.0 shipped:
InelasticHingePropertyHyperSPss's docstring claimed "PSS" isn't stated in any available source — false. The manual repo'sINDEX.mdtitles the endpoint "Assign Inelastic Hinges — Point Spring Support (Hyper-S)", and04_DB_Properties.md's own chapter TOC calls it "... Point Spring (Hyper-S)" (a minor internal inconsistency in the manual — "Support" present in one title, absent in the other — but "Point Spring" either way). What's actually missing is a Specifications table, not the name. Fixed the docstring and itsNAMEfield (now "... Point Spring, Hyper-S)"). This is why the day's own rule matters: verify a claim against the actual source before asserting it, even a claim about what a source doesn't say.docs/coverage.json'slive_verified.methodstring was identical for all 8 Hyper-S stubs, which overclaimed schema confirmation forIEHG-{TRUSS,GL,PSS}-M1— their/inforoute 404s, so only GET was actually confirmed for them, unlike the other 5. Reworded theirmethodfield to say so explicitly, so a future reader of the coverage ledger (orscripts/check_manual_drift.py) doesn't skip re-verifying these three on the strength of a probe that never actually ran against their schema.
2026-07-30 — second independent live re-check of the 8 Hyper-S stubs¶
With a fresh Civil NX session (same build, v2.2 06/18/2026), re-ran
scripts/live_readonly_sweep.py for real this time (2026-07-29's original
recording used a direct probe, since the session disconnected — see above —
before the script itself could run). All 8 answered ok: STYP-M1,
MATL-M1, IMFM-M1, EPMT-M1, IEHG-BEAM-M1, IEHG-TRUSS-M1,
IEHG-GL-M1, IEHG-PSS-M1.
Also re-probed /info/db/... directly for all 8 to check the schema/no-schema
split still holds: it does, exactly. The 5 with a schema
(STYP-M1/MATL-M1/IMFM-M1/EPMT-M1/IEHG-BEAM-M1) returned the
identical field set as 2026-07-29 — a second independent confirmation, not
just a repeat of the same probe. The 3 without one (IEHG-TRUSS-M1,
IEHG-GL-M1, IEHG-PSS-M1) still 404 on /info — their INEL_PROP_NAME
shape remains an assumption by sibling analogy to IEHG-BEAM-M1, not
independently confirmed, and there is still no indication MIDASIT intends to
add an /info route for them.
docs/coverage.json's live_verified entries for all 8 updated to cite
scripts/live_readonly_sweep.py (the intended method, now that it actually
ran) with today's date, keeping the same schema-confirmed/unconfirmed
distinction from the code-review fix above.
2026-07-30 — a real AASHTO arch-bridge model, and rebuilding the moving-tier fixture¶
With a different real production Civil NX model open (an AASHTO-coded arch
bridge), ran a full scripts/live_readonly_sweep.py (281/281 ok, zero
404s — reconfirms every PRODUCTS classification holds on a third,
structurally distinct real model) and spot-checked the genuinely
CIVIL_ONLY bridge-chapter endpoints (CMCS, EWSF, PLCB, RCHK,
SPAN, STRPSSM, WVLD, CAMB, CJFG, CRGR, DYFG, DYLA, DYNF,
GCMB, GSBG) — all answer cleanly with 0 rows, meaning this arch bridge
simply doesn't use girder-camber/composite-girder features, not an error.
The moving-load chapter had real, meaningful AASHTO LRFD data: /db/MVCD
(CODE: "AASHTO LRFD"), /db/MVHL (the actual HL-93 design truck/tandem,
HL-93TRK/HL-93TDM, STANDARD_CODE: "AASHTO-LRFD"), /db/LLAN (2 real
lanes with populated LANE_ITEMS), and /db/MVLD (a load case combining
both HL-93 vehicles with the AASHTO SCALE_FACTORS combination rule).
Cross-checked field-for-field against VehiclePayload, TrafficLineLanePayload,
and MovingLoadCasePayload in db/moving_loads.py: zero drift — every
field name, nesting, and type matched. This also independently reconfirmed
(against genuine production data, not a synthetic test) the existing
LineLaneItem docstring warning that CENT_F must be nonzero when
MVCD.CODE="AASHTO LRFD" (CENT_F: 0.5 in the real data).
Follow-on: rebuilt scripts/live_crud_check.py's moving tier fixture
around this AASHTO LRFD/HL-93 shape, replacing the Korea-standard
(MVCD "KOREA", STANDARD_CODE "KS-RB") fixture that had kept the tier
Civil-only in the checker since 2026-07-29 (Korea/China/KSCE-LSD15 codes
hit a licensed-module gate on Gen; AASHTO does not). Ran it live against
this same Civil session — the user explicitly authorized this knowing it
calls /doc/NEW and discards the open arch-bridge model ("자유롭게 해") —
and all 4 resources (LLAN/MVHL/MVHC/MVLD) passed a full
create→read→update→read→delete→read round trip on the first run. Still
products=civil in the checker for now: the fixture is now
code-portable and the route-level evidence says it should also pass on
Gen, but that is an expectation, not something watched pass live yet —
widen products/flip to Gen-confirmed only once someone actually runs
--tier moving --product gen.
2026-07-30 (same day) — a real Eurocode PSC bridge model finds four schema gaps¶
Same session, model swapped to a different real production Civil NX model:
a PSC (prestressed concrete) bridge built with Eurocode, evidently by the
Free Cantilever Method (4 construction stages, ACT_ELEM/ACT_BNGR/
ACT_LOAD populated per stage, 24 real tendon profiles across groups
A1-C4). Full live_readonly_sweep.py again 281/281 ok. The genuinely
CIVIL_ONLY bridge-chapter endpoints all answered with 0 rows (this bridge
type doesn't use girder-camber features), same as the arch-bridge model
above — reconfirms PRODUCTS holds on a third, structurally distinct real
model.
Cross-checked real tendon/prestress/creep-shrinkage/moving-load data against
their TypedDicts (db/temperature_prestress.py, db/properties/material.py,
db/moving_loads.py) and found four confirmed gaps — smaller in scope than
/db/REBW but the same species of defect (manual under-documents, /info
and real data reveal more):
/db/TDNT(TendonPropertyPayload) was missingbRELAX("Relaxation coefficient - Check Box", boolean) — present in this model's real tendon data and in/info/db/TDNT, absent from both the manual's Specifications table and the TypedDict./db/TDPL(TendonPrestressItem) was missingGROUP_NAME("Group Name", string) — same story: real data has"GROUP_NAME": "PS1"on every item,/info/db/TDPLconfirms it, the manual's table doesn't mention it./db/TDMThas a third code branch,CODE="EUROPEAN", entirely undocumented. This model's concrete (C40/50) uses it with two dedicated fields,TCODE(int) andbSILICA(bool), neither in the manual's table nor the TypedDict (which only covered CEB-FIP and ACI).GET /info/db/TDMTreveals this endpoint's real schema is far larger still — roughly 70 fields spanning many more codes (JSCE, GB, JTG, and others) — only the EUROPEAN branch's two extra fields were added; the rest is noted as a known gap, not fixed, in the TypedDict's own docstring./db/MVHL(VehiclePayload) has 11 more country-specific sub-objects the manual never mentions at all.GET /info/db/MVHLlistsVEH_FR,VEH_CN,VEH_IN,VEH_CA,VEH_BS,VEH_EUROCODE,VEH_RU,VEH_KSCE_LSD15,VEH_AU,VEH_PL,VEH_ZAalongside the documentedVEH_DEFAULT, plus a second load-items arrayLOAD_ITEMS2. This model's real Eurocode "Load Model 1" vehicle (MVLD_CODE: 11) usesVEH_EUROCODEinstead ofVEH_DEFAULTand — more surprising — omitsSTANDARD_CODEentirely, even though the manual's own Specifications table marks it "Required".VEH_EUROCODEitself has ~50 fields (/infoschema) covering multiple Eurocode load-model sub-types (LM1/LM2/LM3, rail HSLM-A/B, permit loads); the flat scalar ones are now typed asVehicleEurocodeParams, with the three deeply nested, load-model-specific arrays (LOADCASES/VEHICLES/PERMIT_LOAD) left untyped, same treatment asSECT_I's precedent. The other 10 country-specific sub-objects are confirmed to exist via/infobut not individually typed — a real, larger backlog item if someone needs France/China/India/Canada/etc. moving-load support beyond what already works throughVEH_DEFAULT.
All four fixed in src/, plus a new test (test_vehicles_create_sends_veh_eurocode_without_standard_code)
covering the VEH_EUROCODE-without-STANDARD_CODE shape. 681 tests passing,
ruff clean. This is a genuine src/ correctness improvement (four
previously-unrepresentable real payload shapes now have accurate
TypedDicts) — adds to the pending version-bump case.
2026-07-30 (same day) — a real Eurocode railway bridge: confirms VehicleEurocodeParams, finds a CENT_F scope surprise¶
Model swapped again, same Civil session: a Eurocode railway bridge. Full
sweep 281/281 ok again; the CIVIL_ONLY railway-specific
RailwayDynamicFactor (/db/DYFG) has real, meaningful computed data
(INPUT_TYPE: 0 = Auto, DYN_FACTOR: 1.148... computed) that matches
RailwayDynamicFactorPayload exactly — no drift.
/db/MVHL has three real Eurocode rail load models — "Load Model 71",
"Load Model SW/0", "Load Model SW/2" (SUB_TYPE: 23, distinct from Load
Model 1's SUB_TYPE: 19 seen on the PSC bridge above) — using W1, DD1,
D1, W2, DD2, D2, V_LOAD_FACTOR, LONGI_DIST, ECCEN_VERT_LOAD.
Every one of these fields was already covered by VehicleEurocodeParams,
added minutes earlier from the PSC bridge's road-vehicle example — a second,
independent real-data confirmation of that fix, this time for the rail
load-model sub-type rather than the road one.
Also surfaced a genuine scope surprise in an existing, previously-trusted
note: LineLaneItem.CENT_F (/db/LLAN's LANE_ITEMS[].CENT_F) was
documented "AASHTO LRFD only" after the 2026-07-29 finding that omitting it
under MVCD.CODE="AASHTO LRFD" gets rejected server-side. This Eurocode
railway bridge's own LANE_ITEMS carry the identical populated value
(CENT_F: 0.5) — same value as the AASHTO arch-bridge model. Left
unresolved rather than "corrected": it isn't yet clear whether CENT_F is
genuinely active under Eurocode too, or just echoed back inertly regardless
of code (as FACT/WIDTH/ECCEN_VERT_LOAD have been seen to be on codes
that don't use them). LineLaneItem's docstring now flags this as an open
question rather than asserting either way — a candidate for a future
same-value-different-code write test if it matters to a caller.
2026-07-30 (same day) — a cable-stayed/suspension bridge: one more gap, STAG's NO¶
Model swapped again to a cable-stayed bridge (this turned out to be the same
FCM model from earlier in the session — recognizable by its ELNK "Stay"
records at nodes 27/78 and 129/180, LINK: "GEN", and a GRUP "Sag" node
group covering exactly those same two i-nodes for cable sag adjustment).
Full sweep 281/281 ok again.
Cross-checked RigidLinkItem (/db/RIGD, 49 real rows), ConstraintItem
(/db/CONS, 10 real rows), and ElasticLinkPayload (/db/ELNK) against
real data — all matched exactly, no drift.
ConstructionStagePayload (/db/STAG, 8 real stages including cable-sag-
specific ones that activate/deactivate the "Stay"/"Pin Connection" boundary
groups mid-sequence) was missing NO ("Construction Stage No.",
integer) — present in every real stage record and in /info/db/STAG, not
in the manual's Specifications table. Fixed. DACT_BNGR/DACT_ELEM's
REDIST (element force redistribution %) were already correctly typed and
matched the real data exactly.
Running tally for 2026-07-30's cross-model spot-checking (four real
production Civil NX models: arch bridge, PSC bridge, railway bridge,
cable-stayed bridge): 6 schema gaps found and fixed (TDNT.bRELAX,
TDPL.GROUP_NAME, TDMT's EUROPEAN branch, MVHL's VEH_EUROCODE +
10 other undocumented country sub-objects, STAG.NO), one open question
left unresolved (CENT_F's true code scope), and one existing fix
(VehicleEurocodeParams) independently reconfirmed twice more against
different real Eurocode load-model sub-types. Zero drift found everywhere
else checked across all four models.
2026-07-30 (later) — first Gen NX pass of the day: a small solid-element cantilever model, STLD.NO gap¶
Switched to a fresh Gen NX session (v2.1, build 07/28/2026) with a small
real model open — not a bridge this time: a 5m x 0.4m x 0.2m concrete
block cantilever modeled as 10 SOLID (hexahedral) elements, fixed at one
end (CONS all-6-DOF on the 4 end nodes), one user-named load case
(STLD "CASE1", TYPE: "USER"). Small model, but real (not /doc/NEW
scratch), and a different element family (SOLID) than anything spot-
checked so far this week (all bridge frame/beam models).
Full live_readonly_sweep.py re-run: 265/265 ok, zero newly-recorded
(all previously verified) — no regressions.
Cross-checked MaterialPayload/MaterialParam (/db/MATL, P_TYPE=2
isotropic concrete), ElementPayload (/db/ELEM, TYPE: "SOLID"),
ConstraintItem (/db/CONS), and UnitPayload (/db/UNIT) against real
data — all matched exactly.
StaticLoadCasePayload (/db/STLD) was missing NO ("Ordering Index
in GUI") — present in the real record ({"NO": 1, "NAME": "CASE1", "TYPE":
"USER", "DESC": ""}) and documented in the manual's own Specifications
table (06_DB_Static_Loads.md, marked "Read Only"), just never
transcribed into the TypedDict. Same class of gap as STAG.NO two
sections up — a read-only GUI-ordering field the manual documents but this
SDK hadn't typed yet. Fixed. TYPE: "USER" ("User Defined Load") is a
real documented code, not a mystery value — first row of the Load Type
table.
2026-07-30 (later still) — 🎉 POST /db/NMAS no longer crashes on Civil NX v2.2, build 07/29/2026¶
User reported MIDASIT shipped a patch and asked to verify. Fresh Civil NX session, v2.2 build 07/29/2026 — one day newer than the build used for reproductions #10-12 (v2.2 build 07/28/2026, see "final" root-cause section above). Empty document (0 nodes), so no data at risk.
Reproduced the exact historical trigger on a raw client.request() call
(bypassing NodalMass's own rmX/rmY/rmZ auto-fill workaround, which
would have masked the question): created node 1, POST /db/NMAS with only
mX/mY/mZ set — the omitted-rotational-fields shape that killed the
session in all 15+ prior reproductions across both products. This time:
201 in 0.5s, session stayed alive. Repeated on a second node (mX/mY/
mZ again omitted-rm) since the original bug specifically needed a second
call on a different node to trigger — same result, 0.1s, alive.
verify_connection() before/after both showed "connected", and a
follow-up GET /db/NMAS showed both records with rmX/rmY/rmZ now
correctly defaulted to 0 server-side — meaning MIDASIT's fix isn't just
"stopped crashing", it's now applying the documented default like it
always should have. Cleaned up both test nodes/masses afterward; document
back to empty.
This looks like a genuine server-side vendor fix, not a fluke — same
account, same reproduction method that was 15/15 reliable before, now 2/2
clean on the newer build. Still only one account/session, so treat as
strong evidence rather than final confirmation (see the Caveat below); the
right trigger to fully retire NodalMass's auto-fill workaround is
independent reproduction of the fix (different account/session, and a
matching Gen NX patch — this was Civil NX only, Gen NX's own last-known
build (v2.1, 07/28/2026) was not re-tested here and NMAS was never
observed to be product-specific anyway). Not removing the workaround
yet — it's harmless when the field is now defaulted correctly either way
(explicit 0.0 in, explicit 0 out), and removing it prematurely would
regress hard the moment someone hits this from an unpatched build.
2026-07-30 (later) — closing the "never GET-swept" gap: /ope, /view, /post plain-function endpoints¶
Coverage stood at 304/398 live-verified with 94 endpoints unaccounted for.
Checked why: scripts/live_readonly_sweep.py only discovers DbResource
subclasses (_all_resources() walks the class hierarchy), so the whole
/doc/*, /ope/*, /view/*, /post/*, /DESIGN/* families — all plain
functions per this SDK's own layout convention — were never reachable by
the sweep regardless of whether they actually work, not because they're
untested-and-risky. Some of them already had been tested live in earlier
sessions (STORY_PARAM/STORY_IRR_PARAM on 2026-07-29) without ever
getting a coverage.json entry, since nothing writes to that file except
the sweep script's --record-coverage flag.
With both Civil NX (v2.2, 07/29/2026) and Gen NX (v2.1, 07/28/2026) connected, empty documents on both (0 nodes), manually probed the GET-shaped subset of these plain functions directly (not through the sweep tool, which doesn't know about them):
| Function | Endpoint | Civil | Gen |
|---|---|---|---|
ope.get_project_status |
/ope/PROJECTSTATUS |
ok | ok |
ope.get_section_properties |
/ope/SECTPROP |
ok (empty) | ok (empty) |
ope.get_story_check_parameter |
/ope/STORY_PARAM |
404 | ok |
ope.get_story_irregularity_check_parameter |
/ope/STORY_IRR_PARAM |
404 | ok |
view.get_selection |
/view/SELECT |
ok | ok |
post.pre_process.get_material_table |
/post/TABLE (pre-process) |
ok (empty) | ok (empty) |
STORY_PARAM/STORY_IRR_PARAM's Civil 404 is now confirmed a third
time (previously: the 2026-07-29 sweep, then the same-day live re-check
with both products open) — solid evidence for the Gen-only restriction
that this SDK documents in the functions' own docstrings but doesn't
(and, being plain functions, can't cleanly) enforce client-side. All 6
recorded into coverage.json's live_verified field; 310/398 total now.
post.pre_process.get_material_table was one spot-check standing in for
all 10 TABLE_TYPE values in that module (they share the same
post.base.get_table()/unwrap_table() plumbing) — the other 9 weren't
individually re-probed.
Left deliberately untouched this pass — all mutate the model, the document itself, or need a completed analysis first, so they get their own explicit go-ahead rather than folding into this GET-only sweep:
/doc/*lifecycle (OPEN/CLOSE/SAVE/SAVEAS/IMPORT/EXPORT/STAGAS) — touches real files on the machine running NX; this file's own history has a confirmedProgram Files-path modal-dialog trap for even GET-shaped calls, so a write-shaped one deserves more care, not less./ope/*actions (DIVIDEELEM,USLC,LINEBMLD,AUTOMESH,SSPS,EDMP,STOR,STORPROP,MEMB,GUSTFACTOR,LCOM-*,GSBG) — real model mutations (mesh, load combos, story calc); both open documents are empty right now so there's nothing to safely exercise them against yet anyway./view/*actions (CAPTURE,PRECAPTURE,ANGLE,ACTIVE,DISPLAY,RESULTGRAPHIC) —CAPTURE/PRECAPTUREwrite image files to the NX machine (same file-path risk class as/doc/*); the rest are harmless view-state toggles but weren't in this pass's scope./post/TABLE(Analysis Result / Analysis Story categories) and/DESIGN/*/*-ANALchapters — need a completed/doc/ANALrun first, and*-ANALcalls have a confirmed history of hanging Gen NX (see theCC-ANAL/BC-ANALsections above) — short-timeout-and-poll discipline applies, not a plain probe.
2026-07-30 (later still) — a synthetic frame model, and a new crash candidate: POST /ope/EDMP¶
User authorized going further into the remaining /ope/*//view/*/analysis
categories and building whatever model was needed ("모델 필요하면 직접
만들어서 진행해"). Built a synthetic 2-bay, 2-story steel frame on the same
empty Gen NX session (9 frame nodes + 4 unconnected quad nodes for a later
AUTOMESH attempt, 10 BEAM elements, 1 isotropic steel material, 1
DBUSER solid-rectangle section, base constraints, one "DL" load case,
two /db/STOR records) — all standard, previously-proven /db/* writes.
Ran a batch of the remaining mutating /ope/* actions against it:
| Action | Endpoint | Result |
|---|---|---|
assign_members |
/ope/MEMB |
ok |
get_story_properties |
/ope/STORPROP |
404 (separate open question, see below) |
calculate_story |
/ope/STOR |
ok — recalculated the two /db/STOR records' geometry-derived fields (STORY_LEVEL, WIND_FLOOR_WIDTH_Y, WIND_CENTER_Y, ...) from actual model geometry, overwriting the placeholder values seeded above; expected behavior for an auto-calculate action, not a bug |
divide_elements |
/ope/DIVIDEELEM |
ok — split element 7 into two elements at a new midpoint node |
calculate_gust_factor |
/ope/GUSTFACTOR |
ok |
change_property (TYPE="NSM", AUTO=true) |
/ope/EDMP |
🛑 30s read timeout, then Gen NX crashed |
create_line_beam_load |
/ope/LINEBMLD |
timed out — but this ran after EDMP already broke the session, so this failure doesn't mean anything about LINEBMLD itself; needs re-testing post-recovery |
POST /ope/EDMP is a new crash candidate, confirmed once: the call
itself read-timed-out (30s), a follow-up plain GET /db/NODE on the same
session also timed out, and verify_connection() still reported
"connected" throughout — the exact "modal dialog blocks every /db/*
call while /mapikey/verify keeps answering" pattern this file already
documents for other crashes. The user confirmed Gen NX showed the familiar
"[Error] Failed to disconnect the work session..." license dialog (same
one seen in the /doc/NEW and pre-fix NMAS crashes) — a full crash, not
just a slow call.
Not yet root-caused. Only one payload variant was tried
({"NODE_ELEMS": {"KEYS": [1,2,3]}, "TYPE": "NSM", "AUTO": true, "CODE":
"Korean Standard", "H_VS": 0.5}, targeting 3 BEAM elements). Unlike the
NMAS saga, this is a single reproduction with no A/B isolation yet —
could be EDMP itself, the AUTO=true auto-calculate path specifically,
the CODE value, or something about the target elements. Flagged here
rather than pursued immediately; whether this gets the full NMAS-style
isolation treatment or just a documented-and-deprioritized flag (like the
*-ANAL hangs) is the user's call once Gen NX is back up.
/ope/STORPROP (get_story_properties) 404'd on its first-ever live
call, independent of the EDMP crash (it ran two calls earlier in the same
batch, before anything broke). Open question, not yet investigated:
possibly needs calculate_story//db/STOR data in a different state,
possibly a genuine route issue, possibly a body-shape problem surfacing as
404 instead of a schema error (seen before in this project — worth
comparing against the manual's worked example rather than assuming the
docstring's FORMAT/PLACE guess is the actual cause).
2026-07-30 (later still) — after recovery: LINEBMLD/AUTOMESH/LCOM-* sorted out, then a second crash on POST /ope/USLC¶
Rebuilt the same synthetic frame (Gen NX's crash-recovery "New Project"
step discards the document, as expected) and continued through the
remaining /ope/* actions.
/ope/LINEBMLD (TARGET.METHOD) sorted out: METHOD=0 (NODE-defined
load line) works exactly per the manual's own worked examples — confirmed
live with a UNILOAD on nodes [7,8], echoed back correctly
(D/P padded to 4 elements: [0.25, 0.85, 0, 0] / [-3, -3, 0, 0]).
METHOD=1 (selected elements) still fails identically a 3rd time
(TYPE=UNILOAD and TYPE=CONLOAD, both with a real, existing element in
TARGET.ELEM) — 3/3 "Wrong Field", 0/1 success. Documented in
ope.py's LineLoadTarget docstring as unconfirmed/likely broken; not
pursued further (no untried field found that changes the outcome).
/ope/AUTOMESH needs boundary elements, and they must be frame-
capable (BEAM), not TRUSS: the first attempt used METHOD="Nodes"
with 4 isolated, unconnected corner nodes and got a generic
"MIDAS GEN NX second query is wrong" — not a documented error string,
and not obviously about a missing field. Switching to METHOD="Line
Elements" with 4 boundary elements ringing the quad (plus adding the
THICKNESS the worked example includes but the Parameters table marks
merely "Optional") got further but still failed
("[Error] Invalid element list!") when those 4 boundary elements were
TRUSS. Rebuilding the same 4 elements as BEAM succeeded immediately,
generating 4 real PLATE elements. Reads as a genuine element-type
restriction (a TRUSS — no bending stiffness — plausibly can't bound a
meshed plate region) rather than a schema documentation gap; not written
up as a defect, just noted here since the manual doesn't say which line-
element types qualify.
/ope/LCOM-CONC, /ope/LCOM-STEEL, /ope/LCOM-SRC all worked with a
minimal payload ({"OPTION": "ADD", "DGNCODE": "<per-endpoint code
string>"} — every other field really is optional as documented), each
generating 2 real combinations (STRENGTH/SERVICE) from the model's
single "DL" load case. /ope/LCOM-GEN (CODE_SELECTION="CONCRETE")
failed with "Wrong Field" on a payload built from the TypedDict's own
documented-required fields for that body
(RS_SCALE_FACTOR:[], ORTHO_EFFECT:{OPT_USE:false},
ADDITIONAL_LOAD:{SPECIAL_LOAD:{OPT_USE:false},
VERTICAL_LOAD:{OPT_USE:false}}, CS_ANALYSIS:false,
PRESTRESS_LOSS:false) — not yet investigated further, lower priority
since LCOM-CONC already covers the same design body successfully via
its own dedicated endpoint.
🛑 POST /ope/USLC crashed Gen NX — a second, independent crash
candidate this session. Payload: {"POSITION": "CONC", "LCOM_LIST":
[{"TYPE": "CONC", "NAME": "cLCB1"}, {"TYPE": "CONC", "NAME": "cLCB2"}]},
referencing two real combinations that LCOM-CONC had just generated
successfully moments earlier in the same session. Same signature as the
EDMP crash: the call itself read-timed-out (25s), a follow-up plain
GET /db/NODE also timed out, verify_connection() still reported
"connected" throughout, and the user confirmed Gen NX itself was dead
("죽음") requiring the same New-Project-then-restart recovery.
Two crash candidates from one session's /ope/* sweep (EDMP, USLC,
2 of 7 actions attempted) changes the risk calculus — this isn't a
single fluke the way early NMAS reproductions looked, it's a live
~30% hit rate on this endpoint family so far. Deliberately not
continuing to blindly try the remaining untested actions (SSPS, GSBG)
without the user's explicit go-ahead each time; asked the user directly
whether to keep pushing through /ope/* (accepting the crash risk) or
switch to safer categories (/view/*, then analysis + result tables) and
leave the rest of /ope/* flagged-but-untested, the same way *-ANAL is
handled elsewhere in this file.
/ope/STORPROP (get_story_properties) 404'd on its first-ever live
call, independent of the EDMP crash (it ran two calls earlier in the same
batch, before anything broke). Open question, not yet investigated:
possibly needs calculate_story//db/STOR data in a different state,
possibly a genuine route issue, possibly a body-shape problem surfacing as
404 instead of a schema error (seen before in this project — worth
comparing against the manual's worked example rather than assuming the
docstring's FORMAT/PLACE guess is the actual cause).
2026-07-30 (later still) — user accepted the crash risk; SSPS, ANAL, result/story tables, and both design-check *-ANAL families all pass¶
User explicitly chose to keep going despite the EDMP/USLC crashes
("계속 진행 (크래시 감수하고)"). Rebuilt the frame a third time (same
9-node/10-BEAM shape, no stories or quad nodes this round) and continued.
/ope/SSPS worked cleanly, no crash: CONVERT_TO=POINT_SPRING,
ELEMENT.TYPE=FRAME on two real BEAM elements, matching the manual's
own worked example almost exactly — generated real /db/NSPR point-spring
records with computed SDR/Cr/EFFAREA/DK fields.
/view/ANGLE, /view/ACTIVE, /view/DISPLAY all worked, no crash —
cosmetic view-state actions, as expected.
/doc/ANAL timed out (30s) — but this was a save-confirmation dialog,
not a crash. The call itself read-timed-out and the follow-up GET
/db/NODE also timed out, looking identical to the EDMP/USLC crash
signature — but the user checked Gen NX and found a plain "저장해달래"
(save-changes) prompt, not the "Failed to disconnect" crash dialog. This
is CLAUDE.md's already-documented "any confirmation dialog blocks the
whole session until dismissed" behavior, reproduced for /doc/ANAL
specifically for the first time in this file, and importantly: not
every session-blocking dialog is a crash — the two need to be told
apart by asking the user what's actually on screen, not assumed from the
timeout pattern alone. After the user saved, the session unblocked
immediately (model intact, 9 nodes) and a retried /doc/ANAL succeeded
in 5s.
/post/TABLE (Analysis Result + Analysis Story categories) both
confirmed working post-analysis: get_reaction_table and
get_beam_force_table (result_1.py) returned real per-node/per-element
rows (all zero, since the model's one "DL" load case never had an
actual load value assigned — expected, not a defect); get_story_drift_table
(story.py) returned a valid empty response (no lateral/seismic load to
report on). One spot-check per category, not all ~25/~16 table types.
/view/RESULTGRAPHIC worked (CURRENT_MODE="reactionforces/moments")
now that real analysis results existed.
Both design-check *-ANAL families tested — neither hung. User
explicitly accepted the extra risk here too (this family's docstring
already warns of a documented Gen NX hang requiring a forced process
kill, a step beyond anything recovered from today via the graceful
New-Project dialog flow). perform_steel_code_check (/DESIGN/STEEL/
KDS-41-30-2022/CODE-ANAL, PERFORM_TYPE=ALL) and perform_column_check
(/DESIGN/RC/KDS-41-20-2022/CC-ANAL, same) both answered in under 2
seconds with clean, informative errors ("failed:LoadCombination" and
"failed:Material, Section, LoadCombination, ElementType, Axis,
SectionType, SectionData, Rebar, Analysis, BeamData" respectively) —
neither ever completed a full check, since the synthetic model has no
active load combination and (CC-ANAL's case) no concrete/rebar data at
all. This does not clear the historical hang risk — the past hangs
happened on a real RC model with actual concrete/rebar data actually
reaching the design-check computation, a code path this synthetic model
never got close to. Follow-up CC-TABLE/CODE-TABLE calls also failed
cleanly ("MIDAS GEN NX second query is wrong"), no hang either.
Two open questions parked, not resolved:
- /ope/STORPROP 404'd a 3rd time even with real /db/STOR data present
and FORMAT="Default" (the manual's own worked-example value) — ruling
out both of the two leading hypotheses from the earlier attempt. Genuine
cause still unknown; documented in ope.py's StoryPropertiesArgument
docstring.
- /ope/LCOM-GEN (CODE_SELECTION="CONCRETE") still fails "Wrong
Field" even with every documented-required field for that body
present. Not pursued further since LCOM-CONC already covers the same
design body successfully; documented in generate_load_combination_general's
docstring.
- A second /ope/LCOM-STEEL call (regenerating combinations on a
fresh model iteration, this time to feed CODE-ANAL) failed
("Set_DefaultLoadComb failed; check CheckLcom history...") after an
earlier identical-shaped call had succeeded cleanly in a prior model
iteration. Not reconciled — possibly some hidden state dependency,
possibly unrelated to the payload at all.
Coverage after this whole multi-crash session: 328/398 live-verified
(+24 from the day's starting 304), covering /ope/*, /view/*,
/post/TABLE's two analysis categories, and a first live pass at the
*-ANAL design-check family.
2026-07-30 (later still) — 🎉 POST /db/NMAS no longer crashes on Gen NX v2.1, build 07/30/2026 either¶
User reported MIDASIT shipped a Gen NX patch too and asked for the same live re-verification already done for Civil. New build confirmed via the About dialog: MIDAS GEN NX 2026 (v2.1), build 07/30/2026 — one day newer than every Gen build tested earlier this session (07/28/2026).
Mid-test wrinkle, not a defect: the session originally connected via a
saved key started answering 404 "client does not exist" /
verify_connection() → "disconnected" — genuinely different from every
other disconnect signature seen this session (which always showed
"connected" while /db/* timed out). Turned out to be a different
machine entirely: the user runs Gen NX on two separate PCs (A and B)
with independent MAPI keys, and the originally-saved key was PC B's,
which had gone offline for an unrelated reason. The user supplied PC A's
key instead, which connected cleanly. .env updated with a note about
the two-PC setup so a future stale-key confusion is diagnosed faster.
On PC A's freshly patched session (0 nodes, scratch document): reproduced
the exact historical trigger — two nodes, two POST /db/NMAS calls each
omitting rmX/rmY/rmZ, the shape that reliably killed both products
before the fix. Both calls succeeded in 0.1s each, verify_connection()
stayed "connected" throughout, and the follow-up GET /db/NMAS showed
the server correctly defaulting the omitted fields to 0 itself — same
signature as Civil's confirmed fix earlier today. Test nodes/masses
cleaned up afterward; document back to empty.
Both Civil NX (v2.2, 07/29/2026) and Gen NX (v2.1, 07/30/2026) now
confirmed fixed, closing out the last open caveat from the Civil
confirmation ("Gen NX was not re-tested"). Still only one account/session
per product; independent reproduction (different account, or a third
session) would raise this from "strong evidence" to "settled". NodalMass's
SDK-side auto-fill workaround stays in place regardless — see the earlier
Civil confirmation section's reasoning, which applies identically here
(harmless once the server also defaults correctly; still needed for
anyone on an unpatched build).
2026-07-30 (last) — EDMP/USLC crashes confirmed independent of NMAS's fix, filed as MAPI-2425/MAPI-2426¶
User asked to retry today's two /ope/* crashes (EDMP, USLC) on the
same Gen NX build just confirmed to fix NMAS (v2.1, 07/30/2026), to see
whether the same patch happened to fix them too.
Both crashed again, on the first retry each. /ope/EDMP with the
identical payload from earlier (NODE_ELEMS.KEYS on 3 real BEAM
elements, TYPE=NSM, AUTO=true) timed out at 25s; verify_connection()
came back "disconnected" this time (a different signature than earlier
today's "connected"-but-blocked pattern — possibly a harder crash, or
just a different failure mode of the same underlying issue). User
confirmed Gen NX had died and restarted it. /ope/USLC (POSITION=CONC,
referencing a real load combination) crashed identically on its retry
too, "connected"-but-blocked this time. Conclusion: these are
independent defects from NMAS — the patch that fixed NMAS did nothing
for either of them.
Side finding while rebuilding for the USLC retry: /ope/LCOM-CONC and
/ope/LCOM-STEEL (auto-generate load combinations), which had worked
cleanly with a minimal payload earlier the same day, now failed with
"Set_DefaultLoadComb failed; check CheckLcom history (e.g. duplicate
LCOM names, name length, stage gate)." on a freshly-restarted Gen NX
session with a brand new empty document — not explained, mentioned in the
USLC ticket as a possibly-related data point rather than claimed as
understood. Worked around by writing the combination directly via
/db/LCOM-CONC (the DbResource, not the /ope/LCOM-CONC generator) to
get USLC a real combination name to reference.
Filed MAPI-2425 (/ope/EDMP) and MAPI-2426 (/ope/USLC) under
epic MAPI-1200, both linked "relates to" MAPI-2378 (NMAS) and to each
other, via the Atlassian MCP directly. A JQL search first ruled out an
existing duplicate — MAPI-597 ("[OPE] Change Property") looked like a
candidate but is an unrelated, already-closed 2024 ticket about a
Confluence spec page, not a crash. Unlike MAPI-2378, neither new issue
claims a root cause — both are framed honestly as "reproduced twice
(pre- and post-NMAS-patch), trigger not yet isolated," asking MIDASIT to
check server-side logs rather than asserting a fix. Also noted: mid-session,
the "disconnected" verify_connection() reading once turned out to mean
a different physical PC's Gen NX had gone offline, not a crash on the
PC actually being tested — the user runs Gen NX on two machines (A/B)
with independent MAPI keys, so a stale-looking key needs checking against
"which PC" before assuming a crash.
Also worth flagging for anyone reading this file to decide what to test next: the Gen NX session reconnected mid-troubleshooting with 710 real nodes already loaded (not the empty scratch document expected after a crash-recovery New Project) — meaning at some point the user's own real work was open in the same window this testing used. No write calls were made against that state; testing stopped as soon as it was noticed.
2026-07-31 — Civil NX re-check of today's Gen-only confirmations, plus the LCOM-CONC/STEEL/SRC 404¶
With Civil NX v2.2 (build 07/29/2026) open on the same synthetic frame model built earlier for the EDMP/USLC session, repeated the endpoints that had only been spot-checked on Gen so far:
/ope/DIVIDEELEM,MEMB,GUSTFACTOR,SSPS— all worked identically to Gen, same payload shapes./ope/LINEBMLD—TARGET.METHOD=0confirmed working on Civil too (matching the manual's worked example, same as Gen);METHOD=1not re-tried here (already unconfirmed/likely broken on Gen)./ope/AUTOMESH— same element-type restriction found on Gen holds on Civil: 4 boundary elements asBEAMsucceeded and generated realPLATEelements;TRUSSwas not re-tried (already known to fail on Gen)./view/ANGLE,ACTIVE,DISPLAY— all worked identically to Gen.- New finding:
/ope/LCOM-CONC,LCOM-STEEL,LCOM-SRCall 404 on Civil NX with the identical minimal payload ({OPTION, DGNCODE}) that generates load combinations cleanly on Gen NX. Single reproduction per endpoint, on the same synthetic frame model shape used for the successful Gen calls earlier today. Documented in each function's docstring inope.py(commit3d2695e), following the same "confirmed Gen-only, not enforced client-side" pattern already established forSTORY_PARAM/STORY_IRR_PARAM.
Then continued into the items that hadn't been attempted on Civil yet at all:
/doc/ANAL— ran clean, no save dialog this time (the model had already been saved from earlier work), matching the pre-existing 2026-07-22live_verifiedrecord for this endpoint (which already covered both products fromlive_smoke.py)./post/TABLE(Analysis Result category) —get_reaction_tableandget_beam_force_tableboth returned real non-zero rows this time (the Civil model has AUTOMESH-generated plates with real self-weight, unlike Gen's earlier all-zero-load test) — expected, not a defect./post/TABLE(Analysis Story category) —get_story_drift_tablefailed with"there was an error creating utbl. (ex PostMode ...)"on Civil. Not treated as a new defect:/db/STOR(Story data) was already confirmed Gen-only earlier in this SDK's history (db/project.py'sStory.PRODUCTS = GEN_ONLY), so a Story-table read having nothing to read on Civil is the expected consequence, not a route-level break. Not added to this endpoint's confirmed-products list.CODE-ANAL(steel) andCC-ANAL(RC column) — both re-ran cleanly on Civil, matching the Gen result: no hang, fast (<2s) informative "failed:..." errors listing missing prerequisites (load combination, material, rebar, etc.). Same caveat as the Gen finding applies: this doesn't clear the historically-hung code path, since the synthetic model still has no real concrete/rebar/load-combination data to reach it.
Civil session stayed "connected" throughout with no crashes. All of the
above recorded in docs/coverage.json, coverage steady at 398/398
implemented / 328/398 live_verified (this round only added products/method
detail to already-verified entries, no new endpoints crossed into
live_verified for the first time).
2026-07-31 (later) — a real production cable-stayed bridge on Civil NX closes 28 read-only gaps¶
The user loaded a real production model into the same Civil NX session
(v2.2, build 07/29/2026): 273 nodes, 278 elements (202 TENSTR cable-type
plus 76 BEAM), no analysis run yet, no design/rebar data. This is genuine
user data, not a scratch file — no write/execute call with any known crash
or hang risk was made against it; everything below is a GET-shaped POST
that only reads or reports "nothing to show yet."
Closed 28 of the previously-unreachable /post//DESIGN read-only
table endpoints (coverage 328 → 356/398) by calling each with a minimal
valid argument and confirming the route + argument shape are accepted and
the error handling is clean:
/post/PM,STEELCODECHECK,BEAMDESIGNFORCES,COLUMNDESIGNFORCES,BRACEDESIGNFORCES,WALLDESIGNFORCES,STEELMEMBERDESIGNFORCES,SRCBEAMDESIGNFORCES,SRCCOLUMNDESIGNFORCES,COLDFORMEDSTEELMEMBERDESIGNFORCES(post/design.py) — all answered"Please Check/perform Analysis"or"there was an error creating utbl"./DESIGN/STEEL/KDS-41-30-2022/CODE-TABLEandTABLE— same "please perform analysis" / utbl error pattern./DESIGN/RC/KDS-41-20-2022/BD-TABLE,CD-TABLE,BRD-TABLE,WD-TABLE,HCD-TABLE(design_forces.py) — all "please perform analysis"./DESIGN/RC/KDS-41-20-2022/BC-TABLE,CC-TABLE,BRC-TABLE(checks.py) initially failed"Wrong Field"with onlyELEMSset — turned outTABLE_TYPE("MEMB") is required and I'd omitted it; once added, all three answered cleanly with "please perform analysis". Not an SDK defect, just an easy-to-miss required field matchingCODE-TABLE's own shape./DESIGN/RC/KDS-41-20-2022/WC-TABLE,TABLE(x3, one physical route shared by Column/Brace/Beam Design Forces per its own docstring) — same pattern./DESIGN/SRC/AIK-SRC2K/BC-TABLE,CC-TABLE,TABLE(x2, Beam/Column Design Forces sharing one route) — same pattern.
Session stayed "connected" throughout, no crashes, no hangs — but note
none of these ever returned real populated data, only clean
"nothing to check yet" errors, since the model has no analysis/design
results. Recorded in coverage.json as confirming route, argument shape,
and error-handling only; flagged for a follow-up pass once real analysis
and design results exist on a model like this.
/ope/STORPROP re-confirmed 404 on Civil too (previously only tried
on Gen), this time against real data, not a synthetic model. Consistent
with /db/STOR (Story) already being Gen-only, though the original Gen
404 itself was never root-caused, so "this whole route is Gen-only" stays
a plausible guess, not a confirmed fact. Noted in StoryPropertiesArgument's
docstring.
Explicitly NOT touched, and why — all of these need either a real file path on the NX host machine or the user's explicit go-ahead given this is now real production data, neither of which was available/asked for in this round:
/doc/OPEN/CLOSE/SAVE/SAVEAS/STAGAS/IMPORT/IMPORTMXT/EXPORT/EXPORTMXT— need a safe file path from the user./view/CAPTURE/PRECAPTURE,*-REPORTacross all three design families,DREULT,CDESIGN— all requireEXPORT_PATH(write a file on the NX machine); same blocker as/doc/*.- All remaining
*-ANAL"perform" endpoints (BD/CD/BRD/WD/HCD-ANAL,BC/BRC/WC-ANALunder RC-KDS,BC-ANAL/CC-ANALunder SRC) — this family has documented hang history (perform_column_check/perform_wall_design, see earlier 2026-07-25 sections); not run against real data without asking first. /DESIGN/SRC/AIK-SRC2K/OCHECK— iterative re-analysis/optimization, flagged in its own docstring as "never independently tested," at least as much risk as the*-ANALfamily./DESIGN/SRC/AIK-SRC2K/DSRC— PUT/DELETE-only config write (sets the active SRC design code); skipped rather than mutate a real model's settings without asking, even though it's likely low-impact./ope/LCOM-GEN(still "Wrong Field" from 2026-07-30, not re-attempted: it's a write, and re-debugging it means adding combos to real data) and/ope/GSBG(needs a load combination with real analysis results plus a Bridge Group defined — this model has neither yet:/db/STLDshows only one"Self Weight"case, and there's no dedicated bridge-group/db/*resource in this SDK to create one via API)./ope/EDMP/USLC— already known Gen NX crashers (MAPI-2425/2426), not retried here at all (different product, and real data regardless).
2026-07-31 (later still) — a real modeling defect found and fixed on the bridge, then a real /doc/ANAL confirms post-analysis progression¶
Off to the side from SDK verification: the user spotted that the deck in
the 3D view looked like it was "standing up" instead of lying flat, and
asked me to check. Node-coordinate inspection showed the deck centerline
itself was correctly horizontal (X 0-657m, Y 5.5m constant, Z gently
curving 20.7-25.2m) with ANGLE: 0 on every deck BEAM element (203-254)
— no rotation/orientation bug. The real cause turned out to be /db/SECT
id 3 ("Deck"), a Box section with H and B swapped: vSIZE was
[11, 1.6, 0.04, 0.04, ...] (11m tall, 1.6m wide) instead of the clearly
intended [1.6, 11, ...] (1.6m tall, 11m wide — matching the deck's real
11m Y-width exactly). Fixed live with the user's consent:
PUT /db/SECTwithvSIZE[0]/vSIZE[1]swapped succeeded, but theSTIFFsub-object (Area/Asy/Asz/RXX/RYY/RZZ — note: despite theRprefix these are moment-of-inertia-type values, not radii of gyration; the manual doesn't document thisSTIFFresponse shape at all for/db/SECT) was NOT recomputed by the PUT — it stayed stale at the old H=11/B=1.6 numbers even after the geometry changed.- The user opened the Section Data dialog in the Civil NX GUI and clicked
"Calc. Section Properties", which recalculated Area/Asy/Asz/Ixx/Iyy/Izz
correctly for the new H=1.6/B=11 shape in the dialog only — a
follow-up
GET /db/SECT/3still showed the old stale values until the user clicked OK to actually commit the dialog. - After OK,
GET /db/SECT/3confirmed the new values saved server-side (AREA: 1.0016,RXX: 1.868,RYY: 0.559,RZZ: 12.525,CYP/CYM: 5.5,CZP/CZM: 0.8, matching H=1.6/B=11 exactly).
Takeaway for this SDK: PUT /db/SECT on a SECTTYPE: "VALUE" box
section only stores the raw dimensions — it does not auto-derive the
STIFF mechanical properties from them. Anything writing /db/SECT
sections programmatically needs to either compute STIFF itself before
sending, or have a human recalculate via the GUI afterward — there's no
API-callable "recalculate now" action found in this chapter.
With the corrected section in place, the user asked to re-run analysis
and sanity-check the results. POST /doc/ANAL completed in 5s (no crash).
This model uses Construction Stage Analysis (/db/STAG has 8 stages,
CS0-CS7) rather than plain static load cases — get_reaction_table/
get_cable_force_table/get_displacement_table all returned {"message":
""} (empty) for ordinary load_case_names like "Self Weight" or
"Self Weight(CS)" until switching to load_case_names=["Summation(CS)"]
with opt_cs=True and stage_step=["CS7:001(last)"] (final stage, per
the manual's "CS1:001(first)"/"CS1:002(last)" format at
19_POST_AnalysisResult_1.md:65) — then all three returned real data:
symmetric reactions (844.4 tonf total, matching the bridge's mirror
symmetry exactly), all 202 cable elements in tension (none went slack/
compression after the section fix), and DZ displacement up to 2.37m
(flagged to the user as needing their own engineering judgment — cumulative
construction-stage displacement isn't directly comparable to a simple
span/400 serviceability check).
Bonus finding while retesting post/design.py after the real analysis
existed: get_pm_interaction_diagram's error changed from "Please
Check Analysis" (pre-analysis) to "Please Check RC Design Code"
(post-analysis) — confirms the route correctly progresses through its
precondition chain rather than being stuck. get_steel_code_check
stopped erroring entirely post-analysis, now answering the "empty"
shape (nothing to report since no code check has been run, not a
failure). BEAMDESIGNFORCES/COLUMNDESIGNFORCES/
STEELMEMBERDESIGNFORCES still hit "there was an error creating utbl"
even post-analysis — these apparently need a load combination too, not
just an analysis result, which this model doesn't have yet (only the one
"Self Weight" load case exists, no LCOM-*).
2026-07-31 (later still) — 19 file-path/ANAL-family endpoints closed, then a new crash: OCHECK¶
With the user's go-ahead and a real safe path on the NX host machine
(E:\MIDAS PROGRAM\temp), closed 19 more endpoints on the real bridge
model (coverage 356 → 375/398):
/doc/* lifecycle, verified as real round-trips, not just trusted
"command complete" responses:
save_as()to a new.mcbxfile, thenopen_project()on that same path — reopened with all 273 nodes intact, confirming the write actually happened (per this SDK's ownsave_asdocstring warning that a rejected path still answers "command complete").close_project()— succeeded, and a follow-upGET /db/NODEcorrectly answered"The project is not opened"(clean, not a hang) — thenopen_project()on the same file restored a fully working session.save()— succeeded (against the test file, not the original, since the open-document context had already switched via theopen_project()round-trip above).export_json()/export_mxt()— both answered command-complete; not independently read back — see below for whyIMPORTwasn't attempted, which is the same reason a round-trip verification wasn't either.stage_as()(/doc/STAGAS) — took 3 tries:.mcbxextension failed ("Please check the file name or extension"), then the post/TABLE-style qualified stage name"CS7:001(last)"failed ("Please specify the correct stage name"), then the plain stage name"CS7"(matching/db/STAG's ownNAMEfield) with a legacy.mcbextension succeeded. Both failures were my own wrong guesses, not a live defect — the manual's own worked example already shows exactly this shape (STAGE_STEP: "Fase1",EXPORT_PATH: "...FASE1.mcb"). Updatedstage_as()'s docstring indoc.pyso the next person doesn't make the same guess from the parameter name alone.
/view/CAPTURE and PRECAPTURE: capture() with just EXPORT_PATH
succeeded cleanly. precapture() (fiber-section diagram) answered a
clean "second query is wrong" — this model has no fiber-modeled
sections, so the argument shape is confirmed but never produced real
data.
Explicitly still skipped: /doc/IMPORT/IMPORTMXT. Both are
additive/merging operations into whatever model is currently open — since
this is genuinely real production data, importing anything into it (even
a file exported from the same model) risks duplicating or corrupting
entities. These need a disposable scratch document (/doc/NEW) to test
safely, not this real bridge — not attempted this round.
The *-ANAL "perform design check" family — 10 more endpoints, all
clean, no hang: with the user's explicit go-ahead given the documented
hang history, ran BD/CD/BRD/WD/HCD-ANAL (design_forces.py),
BC/BRC/WC-ANAL (checks.py), and SRC's BC-ANAL/CC-ANAL — every one
answered "Please perform analysis" in under 1 second, no hang. Notably
this includes WD-ANAL (RC Wall Design Perform), the one endpoint in
this whole family with documented hang history on Gen NX 2026-06-23 — a
clean run here doesn't clear that history (this bridge has zero wall
elements, so it never got anywhere near the code path that hung before),
but it's one more data point of the endpoint behaving normally under
different conditions.
🔴 New crash found: POST /DESIGN/SRC/AIK-SRC2K/OCHECK. Called with
ANALYSIS_OPT.ANAL_TIME=0 and OUTPUT.MODEL_UPDATE=False (deliberately
conservative, to avoid it silently rewriting real sections if it somehow
proceeded past validation) against a model with zero SRC-eligible
sections/materials. The client-side call timed out at 25s; a same-session
GET /db/NODE timed out too — the documented "connected but /db/* blocked"
signature of a native dialog holding the session. The user checked the
screen and found a cascade of three dialogs, distinct from every
other crash found this session (EDMP/USLC crash immediately with no
intermediate dialog):
"Error Checking Result:"listing every missing prerequisite (No Material/Section Shape/Section Type/Section Data/Load Combination/ Member Type/Element Type/Design Axis/Reinforced Bar exists for Checking) — this is the same information every other*-ANALreturns as a clean JSON error; here it's a blocking native dialog instead."Unacceptable model for optimal design."- The familiar
"[Error] Failed to disconnect the work session due to an unidentified error..."crash dialog, followed by"Program will be closed due to an unexpected problem"with an auto-recovery file path (E:\MIDAS PROGRAM\temp\sdk_test_save_restore.mcb).
After the user restarted Civil NX (re-execute → New Project → close,
per the dialog's own instructions) and reconnected with the same MAPI
key, the session recovered fully: 273 nodes intact, and /db/SECT/3's
H/B fix from earlier this session (vSIZE: [1.6, 11, ...]) survived —
no data loss. Not yet filed to MIDASIT Jira — needs the user's
explicit go-ahead first, per the standing rule from the EDMP/USLC
filing earlier this session (see MAPI-2425/2426).
Coverage after this round: 375/398 implemented+verified; remaining gap is
/doc/IMPORT/IMPORTMXT (needs a scratch document), /ope/LCOM-GEN/
STORPROP/GSBG (unresolved or blocked on prerequisites not available
via API), OCHECK (now confirmed a crasher, not "verified working"),
DSRC (config write, skipped for consent), and the *-REPORT/DREULT/
CDESIGN family (still need real design results to test meaningfully,
which no *-ANAL on this model has produced — every one failed the
"please perform analysis"/prerequisite check, since this bridge has no
RC design code or load combination configured).
2026-07-31 (last) — Civil NX coverage closed out to 392/398: *-REPORT family, DSRC, IMPORT/IMPORTMXT, and a routing-level confirmation for LCOM-*/STORPROP¶
Closed the rest of what was tractable on Civil NX this session (375 → 392/398):
All 12 remaining *-REPORT endpoints plus DREULT/CDESIGN (Steel
CODE-REPORT, RC-KDS BD/CD/BRD/WD/HCD/BC/CC/BRC/WC-REPORT, SRC
BC/CC-REPORT) answered "Please perform analysis" cleanly with the
same E:\MIDAS PROGRAM\temp path — consistent with every *-ANAL on
this model failing the same precondition. DREULT answered "It's
failed, Post Mode is not available"; CDESIGN answered "It's not
found Figure Name" (needs a pre-existing named smart-report figure
config this model doesn't have) — both clean, route+shape confirmed, no
crash.
/DESIGN/SRC/AIK-SRC2K/DSRC (config write) round-tripped cleanly:
PUT with DGNCODE="AIK-SRC2K" succeeded, then DELETE reverted it —
both echoed the record back, no lasting mutation left on the real model.
/doc/IMPORT/IMPORTMXT finally closed, with the user's explicit
consent to /doc/NEW a disposable scratch document (discarding the FCM
test model from the OCHECK reproduction, which was no longer needed).
On the resulting empty document: export_json() → import_json() and
export_mxt() → import_mxt() both round-tripped cleanly, staying at 0
nodes throughout — no crash, no data corruption. This is the reason
these two were deliberately skipped earlier against the real bridge
model: additive/merge operations need a throwaway target, not production
data.
/ope/LCOM-GEN retried with the simpler AIK-SRC2K schema ({OPTION,
DGNCODE: "AIK-SRC2K", RS_SCALE_FACTOR: []}, vs the KDS:2022/CONCRETE
attempt that got "Wrong Field" on Gen 2026-07-30) — 404'd outright on
Civil, a different and more definitive failure mode. Checked GET
/info/ope/LCOM-GEN and /info/ope/LCOM-CONC directly: both also 404
on Civil — the routes aren't registered on Civil NX at all, not just
failing at execution. This confirms at the routing level what was only
inferred before: the whole /ope/LCOM-* family (GEN/CONC/STEEL/
SRC) is Gen-only, closing the open question from LCOM-CONC/STEEL/
SRC's original Civil-404 finding (2026-07-30).
/ope/STORPROP got the same /info check: GET /info/ope/STORPROP
also 404s on Civil, matching the routing-level pattern above. Doesn't
explain why Gen also 404s on the same route (Gen's own /info was never
checked), so that half of the mystery stays open — but the Civil side is
now confirmed at the routing level rather than just inferred from a
failed POST.
Final Civil NX tally: 392/398. The 6 remaining are genuinely not
closeable from here:
- /ope/EDMP/USLC — confirmed Gen NX crashers (MAPI-2425/2426),
a different product's problem to retest.
- /ope/STORPROP/LCOM-GEN — routing-confirmed 404 on Civil, but why
Gen also fails (STORPROP) or exactly which field breaks (LCOM-GEN on
Gen) is still open.
- /ope/GSBG — still blocked on a Bridge Group definition, which has no
API-level way to create in this SDK's current endpoint coverage.
- /DESIGN/SRC/AIK-SRC2K/OCHECK — confirmed a genuine Civil NX crash,
reproduced twice on two different bridge models (a cable-stayed bridge
and an FCM bridge), filed as MAPI-2429 (relates to nothing yet —
linking left for the user to decide).
2026-07-31 (session end) — GSBG investigation on a real FCM bridge: two blockers understood, one still open¶
With explicit consent to "handle it freely," dug into why /ope/GSBG
(Bridge Girder Diagram Image Generation) has been unreachable all
session, using a real FCM (Free Cantilever Method) bridge model the user
opened (111 nodes, 106 BEAM elements, 17 construction stages —
Pier1/Pier2, PierTable1/2, P1Seg1-12, P2Seg1-12,
KeySeg1-3, FSM1/2, all as existing /db/GRUP entries).
Corrected an earlier wrong assumption: BRDG_GROUP is just a plain
/db/GRUP name, not a GUI-wizard-only object. docs/manual/17_DB_Bridge.md's
/db/GSBG chapter (the DB-level sibling of /ope/GSBG) requires
BODY_ELEM_GRUP_K, an integer referencing a /db/GRUP group — proving
the "Bridge Girder Group" concept is exactly the general-purpose
Structure Group table this SDK already exposes as StructureGroup
(db/project.py, fully POST/PUT-capable). Split this model's 106 BEAM
elements into 82 horizontal (girder, ids 1-82, constant Z between
segment endpoints) vs 24 vertical (pier, ids 83-106, constant X) by node
geometry, then created a new group:
This succeeded and is now a permanent addition to this real model — worth
noting since StructureGroup.PRODUCTS/METHODS is NO_DELETE_METHODS,
so it can't be removed via this SDK; only through the Civil NX GUI if the
user wants it gone.
First blocker, understood but not solvable via API alone: "post mode
is required." Passing BRDG_GROUP="Girder_All" got past the
group-not-found stage into this error (matching DREULT's "Post Mode is
not available" seen earlier on the cable-stayed bridge — the same
underlying gate, different wording). Ran a real /doc/ANAL first (46.6s
for this 17-stage FCM model, no crash), then tried set_result_graphic()
(/view/RESULTGRAPHIC, TYPE: "CS", NAME: "Summation") — that itself
succeeded, but did not clear the "post mode" gate for GSBG. Only
the user manually clicking the "Post" tab in the Civil NX GUI did. No
API-only path into this mode was found this session.
Second blocker, reproduced but not root-caused: "Final/PostCS stage is
not supported." Once Post Mode was manually enabled, every GSBG call
hit this new error — and it did not change across STAGE_LIST values
CS1/CS2/CS3/CS16/CS17 (the model's real final stage) or
LC_NAME values "Self"/"Self(CS)"/"Summation(CS)". Since varying
the documented parameters had zero effect, this reads like leftover
document state — plausibly the earlier set_result_graphic() call's
NAME: "Summation" (itself a "Final/PostCS" aggregate result type)
stuck the document in a mode GSBG refuses to diagram from, rather than
anything wrong with the GSBG call's own arguments. Not confirmed before
the session ended.
Net effect: GSBG went from "can't even test it" to "two of three
blockers understood, one open." Recorded as still unverified in
coverage.json — a real success would need starting fresh (undo the
Summation result-graphic state, or open yet another session) and
confirming whether a plain single-stage set_result_graphic() call
avoids the "Final/PostCS" error.
2026-08-01 — Gen NX re-check of the 3 unresolved /ope/* cases (STORPROP, LCOM-GEN, OCHECK)¶
Connected to a fresh Gen NX session (PC A, user sjj0507@midasit.com) to
follow up on the endpoints left "no live_verified" in coverage.json,
skipping the two already-filed crashers (EDMP/USLC, MAPI-2425/2426)
and the blocked GSBG.
/ope/STORPROP — 4th reproduction, still 404. Same FORMAT="Default",
PLACE=4 payload that 404'd on 2026-07-30. Still fully unexplained; not
worth another blind retry without checking Gen's own /info/ope/STORPROP
(only Civil's has been checked, see the 2026-07-31 entry above).
/ope/LCOM-GEN — new data point, still broken. Only the KDS:2022/
CONCRETE schema had been tried on Gen before (2026-07-30, "Wrong Field").
Today's minimal AIK-SRC2K schema ({OPTION, DGNCODE: "AIK-SRC2K",
RS_SCALE_FACTOR: []}) reached the server (200, not 404 — confirms the
Gen route is genuinely live, unlike Civil's routing-level 404) but also
answered "Wrong Field". Both schema shapes now fail the same way on Gen;
root cause still unknown.
/DESIGN/SRC/AIK-SRC2K/OCHECK — attempted, but not a real repro of the
Civil crash. The open Gen document had zero sections (/db/SECT
empty) — not the "sections exist, none SRC-eligible" shape that crashed
Civil NX on 2026-07-31 (MAPI-2429). A fabricated SECT_NO: 1 got a
clean "Section 1 does not exist." JSON error; a follow-up GET /db/NODE
confirmed the session stayed alive (0 nodes, matching the empty document).
This does not clear Gen of the same crash risk — it never reached the
code path that crashed Civil, since that path needs a real, existing,
non-SRC-eligible section to validate against. Re-test needed against a
real Gen model with actual section data before drawing any conclusion
either way.
Net: no new crashes, no new working endpoints — just narrowed what's
already known. All three remain open. Nothing filed to Jira from this
round (nothing new to report — LCOM-GEN's finding refines a symptom
already implicitly covered by generate_load_combination_general's own
docstring, not a new bug).
2026-08-01 (later) — real Gen NX apartment model retest of OCHECK crashes; a new crash found on KDS-41-20-2022/TABLE (CD-TABLE), filed as MAPI-2431¶
Following up on the note above that the empty-document OCHECK attempt didn't clear Gen of crash risk: reconnected to a fresh Gen NX session (new MAPI key) with the user's real production "apartment" model open (14,027 nodes, 476 sections) to retest against actual section data.
/DESIGN/SRC/AIK-SRC2K/OCHECK crashed Gen NX on the real model.
verify_connection() kept answering "connected" while every /db/*
call timed out, then the NX process itself died — the same signature
previously seen on Civil (MAPI-2429). Recovery cycle (dismiss dialogs
→ relaunch → New Project → close → reconnect with the same MAPI key)
completed with no data loss: post-recovery /db/NODE//db/SECT
counts matched pre-crash exactly (14,027 / 476). This is the first
confirmation that the crash-recovery-without-data-loss pattern, well
established on Civil, also holds for Gen NX.
Then a second, different crash: POST /DESIGN/RC/KDS-41-20-2022/TABLE
(Column Design Forces, get_column_design_forces_table /
TABLE_TYPE_COLUMN_DESIGN_FORCES). Tried as the next step in the
RC/SRC design-code verification plan, on the assumption that a TABLE
read-back endpoint would be safe (no prior crash history for any
*-TABLE case) — that assumption was wrong. The very first call
produced the identical "connected but every /db/* call times out,
then the process dies" signature. Recovered the same way, again with
no data loss once the user reopened the apartment model.
To rule out leftover state from the OCHECK crash/recovery cycle as a
confound, reproduced independently: recovered to a freshly-created,
completely empty Gen document and issued the same CD-TABLE call in
isolation. Same crash signature, same recovery, same no-data-loss
outcome (trivially, since the document was empty). Two independent
reproductions (real populated model, isolated empty model) — meets this
project's bar for "confirmed," not just "unconfirmed single repro."
Filed as MAPI-2431 (build: MIDAS Gen NX 2026 (v2.1), Build
07/30/2026), under epic MAPI-1200. Not linked to MAPI-2429/OCHECK —
different endpoint, no evidence of a shared cause. get_brace_design_forces_table/get_beam_design_forces_table share the same
underlying TABLE endpoint/helper and were not independently tested;
flagged as equally at risk in their docstrings until tested.
Net for this session: two real crashes confirmed on Gen NX
(OCHECK via MAPI-2429's Civil finding now also reproduced on Gen;
CD-TABLE newly found and filed as MAPI-2431), zero data loss across
both. Further crash-risk testing on the real apartment model paused
per the user pending explicit re-confirmation — the working assumption
that *-TABLE/*-REPORT reads are inherently safe no longer holds and
each new candidate needs to be treated as a possible crasher until
tested.
2026-08-07 — patch verification: MAPI-2425/MAPI-2426 fixed on both products; the predicted get_beam_design_forces_table risk confirmed; MAPI-2429 closed as "not a defect"¶
Followed up on a fresh, previously-unseen crash found earlier the same
session (get_beam_design_forces_table, POST /post/TABLE,
TABLE_TYPE_BEAM_DESIGN_FORCES — hung Gen NX build 07/30/2026 on the
very first call of a post/* read sweep, ~4 minutes of timeouts before
the session died). The user then patched both products — About dialogs
confirmed MIDAS GEN NX 2026 (v2.1), Build 08/06/2026 (patch v975,
see below) and MIDAS CIVIL NX 2026 (v2.2), Build 08/06/2026 — and
asked to check whether previously-reported issues were resolved, and
whether the patch introduced anything new.
Checked MIDASIT's internal Jira for what changed. MAPI-2425
(/ope/EDMP) and MAPI-2426 (/ope/USLC) — both filed 2026-07-30, both
originally Gen-NX-only reports — were marked DONE at 09:13-09:15 the
same morning the user patched, linked to a shared fix build
(GEN_NX_US_D260806_T0910_N3547_r_b1_MR.zip, v975). Root cause per the
vendor comment on MAPI-2425: AUTO: true internally still read
PARAMETER even though the manual only documents it as required when
AUTO: false; with AUTO: true and no PARAMETER, the code used the
missing value directly instead of guarding it, crashing the product. The
fix changes that path to return a proper error response instead of
crashing — it is not a requiredness change to PARAMETER itself, so
this SDK's existing docstring (PARAMETER: ... required if AUTO=false —
matching the manual exactly) needed no correction.
MAPI-2429 (/DESIGN/SRC/AIK-SRC2K/OCHECK crash, filed against both
products) was closed the day before as "결함 아님" (not a defect) —
not because it doesn't crash, but because the endpoint itself is an
unofficial, paused-mid-development API that MIDASIT is renaming to a
/TEMP/DESIGN/... prefix (also affects STEEL/KDS-41-30-2022/OCHECK
and SRC/AIK-SRC2K/DCHECK). No fix timeline; still crash-prone by
design, not by accident.
Retested EDMP/USLC live, on both products, with the exact
crash-reproduction payloads from the original reports. Per the user's
standing permission to build disposable models for this ("모델은 안
중요해, 필요하면 더미 만들어서 테스트해도 됨"), built a minimal model on
each product from empty (Material "C24"/KS01(RC), Section
400×400 DBUSER, two Nodes, one BEAM Element, one StaticLoadCase
"DL", one LoadCombinationConcrete "cLCB1") and issued:
POST /ope/EDMP
{"Argument": {"NODE_ELEMS": {"KEYS": [1]}, "TYPE": "NSM", "AUTO": true,
"CODE": "Korean Standard", "H_VS": 0.5}}
Both products, both calls: no crash. EDMP now answers
MidasResultError("Unknown Error") — a clean rejection, not a hang.
USLC now answers {"message": "MIDAS <product> NX command complete"}
— an actual success. verify_connection() confirmed healthy after every
call, on both Gen and Civil. Neither crash report was originally filed
against Civil NX (both said "Gen NX 세션 종료" only) — tested there
anyway since the fix build is shared, and it holds on Civil too.
The get_beam_design_forces_table crash from earlier this session is
not a new, unfiled bug — it's the risk the 2026-08-01 entry above
already flagged and left untested. That entry (MAPI-2431, Column
Design Forces) noted: "get_brace_design_forces_table/
get_beam_design_forces_table share the same underlying TABLE
endpoint/helper and were not independently tested; flagged as equally at
risk." post/base.py's get_table() confirms this at the code level —
every post.design.get_*_design_forces_table() function, Beam included,
routes through the same POST /post/TABLE call with a different
TABLE_TYPE. This session's Beam crash is that prediction landing, on
build 07/30/2026 (pre-patch) — same failure signature as MAPI-2431
(long timeout, then every /db/* call fails, then the process dies).
Whether the 08/06 patch fixes this specific TABLE_TYPE the way it fixed
EDMP/USLC is untested — retesting it means deliberately repeating a
call already known to hang, so it stays paused pending the user's
explicit go-ahead, per "위험한 것은 마지막에."
Net: two of three previously-reported crashes (EDMP/USLC) confirmed
fixed on both products by the same patch; the third (OCHECK) confirmed
not fixed and not going to be (unofficial API); MAPI-2431's Column
Design Forces crash remains unresolved (IN PROGRESS) and its sibling
Beam Design Forces crash is now empirically confirmed rather than just
predicted. No evidence of new, undocumented endpoints in this patch —
checked both scripts/check_manual_drift.py (has_diff: false) and a
7-day Jira sweep of [MIDAS API]-tagged issues (nothing beyond the six
already tracked here).
2026-08-07 (later) — MAPI-2431 re-tested post-patch: still crashes, and MIDASIT couldn't reproduce it on their side¶
MIDASIT replied on MAPI-2431 saying the same call worked fine in their
environment and asked for the model used to test it. Rather than share a
model file, re-tested two cases live on Gen NX (same patch build, v975,
build 08/06/2026) to characterize exactly when it does and doesn't crash:
Case 1 — the currently-open real model, no design run yet: no crash.
POST /DESIGN/RC/KDS-41-20-2022/TABLE with
{"Argument": {"TABLE_NAME": "", "TABLE_TYPE": "COLUMNDESIGNFORCES"}}
answered a clean empty {}, and a follow-up verify_connection()/
GET /db/NODE confirmed the session stayed healthy. This matches what
MIDASIT saw on their side.
Case 2 — a completely blank document (/doc/NEW, confirmed 0 nodes via
GET /db/NODE): crashes, same signature as before. The same call got no
response; verify_connection() then answered "status": "disconnected"
(notably accurate this time, not the usual false "connected") and
GET /db/NODE failed 404 client does not exist. Gen NX needed a
restart.
This reconciles with the 2026-08-01 entry above, which also crashed on
both a real populated model (14,027 nodes, real section data) and an
isolated empty document — so the empty-document repro isn't new. What's
new is that today's small real model (63 nodes) did not crash, where
the much larger apartment model on 08-01 did. That's not enough evidence
to conclude the patch fixed anything for real models — the two "real
model" tests differ in more than just the patch (node count, whether any
design/analysis had been run, section data present or not) — but it does
mean the crash isn't purely a function of "real model vs. empty model."
The one variable that reproduces it reliably across every test so far,
pre- and post-patch, is zero design data present — trivially true for
a blank document, and possibly also true of the small 08-07 test model if
it turns out to have sections without any run design check. Reported both
cases back on the ticket with the exact repro steps (/doc/NEW then the
call above, no model file needed) since that's a strictly easier repro
path for MIDASIT than sharing a model.
Still IN PROGRESS, unresolved as of this entry.
2026-08-07 (later still) — the TABLE//post/TABLE design-forces crash family is Gen-NX-only: full Civil NX sweep clean, plus a 43/43 live_crud_check.py reconfirmation¶
Following the MAPI-2431 re-test above, checked whether the crash family
(everything sharing post.design's /post/TABLE helper, and
design.rc_kds.checks's sibling /DESIGN/RC/KDS-41-20-2022/TABLE
endpoint) is really Gen-specific, or just hadn't been tried on Civil yet.
Civil NX, same patch build (v975-equivalent, build 08/06/2026), against a real model (111 nodes, no design run yet):
/post/TABLE, all 8TABLE_TYPEvalues inpost.design(BEAMDESIGNFORCES,COLUMNDESIGNFORCES,BRACEDESIGNFORCES,WALLDESIGNFORCES,STEELMEMBERDESIGNFORCES,SRCBEAMDESIGNFORCES,SRCCOLUMNDESIGNFORCES,COLDFORMEDSTEELMEMBERDESIGNFORCES) — every single one answered a clean200-with-error-body"there was an error creating utbl (ex PostMode ...)". No hang, no crash;verify_connection()/GET /db/NODEconfirmed the session healthy after each call, node count unchanged (111) throughout./DESIGN/RC/KDS-41-20-2022/TABLE, the two not yet covered (BEAMDESIGNFORCES,BRACEDESIGNFORCES—COLUMNDESIGNFORCESwas already confirmed clean here back on 2026-07-31) — same cleanPostModeerror, no crash.
Net: 11 of 11 tested combinations are clean on Civil NX; the only
confirmed crashes in this whole family remain the two already filed on
Gen NX (MAPI-2431's Column Design Forces via the KDS-41-20-2022
endpoint, and this session's Beam Design Forces via /post/TABLE, both
reproduced again post-patch). The remaining Gen-side combinations
(Brace/Wall/Steel/SRC/Cold-Formed via /post/TABLE, Brace via the KDS
endpoint) are still untested on Gen and are documented as "equally at
risk" rather than confirmed either way — this crash family looks
Gen-specific so far, but that's not the same claim as "safe on Gen for
the untested types."
Separately, ran scripts/live_crud_check.py --product civil (all
tiers, no --include-crashers) against this same patch build: 43/43
resources completed a full create→read→update→read→delete→read round
trip, no failures. This is a reconfirmation, not a new finding — all
43 cases were already confirmed=True as of 2026-07-29 per the script's
own tracking — but it's the first time they've all been re-run together
against the 08/06/2026 patch build, and nothing regressed. Note this
script creates its own scratch document via /doc/NEW, so it discarded
whatever was open beforehand (with the user's explicit go-ahead, since
that document didn't matter).
2026-08-07 (last) — full Civil NX DbResource GET sweep closes most of the read-coverage gap; GEN_ONLY reconfirmed unchanged¶
Prompted by a moment of confusion: after a run of Civil-specific findings, it looked like Civil NX coverage might be "done." It wasn't — at the time, only 195/399 endpoints had ever been live-verified on Civil at all (most of this project's live sessions have skewed Gen-heavy). Ran the actual numbers, corrected the misunderstanding, then closed as much of the real gap as a single sweep reasonably could.
scripts/live_readonly_sweep.py --product civil --record-coverage
against build 08/06/2026 (confirmed via a Help > About screenshot: MIDAS
CIVIL NX 2026 (v2.2), Build: 08/06/2026) swept all 282 GET-capable
DbResource classes (everything in db/*, plus
design.rc_kds.rebar/design.rc_kds.setup/design.steel_kds/
design.src_aiksrc2k's DbResource-based classes — the plain-function
TABLE/ANAL/REPORT endpoints in design.rc_kds.checks and
doc.py/ope.py/post/* aren't covered by this tool at all, since it
only enumerates DbResource subclasses). All 282 answered ok — no
failures, no crashes, session healthy throughout.
The script's own --record-coverage only writes a new live_verified
entry where none exists yet, so it undercounted: most of these 282 already
had a Gen-only live_verified entry from an earlier session, and the
script correctly declined to touch those (its docstring says so
explicitly — an existing entry is never overwritten). Wrote a one-off
merge script instead: for every endpoint this sweep confirmed ok, if its
existing live_verified.products didn't already include "civil", add
it, append a short note, and cite this build. Matched primarily by
(endpoint, module); a residual 21 entries use a wildcard module string
("midas_nx.db.properties.*") in coverage.json instead of the real
submodule, so those were matched by endpoint alone (checked for
uniqueness first) in a second pass. 172 endpoints gained a Civil
confirmation this way. Verified on Civil NX went 195/399 → 367/399.
Separately, force-tested all 20 GEN_ONLY-tagged DbResource classes
against Civil NX (strict_product=False, bypassing the client-side
guard that normally blocks a product mismatch) — the same check that
originally established GEN_ONLY on 2026-07-29. All 20 still 404 on
Civil, identical to the original finding: no drift across two patch
cycles. db/base.py's GEN_ONLY docstring now cites this reconfirmation
alongside the original evidence.
What's left of the 32/399 still not live-verified on Civil: almost
entirely the plain-function endpoints (doc.py/ope.py/post/*/
design.rc_kds.checks) that this sweep tool doesn't reach, several of
which overlap the Gen-only crash-risk family documented earlier this same
day (Column/Beam/Brace Design Forces and friends). Closing that remainder
needs per-module manual testing, not a single automated sweep, and was
deliberately deferred rather than rushed — see the still-open item at the
end of this file's history.
2026-08-10 — BRACEDESIGNFORCES confirmed crashing Gen NX, closing one more gap in the design-forces crash family¶
Continuing the Gen-side sweep of the post.design//post/TABLE design-
forces crash family (Column and Beam already confirmed crashing, the
rest flagged "equally at risk" but untested): tried BRACEDESIGNFORCES
against a blank /doc/NEW document on Gen NX (build 08/06/2026, same
patch already confirmed crashing for Column/Beam). Same signature: no
response, then verify_connection() → disconnected, every /db/* call
→ 404. Gen NX needed a restart.
User paused the sweep here rather than continuing through the remaining
5 candidates (WALLDESIGNFORCES, STEELMEMBERDESIGNFORCES,
SRCBEAMDESIGNFORCES, SRCCOLUMNDESIGNFORCES,
COLDFORMEDSTEELMEMBERDESIGNFORCES via /post/TABLE, plus
BRACEDESIGNFORCES via the sibling /DESIGN/RC/KDS-41-20-2022/TABLE
endpoint in design.rc_kds.checks — still untested) — each confirmed
crash costs a full Gen NX restart, and three confirmed crashes
(Column/Beam/Brace, all via the same shared /post/TABLE helper) was
judged enough evidence for the pattern without burning through the rest
one restart at a time. Remaining candidates stay documented as "equally
at risk, untested" rather than confirmed.
2026-08-10 (later) — full Gen NX DbResource GET sweep, mirroring the earlier Civil sweep¶
After confirming Gen coverage had a much bigger gap than Civil (132/399 endpoints never live-tested on Gen at all — this project's live sessions have skewed Civil-heavy since the FCM bridge model work), ran the same tool used for the Civil sweep, this time against Gen:
scripts/live_readonly_sweep.py --product gen --record-coverage
against build 08/06/2026, on a blank /doc/NEW document (post-crash
restart from the BRACEDESIGNFORCES finding above): swept all 266
GET-capable DbResource classes applicable to Gen — all 266 answered
ok, no failures, no crashes, session stayed healthy throughout and
after.
Same merge-script approach as the Civil sweep (the tool's own
--record-coverage only adds a new entry, so a one-off script added
"gen" to existing Civil-only live_verified.products wherever this
sweep confirmed it): 32 endpoints gained a Gen confirmation this way.
Verified on Gen NX went 266/399 → 299/399. A smaller jump than the
Civil sweep's 172, because most of the remaining gap here is
plain-function endpoints (doc.py/ope.py/post/*/
design.rc_kds.checks/design.rc_kds.design_forces/
design.src_aiksrc2k's ANAL/TABLE/REPORT triads) this tool doesn't
reach — including the crash-risk family from earlier today, which stays
untouched by this GET-only sweep by design.
Explicitly paused here rather than continuing into those plain-function
modules: several overlap the confirmed Gen crash-risk family, and the
RC/SRC/Steel *-ANAL triads have their own independent Gen-hang history
(see the 2026-08-01 entries above) — closing the remainder needs
per-module manual testing with explicit go-ahead each time, not another
single automated sweep.
2026-08-10 (last) — non-crash-family ANAL/TABLE/REPORT/CAPTURE batch on Gen NX: 40 endpoints, no crash/hang, all recorded¶
Continuing the DbResource sweep's leftover gap: the plain-function design
chapters (design.rc_kds.design_forces, design.rc_kds.checks,
design.steel_kds, design.src_aiksrc2k, view.py) that the GET-only
sweep can't reach. Explicitly excluded from this batch: the confirmed/
at-risk Design-Forces crash family (post.design's 8, checks.py's
Column/Brace/Beam Design Forces TABLE, steel_kds.py's
TABLE=STEELMEMBERDESIGNFORCES, src_aiksrc2k.py's TABLE=
Beam/Column SRC Design Forces — all share the same *DESIGNFORCES
TABLE_TYPE naming convention as the confirmed Column/Brace/Beam crashes)
and src_aiksrc2k.py's OCHECK (confirmed crashing both products,
MAPI-2429, already recorded separately).
Correction to the earlier "22 crash-family" figure quoted mid-session:
that overcounted by treating all 14 untested checks.py entries as
crash-family, when only 3 of them (Column/Brace/Beam Design Forces) are.
The other 11 (BC/CC/BRC/WC-ANAL/TABLE/REPORT, CDESIGN) are
unrelated check/report functions — BC-ANAL/CC-ANAL were already
re-verified clean via the QuickRebar NX production tool (2026-07-25),
and WC-ANAL was independently confirmed to NOT reproduce the CC-ANAL
stall. The real crash-family total across all modules is 11 Design-Forces
functions + OCHECK, not 22.
Ran against a blank /doc/NEW document (0 nodes/0 elements, same one
left over from the DbResource sweep), in two batches:
Category A (29 calls, no ANAL/PERFORM prerequisite) — view.CAPTURE/
PRECAPTURE; design_forces.py's BD/CD/BRD/WD/HCD *-TABLE/*-REPORT
(10); checks.py's BC/CC/BRC/WC *-TABLE/*-REPORT + CDESIGN (9);
steel_kds.py's CODE-TABLE/CODE-REPORT/DREULT (3, TABLE skipped
as crash-family-adjacent); src_aiksrc2k.py's BC/CC *-TABLE/*-REPORT
(4, TABLE/OCHECK skipped). All 29 answered cleanly with informative
refusals ("Please perform analysis.", "It's not found Figure Name",
"Wrong Field", "Post Mode is not available") — no crash, no hang,
session alive after every call.
Category B (12 *-ANAL/*-PERFORM calls, 25s timeout), run only
after explicit user go-ahead given the documented Gen-hang history on
this family (WC/BC/CC/BRC-ANAL, BD/CD/BRD/WD/HCD-ANAL, CODE-ANAL, SRC
BC/CC-ANAL — WD-ANAL deliberately tested last, being the one with
confirmed historical hang evidence). All 12 answered in <1s with the same
clean "Please perform analysis." refusal, immediately followed by a
*-TABLE read-back (per the established mitigation pattern) and a
/db/NODE session-alive check — no hang anywhere, including WD-ANAL.
Plausible explanation: the historical hangs were reproduced specifically
with real rebar/analysis data to process; against 0 elements the server
has nothing to "Convert Design Results" for and fails fast instead. This
does not clear the historical hang risk for real models — it's a
second data point (blank-document-is-safe), not a fix confirmation.
Recorded via a one-off merge script (same (endpoint, module)-matching
approach as the two DbResource sweeps): 38 endpoints gained a new Gen
confirmation (2 — CC-ANAL, CODE-ANAL — already had one from an
earlier session). Verified on Gen NX went 299/399 → 337/399.
Remaining real gap on Gen: the crash-family (11 Design-Forces functions,
already characterized as crashing/at-risk, not "unverified"), OCHECK
(confirmed crashing, ditto), and doc.py's 9 file-lifecycle endpoints
(OPEN/CLOSE/SAVE/SAVEAS/STAGAS/IMPORT/IMPORTMXT/EXPORT/
EXPORTMXT — deliberately not attempted against a session with real
state at risk) plus ope.py's 3 already-investigated-and-blocked cases
(STORPROP/LCOM-GEN/GSBG).
coverage.json correction (2026-08-11): the 2026-08-10 batch's merge
script had recorded the Gen version as v2.2 (copy-pasted from Civil's
version string) on all 38 entries it touched — Gen was never on v2.2.
Corrected all 38 to MIDAS Gen NX 2026 (v2.1), build 08/06/2026, the
build actually used that session. Caught via a fresh connection check
this session: About dialog showed Gen NX 2026 (v2.1), build
08/11/2026 (user sjj0507@midasit.com).
Connection-check tooling bug, same session: the first pass of both
this Gen check and a following Civil check (About dialog: Civil NX
2026 (v2.2), build 08/11/2026) called MidasClient(..., base_url=
"https://moa-engineers.midasit.com") — overriding the default and
stripping the required /gen//civil product path segment that
build_base_url() normally appends. verify_connection() still
succeeded (its URL-strip logic in client.py tolerates either form),
masking the bug, but every /db/* call landed on a route that doesn't
exist and returned a generic 404 — misread at the time as "blank
document, 0 nodes." Re-run without the base_url override: Node.get()
→ {"message": ""} on both products, the correct zero-row shape —
so both sessions genuinely are on blank documents, same conclusion as
before, but now for the right reason. No SDK code was at fault — the
bug was in the ad hoc verification script, not client.py.
OCHECK re-tried on Civil (v2.2, build 08/11/2026) with the corrected
client, at the user's request to re-attempt Civil's known crash
(perform_src_optimal_design, docs/live_verification_notes.md's
2026-07-31 "New crash found" section). Same shape as Gen's 2026-08-01
attempt: a fabricated SECT_NO: 1 against a document with zero sections
got a clean MidasResultError — "Section 1 does not exist." — and a
follow-up Node.get() confirmed the session stayed alive
({"message": ""}). Not a repro of the 2026-07-31 crash — that
needed a real, existing, non-SRC-eligible section to reach the crashing
code path, which this blank document doesn't have. Narrows nothing new;
the crash risk on real Civil models with real sections stands as
documented.
Quick full Civil-gap sweep, same session. Of the 11 endpoints
coverage.json listed as not-yet-civil-verified, 9 turned out to
already carry a conclusive Civil finding recorded only in their
docstring/method text (not reflected in live_verified.products because
the finding is negative): STORY_PARAM/STORY_IRR_PARAM (confirmed
404, 3rd+ repro), /post/TABLE story types (confirmed error, 2 sweeps),
STORPROP/LCOM-GEN/GSBG (dead route or unmet precondition on every
product, not Civil-specific), LCOM-CONC/LCOM-STEEL/LCOM-SRC
(confirmed 404 — "the whole /ope/LCOM-* family's routes aren't
registered on Civil at all," per generate_load_combination_concrete's
existing docstring). Retesting these would only reconfirm known dead
routes/blocked preconditions, so only the 2 genuinely untested ones were
run:
/ope/STOR(Story Calculation) — 404 on Civil, first direct test against this product (SEIS_ECC/WIND_ECCboth disabled, blank doc). Extends the story family's Gen-only pattern to cover this endpoint too./view/RESULTGRAPHIC— route IS registered on Civil, unlike the story family:CURRENT_MODE=reactionforces/momentsagainst a blank doc (no analysis run) got a cleanMidasResultError,"MIDAS CIVIL NX Empty Load Case Type". Session stayed alive. Addedcivilto itslive_verified.products— same standard as the 2026-08-10 Gen batch (a clean, correctly-shaped rejection counts as verified request handling, not "no data").
Both Node.get()-checked alive after each call. No crash, no hang.
docs/coverage.json and both functions' docstrings (ope.py,
view.py) updated; ROADMAP.md regenerated.
Full write round-trip + per-endpoint PUT sweep, same session, Civil NX
v2.2 build 08/11/2026. scripts/live_smoke.py --product civil run
against the blank connected session: /doc/NEW → UNIT → MATL (C24)
→ SECT (600×600 DBUSER column) → 2×NODE → ELEM (beam) → CONS
(fixed) → STLD (DL) → BODF (self-weight) → /doc/ANAL →
reaction/displacement/beam-force tables, all 13 steps ok: true;
reaction FZ = 27.11 kN vs. 28.22 kN hand-calc, within the script's 5%
tolerance.
Followed by a dedicated PUT-only sweep (change → GET-verify → revert →
GET-verify per endpoint, on the 8 resources the smoke test had just
populated): UNIT, MATL, SECT, NODE, ELEM, CONS, STLD,
BODF — all 8 changed and reverted cleanly, confirmed via a follow-up
GET each time. One cosmetic-only observation: SECT's vSIZE readback
comes back zero-padded to a fixed 10-element array
([0.6, 0.6, 0, 0, 0, 0, 0, 0, 0, 0]) rather than echoing the 2-element
list that was sent — not a defect, just the server's storage shape for
a variable-length dimension array. Node.get() confirmed the session
alive throughout. All 8 of these endpoints were already civil-verified
at level: "write" in coverage.json (from earlier create()-only
testing) — this sweep specifically exercised update()/PUT, which
hadn't been individually confirmed before, so no new coverage entries,
just a stronger evidence base behind the existing ones.
2026-08-11 (later) — full Gen NX crash-family re-test: 15 previously-crashing/at-risk calls, 0 crashes this time¶
At the user's explicit request to re-test "everything that had crashed on
Gen," and after correcting an initial mis-framing (told the user this
would likely be inconclusive on a blank document like OCHECK — wrong:
get_beam_design_forces_table()'s own docstring already documented a
confirmed crash on a blank /doc/NEW document, so the risk was real,
not just theoretical). User re-confirmed proceeding anyway with the
corrected risk understanding.
Batch 1 — 11 previously-unverified-on-Gen crash-family functions + OCHECK,
called one at a time against the connected blank Gen session (0 nodes),
Node.get() health-checked after every single call, ready to stop
immediately on the first failure:
checks.get_brace_design_forces_table, checks.get_beam_design_forces_table,
steel_kds.get_steel_member_design_forces_table,
src_aiksrc2k.get_src_beam_design_forces_table,
src_aiksrc2k.get_src_column_design_forces_table,
post.design.get_column_design_forces_table,
post.design.get_wall_design_forces_table,
post.design.get_steel_member_design_forces_table,
post.design.get_src_beam_design_forces_table,
post.design.get_src_column_design_forces_table,
post.design.get_cold_formed_steel_member_design_forces_table, and
perform_src_optimal_design (OCHECK, zero-section precondition, same
non-repro shape as the existing 2026-08-01 finding). All 12 answered
cleanly (mostly empty-table responses), session alive throughout.
Batch 2 — the 3 already-confirmed-crashing cases, re-tested next
since "전부" (all) includes these: post.design.get_brace_design_forces_table
(BRACEDESIGNFORCES), post.design.get_beam_design_forces_table
(BEAMDESIGNFORCES), and checks.get_column_design_forces_table
(MAPI-2431 — reproduced twice independently across different models,
re-confirmed not fixed as recently as 2026-08-07, the single
strongest repro in this whole family). All 3 — including MAPI-2431 —
answered cleanly this time too. Session alive after all 3.
Total: 15 of 15 calls clean, zero crashes, zero hangs, against Gen NX 2026 v2.1, build 08/11/2026 (previous crash confirmations were on build 08/06/2026 and earlier).
This is not being called "fixed." One clean pass against a
historically-confirmed crash doesn't distinguish "the vendor fixed it"
from "the crash is intermittent/non-deterministic" — and MAPI-2431's own
history already shows non-monotonic behavior (crashed on a blank
document, clean on a 63-node real model, in the same 2026-08-07 session).
Every affected docstring and coverage.json entry now carries today's
result as an additional data point, explicitly flagged as
"reduced-but-not-cleared," not a resolution. An independent second
re-test — ideally against real, populated model data rather than a
blank document, since that's the condition never yet cleanly tested for
most of this family — is the next real step, not a documentation
close-out.
docs/coverage.json (15 entries updated/extended), ROADMAP.md
(regenerated), and the docstrings in post/design.py, checks.py,
steel_kds.py, src_aiksrc2k.py (10 functions) all updated with
today's finding. ruff check and the full test suite (701 tests) both
pass.
DSRC (SRC Design Code) tested on Gen, same session, after the Civil
session was closed. Previously deferred pending consent (config-write,
no GET to verify state either way). PUT {"DGNCODE": "AIK-SRC2K"}
against Gen NX (v2.1, build 08/11/2026, blank document) succeeded,
echoed back cleanly, session stayed healthy. Not a full round trip like
the existing 2026-07-31 Civil test (PUT + DELETE) — DELETE wasn't
re-tried this pass. coverage.json gains gen in live_verified.products;
its level was also corrected read → write (it's a PUT, not a
read, regardless of which product tested it first).
2026-08-13 — new patch on both products: connection check only¶
User applied a new patch to both products and asked to confirm both
connect, with versions recorded. verify_connection() against fresh
.env MAPI keys (last-occurrence-wins for the duplicated
MIDAS_MAPI_KEY_GEN/MIDAS_MAPI_KEY_CIVIL lines) succeeded for both:
GEN: {'user': 'sjj0507@midasit.com', 'program': 'gen', 'connectionID': 'N-pAmlMjSg', 'keyVerified': True, 'status': 'connected'}
CIVIL: {'user': 'sjj0507@midasit.com', 'program': 'civil', 'connectionID': 'WjbfiHlPSw', 'keyVerified': True, 'status': 'connected'}
About-dialog screenshots confirm the new build:
- MIDAS GEN NX 2026 (v2.1), build 08/12/2026 (previous: 08/11/2026)
- MIDAS CIVIL NX 2026 (v2.2), build 08/12/2026 (previous: 08/11/2026)
Same version numbers as the prior patch, one-day-newer build only — consistent with a routine patch rather than a version bump.
2026-08-13 (later) — /db/NMAS raw crash-trigger re-repro on Civil NX: server-side bug looks actually fixed now, not just SDK-masked¶
User asked whether the crash-family items flagged earlier in this file
were all resolved on Civil NX. Answer at the time: NMAS — SDK-safe via
the rmX/rmY/rmZ auto-fill workaround, previously confirmed the
server itself no longer crashed as of Civil NX v2.2 build 07/29/2026;
OCHECK/perform_src_optimal_design (MAPI-2429) — still open, closed
by MIDASIT as "not a defect" (unofficial paused-development API being
moved to /TEMP/...), crash risk on real models with real sections never
actually retested. User asked to proceed with NMAS first, then
explicitly asked for the raw repro (bypassing the SDK workaround) to
check the server's current state directly, accepting the session-death
risk that trigger has historically carried.
Against Civil NX v2.2, build 08/12/2026, on a blank connected document:
- SDK-safe path first (sanity check): created
Node1, thenNodalMass.create({1: {mX:1, mY:1, mZ:1}})(rm fields omitted from the call, auto-filled to0.0by the SDK before sending) — clean201, read back correctly, session alive. Cleaned up. - Raw repro, bypassing
NodalMass.create()entirely viaclient.request()directly: createdNode1 andNode2. Control call —POST /db/NMASon node 1 with all six fields explicit (mX/mY/mZ+rmX/rmY/rmZ: 0.0) — succeeded in 0.2s. Trigger call —POST /db/NMASon node 2 withrmX/rmY/rmZomitted entirely (the exact payload shape that reproduced the crash 15+ times across both products pre-fix) — succeeded in 0.1s, no timeout, no hang.GET /db/NMASread back node 2 withrmX: 0, rmY: 0, rmZ: 0— the server itself now applies the documented default, rather than reading an uninitialized value. Follow-upverify_connection()andNode.get()both confirmed the session fully responsive immediately after. Test data (NMAS+ both nodes) deleted, document back to blank, session stillconnectedthroughout and after.
Historically this exact omitted-fields call took 15-60s and then killed
the session; here it returned in under a second with a correct result.
That's a materially stronger signal than the 07-29 finding (which only
established "doesn't crash," not "applies the right default") —
consistent with MIDASIT having actually fixed the uninitialized-value
bug server-side, not just gotten lucky on one retest. Not changing
NodalMass's SDK-side workaround based on this single repro on one
account/build — the class still fills rmX/rmY/rmZ explicitly, since
that costs nothing, remains correct regardless of server state, and this
is one data point on one build, not proof the fix is universal across
every deployed installation. Only tested on Civil this session; Gen not
re-repro'd today (its own last confirmation was 2026-07-30, build
07/30/2026).
2026-08-13 (last) — OCHECK/MAPI-2429 re-repro'd on Civil NX with the real trigger shape: still crashes on the current patch¶
After the NMAS reconfirmation above, asked whether Civil's crash-family
items were "all resolved." Answer: NMAS yes (see above), OCHECK
(perform_src_optimal_design, MAPI-2429) no — MIDASIT closed it "not a
defect," no fix timeline, and the 2026-08-11 retest never actually
reached the crashing code path (zero-section document). User asked to
build a dummy model and retry properly.
Dummy model built on Civil NX v2.2, build 08/12/2026 (blank document,
confirmed empty first): Material.create (C24 concrete, KS01(RC)),
Section.create (600×600 DBUSER, SHAPE: "SB" — a real, existing,
plain concrete section, i.e. non-SRC-eligible, the exact
precondition the 2026-07-31 finding says is needed), two Nodes, one
BEAM Element referencing both. All four calls succeeded, session
alive.
perform_src_optimal_design called against it — SECT_LIST:
[{SECT_NO: 1, SECT_DB: "USER"}], ANALYSIS_OPT.ANAL_TIME: 0,
OUTPUT.MODEL_UPDATE: False (same conservative shape as the original
2026-07-31 repro). The call timed out client-side at 30s. A follow-up
GET /db/NODE immediately after returned MidasNotFoundError: 404
client does not exist — the documented "process died after connecting"
signature. User confirmed on screen: the "[Error] Failed to disconnect
the work session due to an unidentified error..." dialog, identical to
2026-07-31's crash.
Recovery, per the dialog's own instructions (OK → re-launch → New
Project → close → reconnect with the same MAPI key): reconnected
cleanly, verify_connection() → connected, same connectionID.
Node/Element/Material/Section all read back empty — the dummy
model was cleared by the New Project step, not a data-loss event; it was
disposable test data built specifically for this repro, nothing of
value was lost.
Conclusion: MAPI-2429 is confirmed still live on the current patch
(v2.2, build 08/12/2026), not fixed and not intermittent in the way
NMAS briefly was. This is a stronger data point than the 08-11
non-repro (which used the wrong precondition) and is consistent with
MIDASIT's "not a defect, no fix timeline" stance — the crash isn't
build-dependent, it's inherent to calling this unofficial,
paused-development endpoint with a real section. docs/coverage.json's
/TEMP/DESIGN/SRC/AIK-SRC2K/OCHECK entry updated with today's repro and
build. Not re-tested on Gen this session.
2026-08-13 (last) — closing the 3 "typed but never live-tested" gaps from the recent manual syncs: SWIND/SSEIS USER TYPE, renamed Story Load/Weight tables, CONCURRENT_JOINT_FORCE¶
Earlier the same day, checking what the two most recent manual-repo sync
commits (f4a55e7 08-07, 76ebda9 08-10) actually added turned up 3
items that were typed into this SDK but never independently live-tested
against the new shape: /db/SWIND//db/SSEIS's "USER TYPE" variant,
the renamed /post/TABLE STORY_LOAD_{X,Y,Z} + new STORYWEIGHT
fields, and the brand-new CONCURRENT_JOINT_FORCE table type. User asked
to test all of them, on both products, building dummy models as needed.
Gen NX (v2.1, build 08/12/2026) — built a 2-story cantilever model
from scratch on the blank connected session: Unit, Material (C24),
Section (600×600 DBUSER), 3 Nodes / 2 BEAM Elements (a
0→3.2m→6.4m column), base Constraint, 2 real Story records
("1F" at 3.2m, "RF" at 6.4m, full field set), StaticLoadCase
("DL"), SelfWeight, then /doc/ANAL. Reaction sanity-checked
(54.23 kN, self-weight of the two-segment column). Every step ok.
SWIND/SSEIS"USER TYPE": POST withSTORY_WIND_PRESSURE/SEISMIC_FORCEkeyed to"1F"/"RF"succeeded (201) for both, GET read both back correctly — the server fills in GET-only fields (ELEV/LOAD_H/LOAD_BX/LOAD_BYfor wind,WEIGHT/ELEVfor seismic) on the way out, confirming those must stay client-side-omit on write, as the docstrings already said.INHERENT_TORSION's corrected spelling (vs. the manual's own"NHERENT_TORSION"typo) confirmed as the one the server accepts.- Story Load Summary / Story Weight:
get_story_load_summary_table("X", load_case_names=["DL(ST)"])andget_story_weight_table()both returned real per-story populated rows ("1F"/"RF", correct elevations, correct self-weight distribution) — closes the "renamed TABLE_TYPE never re-tested" gap. CONCURRENT_JOINT_FORCE:additional.SET_REACTION_PARAMS = {NODE_KEY: 1, COMPONENT: "111111"},load_case_names=["DL(ST)"](then retried with 2 load cases after adding a secondStaticLoadCase"LL") — both attempts got the identical clean error"there was an error creating utbl. (ex PostMode ...)". Not a crash, not a 404 — same "PostMode" precondition family asget_wall_force_table/GSBG.
Civil NX (v2.2, build 08/12/2026) — re-confirmed /db/STOR/SWIND/
SSEIS still cleanly 404 (GEN_ONLY holds on the current patch too).
Built a fresh single-story-height cantilever column (same recipe, no
Story data — Civil doesn't have that endpoint) and tested
CONCURRENT_JOINT_FORCE there too: same request shape got a
different clean error, "No data found for the specified node
key." A follow-up retry with NODE_KEY sent as a string (instead of
int) got a worse, obviously-wrong-shape error ("second query is
wrong"), which rules out a type mismatch as the cause of the first
error — confirms the documented int type is correct and the node id
itself (which does have real reaction data, confirmed via
get_reaction_table in the same session) just isn't what this table
is looking for.
Conclusion: CONCURRENT_JOINT_FORCE's own manual note — "typically
paired with moving-load (MV:max)/(MV:min) load cases" — reads as
literal, not just typical: a plain static-load-case reaction isn't
"extreme" over anything for this table to search, on either product.
Route and request shape are now confirmed correct on both products
(no defect found); building actual moving-load (Vehicle/Lane/MV load
case) test data to exercise the real result path is future work, not
done this session.
Correction, same session: Gen's "PostMode" error is NOT the same gate
GSBG is blocked on. User asked "Gen은 현재 postmode 맞잖아?" (Gen is
already in Post mode right now, isn't it?) and shared a screenshot
proving it — the "Post-processing Mode" toolbar toggle visibly enabled,
the analysis message log showing the completed solve, on the same
2-story column model this session built. Re-ran the exact
CONCURRENT_JOINT_FORCE call with Post mode confirmed already active:
identical error, unchanged. This decouples it from the
GSBG/get_wall_force_table "post mode is required" gate documented
2026-07-31, which does clear once a human manually enables Post mode
— here it didn't, so the word "PostMode" in this particular error string
is a red herring for this table specifically. Strengthens rather than
weakens the moving-load-data hypothesis above: with the generic
Post-mode explanation ruled out, "no (MV:max)/(MV:min) result to
search over" is the more likely remaining explanation for both
products' errors. docs/coverage.json and
post/result_1.py's get_concurrent_joint_force_table docstring
corrected to not conflate this with the GSBG gate.
All dummy models left open on both sessions (not cleaned up) in case
useful for follow-up testing. docs/coverage.json updated for /db/STOR,
/db/SWIND, /db/SSEIS, and both /post/TABLE aggregate rows (ch18,
ch19); docstrings in db/project.py, db/static_loads.py,
post/pre_process.py, post/result_1.py updated to match.
2026-08-13 (last) — GSBG retest: the "post mode" gate is a reproducible fix, but the "Final/PostCS" blocker is not leftover state after all¶
Following the Civil-gap review above (which flagged /ope/GSBG as the
one genuinely open item), user opened the same real FCM bridge model
used in the original 2026-07-31 investigation and ran a full analysis,
asking to retry GSBG.
First attempt, FCM bridge (111 nodes, 106 elements), Post mode not yet
manually enabled: created a Girder_All StructureGroup covering the
82 non-pier elements (P1Seg*/P2Seg*/PierTable*/KeySeg*/FSM*
groups' union), then called generate_bridge_girder_diagram —
immediately hit the known "post mode is required" gate again, exactly
as before. Asked the user to manually click the "Post" tab.
User raised a fair question before proceeding: is it okay to test
against a real production bridge? Answered honestly — GSBG itself
has never crashed in any prior session (only clean JSON errors), and the
call doesn't write model data (only an output image file), so the risk
profile is lower than e.g. OCHECK, but not zero since this specific
combination (Post mode + a real registered Bridge Group) had never been
tried. User switched to a different, smaller real bridge model instead
(61 nodes, 52 elements, 4 construction stages CS1-CS4, groups
SG1/SG2/SG3) and confirmed Post mode active via the GUI.
With Post mode confirmed active: "post mode is required" did not
recur. Confirms the manual "Post" tab toggle is a real, reproducible
fix for that specific gate — not a fluke of the 2026-07-31 session.
But "Final/PostCS stage is not supported" came right back,
identically, across STAGE_LIST=["CS1"] (the model's first stage) with
LC_NAME = "Self Weight", "Self Weight(CS)", and "Summation(CS)",
using both a fresh Girder_All group (all 52 elements) and the model's
own pre-existing SG1 segment group as BRDG_GROUP. This session
never called set_result_graphic() before hitting the error — directly
contradicting the 2026-07-31 hypothesis that this was leftover state
from an earlier RESULTGRAPHIC call with a "Summation" load case.
That theory is now ruled out.
Tried one more thing: explicitly selecting stage CS1 as the active
result via set_result_graphic(CURRENT_MODE="beamdiagrams",
LOAD_CASE_COMB={"TYPE": "CS", "NAME": "CS1"}) — failed differently,
"Can not find load case", meaning CS1 alone isn't a valid
LOAD_CASE_COMB.NAME for that call. Didn't find the right name before
stopping (user called time on this thread — GSBG stays open for a
future session, not close-out material today).
Civil NX session stayed "connected" and responsive throughout every
attempt — no crash, no hang, on either bridge model. docs/coverage.json
gained GSBG's first live_verified entry (previously had none at all,
despite the extensive 2026-07-31 investigation never having been
synced in) recording this as still-blocked, not a success.
ope.py's generate_bridge_girder_diagram docstring updated with
today's findings.
2026-08-13 (last) — full live_crud_check.py reconfirmation on Civil NX build 08/12/2026: 43/43, no regressions¶
User asked whether Civil NX had ever had the full CRUD suite run against
it. Answer at the time: yes, all 43 cases confirmed since 2026-07-29,
last fully re-run together 2026-08-07 against build 08/06/2026 — but not
against either of the two patches since (08/11, 08/12). User gave
explicit go-ahead to run it now, understanding /doc/NEW would discard
the small 4-stage bridge model (SG1/SG2/SG3) open from the GSBG
session above (not saved, not needed further).
scripts/live_crud_check.py --product civil (all 6 tiers, no
--include-crashers — nothing is quarantined anymore): 43/43
resources completed a full create→read→update→read→delete→read round
trip, zero failures, against Civil NX 2026 v2.2, build 08/12/2026.
Covers core (10), props (7), boundary (9), static (9, including
/db/NMAS), stage (4), and moving (4, AASHTO LRFD fixtures). No
regressions from the 2026-08-07 baseline. Reconfirmation, not a new
finding — same conclusion as 08-07, now current as of today's patch.
2026-08-13 (last) — Gen NX full verification pass, mirroring today's Civil NX session¶
User asked to do the same broad pass on Gen NX that Civil NX got earlier
today, "in a safe order." Plan: read-only sweep first, then the two
untested read-shaped POSTs, then the riskier /doc/* file-management
family (paths resolve on the NX host, /doc/SAVEAS has a known silent-
failure landmine), and the destructive full CRUD suite last.
Coverage-gap check (read-only, coverage.json only): of 363 gen-
applicable endpoints, 0 had zero live evidence, but 12 had never been
tested on Gen specifically (Civil-only so far): the whole /doc/*
file-management family (OPEN/CLOSE/SAVE/SAVEAS/STAGAS/
IMPORT/IMPORTMXT/EXPORT/EXPORTMXT), /post/PM, /post/
STEELCODECHECK, and the already-known-open /ope/GSBG.
Full read-only sweep, Gen NX v2.1 build 08/12/2026: 266/266 GET- capable resources answered, zero 404s — no regressions from prior sweeps.
/post/PM and /post/STEELCODECHECK, against the small analyzed
2-story concrete column (no RC design code configured): both answered
the same clean precondition errors/empty responses Civil got on 2026-
07-31 ("Please Check RC Design Code" for PM, {"message": ""} for
STEELCODECHECK). Route/shape confirmed on Gen for the first time.
/doc/* file family, path built from verify_connection()['user']
per save_as()'s own documented pattern (C:/Users/sjj0507/Documents/
gsdk_test.mgbx), all against the same disposable test model:
SAVEAS→OPEN(verify) →SAVE→CLOSE→OPEN(reopen): all clean, node count (3) intact through every step. First Gen confirmation for all four endpoints.EXPORT(JSON) succeeded; theIMPORTround trip on that same file failed —"MAINREBAR_B_FY must be > 0."— a clean, informative error (not a crash), but a genuine new finding: this model's exported JSON apparently carries an invalid rebar default that import-side validation rejects. Not root-caused (SDK export gap vs. a real product default-value bug is still an open question). Node count unaffected by the failed import.EXPORTMXTsucceeded; theIMPORTMXTround trip succeeded too, but with a warning that turned out to be inaccurate:"[Warning] Static Seismic/Wind Loads Data for User Type are deleted due to changes in Story Data."A follow-upGETon/db/SWIND,/db/SSEIS, and/db/STORshowed all three completely unchanged — nothing was actually deleted. Don't take this warning's wording as ground truth for final state; verify with GET, same lesson as the "a 200 doesn't mean success" family of findings, just inverted (a warning that doesn't mean failure either).STAGASnot tested — needs a construction-stage model, which this session's throwaway column doesn't have. Still open on Gen.
Session stayed "connected" and responsive throughout every step, no
crash, no hang. docs/coverage.json updated for /post/PM,
/post/STEELCODECHECK, and 8 of the 9 /doc/* endpoints (all but
STAGAS) with today's Gen findings; ROADMAP.md regenerated.
Last step: full scripts/live_crud_check.py --product gen run,
against the same patch build (v2.1, 08/12/2026), no --include-crashers
needed (nothing quarantined). 38/38 resources completed a full
create→read→update→read→delete→read round trip, zero failures — core
(10), props (7), boundary (9), static (9, including /db/NMAS), stage
(3 of 4; /db/CMCS is declared Civil-only in the checker by design).
The moving tier (4 cases) is also Civil-only in the checker, per the
2026-07-29 finding that /db/MVCD's Gen availability is per-CODE, not
unconditional — not re-litigated today. No regressions from any prior
Gen run. This closes out today's Gen NX pass at the same depth as the
Civil NX one earlier: read sweep, the 2 previously-Gen-untested
read-shaped POSTs, the /doc/* file family, and the full write suite,
all clean or with informative (non-crash) findings on this patch build.
2026-08-16 — new patch on both products: connection check only¶
User applied a new patch to both products and asked to confirm both
connect, with versions recorded. verify_connection() against fresh
.env MAPI keys (last-occurrence-wins for the duplicated
MIDAS_MAPI_KEY_GEN/MIDAS_MAPI_KEY_CIVIL lines) succeeded for both:
GEN: {'user': 'sjj0507@midasit.com', 'program': 'gen', 'connectionID': 'N-pAmlMjSg', 'keyVerified': True, 'status': 'connected'}
CIVIL: {'user': 'sjj0507@midasit.com', 'program': 'civil', 'connectionID': 'WjbfiHlPSw', 'keyVerified': True, 'status': 'connected'}
About-dialog screenshots confirm the new build:
- MIDAS GEN NX 2026 (v2.1), build 08/14/2026 (previous: 08/12/2026)
- MIDAS CIVIL NX 2026 (v2.2), build 08/14/2026 (previous: 08/12/2026)
Same version numbers as the prior patch, two-days-newer build only — consistent with a routine patch rather than a version bump.
2026-08-16 (last) — full live_crud_check.py reconfirmation on both products, build 08/14/2026: 43/43 Civil, 38/38 Gen, no regressions¶
User asked to verify the new 08/14/2026 patch after confirming both
products connect (see the connection-check entry above). Chose the full
CRUD-suite scope over a read-only sweep or a targeted re-test of past
crash items, and explicitly authorized the /doc/NEW data loss ("go
go") after being warned.
Ran scripts/live_crud_check.py with no --tier filter (all tiers) on
each product in turn, Civil first:
- Civil NX (v2.2, build 08/14/2026): 43/43 — identical result set to
the 08/12/2026 run (
core/props/boundary/static/stage/movingall pass, including/db/NMASclean via the auto-filledrmX/rmY/rmZworkaround). - Gen NX (v2.1, build 08/14/2026): 38/38 — same as 08/12/2026 (no
movingtier; those fixtures are Civil-confirmed only, per the tier's own docstring in the script).
No crashes, no hangs, no field/value regressions surfaced on either product. This is a clean re-confirmation, not new coverage — same cases as the 08-13 runs, one patch build later.
2026-08-16 (last) — expanding write coverage past the curated CRUD suite: batch 1 of db.project/db.boundary, 14/18 confirmed¶
User asked what to do next on the new 08/14/2026 patch. Given the existing
live_crud_check.py suite only covers a curated 43/38-endpoint subset while
174 /db/* endpoints across both products were still only read-verified,
picked expanding write coverage over re-chasing GSBG's open blocker or the
Gen MAINREBAR_B_FY import bug. User chose to start with db.project +
db.boundary's 24 read-only endpoints (of 174 total), scoped down to a
tractable 18 for this session — deferred the 5 seismic-device endpoints
(SDVI/SDVE/SDST/SDHY/SDIS, deeply nested COMMON payloads) and DRLS
(empty-object payload, no field to round-trip) to a future batch.
Added a new extras1 tier to scripts/live_crud_check.py (18 cases, 3 new
seed steps) covering: PJCF, STYP, STYP-M1, TDGR, NPLN, CO_M,
CO_S, CO_T, CO_F, SPAN, NLLP, NLNK, NLNK-M1, CGLP, PRLS,
MLFC, PZEF, CLDR. First live run (Civil NX v2.2, build 08/14/2026):
10/18, all failures fixture problems as expected on a first pass. Triaged
and fixed 4 of them:
/db/PJCF: a fresh document already carries a Project Info record at id 1 (non-empty placeholder, confirmed viaProjectInfo.items()before any case ran), and POST answers "Key Already Exist" for any id, not just 1, until that record is deleted first. Same singleton family as UNIT/STYP, just with DELETE as the unlock instead of being GET/PUT-only. Added apjcf_unlockseed step./db/STYP:MASS: 0answers "Wrong Field" — valid values are only1(Lumped) or2(Consistent) per the manual's own enum, which the first payload didn't respect. Fixed toMASS: 1./db/SPAN:SPAN_BASE_ITEMS.lengthmust beSPAN_LIST.length + 1(one support point per span boundary) — a 2-items/3-list mismatch answered"[Error] ... (Item:Number of Spans)". The manual's Specifications table doesn't state this relationship; only cross-checking against its own worked JSON example (4 items / 3 values) surfaced it. Fixed to 3 items / 2 values./db/CO_F: keyed by a Floor Load Type (/db/FBLD) id, which the base seed model doesn't create — needed its ownfbld_seedstep. Also found live that CO_F's own"NAME"field is read-only, mirroring the linked FBLD record's name: a PUT withNAME="FL_CRUD"echoed back"FL_SEED"unchanged. Switched the case to probe a colour field (WF_R) instead, matching CO_M/CO_S/CO_T.
One failure did not resolve to a fixture problem: /db/NLLP
(General Link Properties) answers a generic "Unknown Error" on POST even
with the manual's own request-example payload reproduced verbatim
(PROPERTY_NAME/DESC/APPLICATION_TYPE="ELEMENT"/
APPLICATION_TYPE_D="SPG"/TOTAL_WEIGHT/OPT_USE_MASS), tried against
both a partially-seeded and a completely fresh /doc/NEW document, on
both Civil NX and Gen NX. Left as level: read in coverage.json —
genuinely unresolved, not swept under a workaround. This blocks NLNK,
NLNK-M1, and CGLP (all reference an NLLP record by name), so those
three stayed untested this round too; their coverage.json entries got a
2026-08-16 note saying so rather than being silently left stale.
Final result after fixes, re-run fresh on both products:
- Civil NX (v2.2, build 08/14/2026): 14/18 (
STYP-M1/SPANare Civil-only and both pass;NLLP/NLNK/NLNK-M1/CGLPare the 4 failures/blocks). - Gen NX (v2.1, build 08/14/2026): 12/15 (
STYP-M1/SPANcorrectly skipped as Civil-only;NLLP/NLNK/CGLPare the 3 failures/blocks — sameNLLProot cause reproduces here too, ruling out a Civil-specific explanation).
All 14 passing cases flipped to confirmed=True in the script.
docs/coverage.json updated for all 14 to level: "write"; /db/NLLP,
/db/NLNK, /db/NLNK-M1, /db/CGLP stay level: "read" with a dated
note. ROADMAP.md regenerated. Batch 2 (the remaining ~150 read-only
/db/* endpoints, including the deferred seismic-device family and the
NLLP root cause) is open for a future session.
2026-08-16 (last) — write coverage batch 2: db.misc_loads in full + 3 of db.temperature_prestress, 11/12 confirmed¶
Continuing the write-coverage push from earlier today (batch 1: db.project
+ db.boundary, 14/18). User asked to keep going; picked db.misc_loads (all
9 of its endpoints were still read-only) plus 3 tractable
db.temperature_prestress endpoints (GTMP/STMP/BTMP — the other 7 are
tendon/prestress geometry, deferred alongside extras1's seismic-device
family).
Found a genuine shortcut: docs/manual/11_DB_Settlement_Misc_Loads.md ends
with an "End-to-End 워크플로우 예제" that chains all 8 core misc_loads
endpoints (SMPT → SMLC → PLCB → LDSQ → WVLD → IELC → EFCT → INMF) through
one consistent fixture. Adapted its payloads almost verbatim into a new
extras2 tier (12 cases, 1 seed step) instead of re-deriving fixtures from
the Specifications tables like extras1 needed to.
First live run (Civil NX v2.2, build 08/14/2026): 10/12. Triaged the 2 failures:
/db/SMPT: same renumbering behaviour as/db/STLD//db/FBLD— a seed record requested at id 90 landed at id 1 instead, colliding with the case's own id-1 target ("Key Already Exist"). Fixed by moving the case to id 2./db/WVLD: did not resolve to a fixture problem. The manual's own full canonical example, reproduced verbatim, answered"Wrong Field"— and so did a bare{"NAME": "..."}payload, ruling out any specific field. Left atlevel: read, same class of unexplained finding as extras1's/db/NLLP(possibly a licensed offshore/marine module gate, unconfirmed).
Re-run clean on both products after the fix:
- Civil NX (v2.2, build 08/14/2026): 11/12 (
PLCB/WVLDare Civil-only;WVLDis the one remaining failure). - Gen NX (v2.1, build 08/14/2026): 10/10 — clean pass, exit code 0.
PLCB/WVLDcorrectly skipped as Civil-only.
Incidental finding: /db/BTMP (Beam Section Temperature) passed live
on both products, despite the manual's own prose flagging it
"⚠️ MIDAS Civil NX 전용 기능" (Civil-NX-only) — its Specifications table
carries no such restriction and coverage.json already listed both products.
Same documented-vs-actual-routing mismatch pattern as the ch08/ch17
moving-load family from 2026-07-29.
11/12 cases flipped to confirmed=True; docs/coverage.json updated for
all 11 to level: "write", /db/WVLD stays level: "read" with a dated
note. ROADMAP.md regenerated. Batch 3 (properties.*, analysis_control,
dynamic_loads, design, moving_loads, construction_stage, load_combinations,
pushover, bridge, the tendon/prestress half of temperature_prestress, the
deferred seismic-device family, and root-causing NLLP/WVLD) is open for
a future session.
2026-08-16 (last) — write coverage batch 3: tractable subset of db.properties.*, 4-5/9 confirmed¶
Third write-coverage batch of the day. Picked 9 of db.properties.*'s
15 remaining read-only endpoints — deferred the 5 fiber/inelastic-hinge
endpoints (IMFM, EPMT, FIMP, IEHC, IEHG, needing real
stress-strain curve fixtures) and FIBR (depends on FIMP), same
complexity class as extras1's deferred seismic-device family.
First live run (Civil NX v2.2, build 08/14/2026): 5/9. Unlike batches 1-2, most of the 4 failures did not resolve to fixture problems even after reproducing each endpoint's own manual canonical example verbatim:
/db/GRDP(Group Damping): tried both a minimal Specifications-table payload and the manual's full worked example (withGROUP_NAMEas the material's numeric id"1", not its name — the actual fixture bug found — plus the extraSTIFF_COEF_DEFAULT/MASS_COEF_DEFAULT/OPT_*_PROP_DEFAULTfields the manual's example includes but its own Specifications table omits). Both answered"Wrong Field"identically./db/TDMF(Time Dependent Material – User Defined): reproduced the manual's own 4-pointvDAYRequest Body example verbatim (not just the 2-point one first tried) — still"Wrong Field"./db/RPSC(Section Manager – Reinforcements): manual's own example reproduced — still fails./db/STRPSSM(Section Manager – Stress Points, Civil-only): manual's own example reproduced — still fails. Noteworthy: RPSC's own worked example keys at id401and STRPSSM's at id9003, not a plain running number like every other endpoint tested today — both describe "PSC/RC 단면" specifically, so the base seed's plainDBUSERrectangular column section may not carry a Section Manager reinforcement/stress-point slot at all. Left genuinely unresolved rather than guessed at further.
All 4 are the same class of finding as /db/NLLP (extras1) and /db/WVLD
(extras2) — a manual-exact payload still answering a generic error live.
Three unrelated-looking endpoints failing identically on the first try of
a brand-new tier is unusual enough (vs. extras1/2's near-clean first
passes) that it's worth flagging as a pattern to watch, not just three
independent coincidences — worth revisiting with a fresh angle rather than
more payload guessing.
Re-run clean on both products (no changes needed for the passing 5):
- Civil NX (v2.2, build 08/14/2026): 5/9 (
EDMP,PSSF,VSEC,VBEM,EWSFpass;GRDP/TDMF/RPSC/STRPSSMare the 4 failures). - Gen NX (v2.1, build 08/14/2026): 4/7 (
STRPSSM/EWSFcorrectly skipped as Civil-only;GRDP/TDMF/RPSCreproduce the identical failure, ruling out a Civil-specific explanation for those three).
5 passing cases flipped to confirmed=True; docs/coverage.json updated
for EDMP/PSSF/VSEC/VBEM/EWSF to level: "write".
GRDP/TDMF/RPSC/STRPSSM stay level: "read" with dated notes.
ROADMAP.md regenerated. Batch 4 (the deferred fiber/inelastic-hinge
family, analysis_control, dynamic_loads, design, moving_loads,
construction_stage, load_combinations, pushover, bridge, the
tendon/prestress half of temperature_prestress, and root-causing
NLLP/WVLD/GRDP/TDMF/RPSC/STRPSSM) is open for a future session.
2026-08-16 (last) — write coverage batch 4: db.load_combinations in full, 7-8/8 confirmed¶
Fourth write-coverage batch of the day. db.load_combinations was a clean
target: all 8 of its endpoints were still read-only, and 6 of them
(LCOM-GEN/CONC/STEEL/SRC/STLCOMP/SEISMIC) share one payload shape per
the module's own LoadCombinationPayload docstring, so the tier is mostly
one parametrized case repeated six times.
First live run (Civil NX v2.2, build 08/14/2026): 7/8 — only
LCOM-SEISMIC failed, with "The Load Combination Type is not
supported" for the same ANAL="ST" payload its 5 siblings all accept.
The interesting part: re-running on Gen NX passed 8/8, including
LCOM-SEISMIC with the identical payload. This is the first
same-day, same-build, same-payload case in today's batches where the two
products actually disagree rather than one being a documented
Gen/Civil-only route — Civil genuinely rejects ANAL="ST" for seismic
combinations while Gen accepts it. Tried the manual's own ANAL="RS"/
"CS" alternative on Civil against the base seed's plain static "DL"
case; both answered "Unknown Error" instead, because DL isn't
actually an RS/CS-typed case — reproducing the manual's intended usage
properly needs a real /db/SPLC Response Spectrum Load Case, which is
one of the db.dynamic_loads endpoints deferred to a future batch. Left
LCOM-SEISMIC at level: read rather than call it "confirmed" off an
asymmetric pass.
7 cases (LCOM-GEN, LCOM-CONC, LCOM-STEEL, LCOM-SRC,
LCOM-STLCOMP, CUTL, CLWP) flipped to confirmed=True;
docs/coverage.json updated for all 7 to level: "write".
LCOM-SEISMIC stays level: "read" with a dated note explaining the
product asymmetry. ROADMAP.md regenerated.
Running total for today's write-coverage push (batches 1-4): 42 endpoints
flipped to level: write, 7 left as genuinely unresolved live findings
(NLLP, WVLD, GRDP, TDMF, RPSC, STRPSSM, LCOM-SEISMIC). Batch
5 (the deferred fiber/inelastic-hinge family, db.analysis_control,
db.dynamic_loads — which would also unblock LCOM-SEISMIC —
db.design, db.moving_loads, db.construction_stage's hydration
family, db.pushover, db.bridge, and the tendon/prestress half of
db.temperature_prestress) is open for a future session.
2026-08-16 (last) — write coverage batch 5: db.dynamic_loads, new Gen NX crash found and filed as MAPI-2468¶
Fifth write-coverage batch of the day, and the one this session picked
specifically because it also unblocks batch 4's LCOM-SEISMIC finding
(needs a real /db/SPLC Response Spectrum Load Case). Covered 9 of
db.dynamic_loads's 12 endpoints — deferred the 3 Hyper-S variants
(THGC-M1/THOO-M1/THIS-M1, deeply-nested required control
sub-objects).
First live run (Civil NX v2.2, build 08/14/2026): 4/9. Triaged and fixed 3 fixture issues:
/db/SPFC//db/THIS//db/THFC: all three answered "Key Already Exist" — their seed records (requested at id 90) renumber to id 1, same STLD/FBLD/SMPT family, so the cases' own test records collided at the same id. Fixed by moving the cases to the next free id (2, or 3 where/db/THFChas two seed records ahead of it)./db/THNL: "Unknown Error" — itsFUNC_NAMEmust reference a Force/Moment-type function (iTYPE=3/4), not the Accel-type one (iTYPE=2) already seeded for other cases; added a second, Force-typed seed function. This matches the manual's own explicit warning ("FUNC_NAME에는 Force 또는 Moment 타입의 시간이력 함수만 사용 가능"), just missed on the first pass.
Re-run clean on Civil NX after the fixes: 8/9 (only THMS still fails —
see below).
Then, running the same tier on Gen NX, the product crashed mid-run.
SPLC failed normally ("Unknown Error", session still alive), THGC/
THIS/THFC/THGA all passed clean, then THNL's own case showed
create=ok read_back=ok update=FAIL — its PUT failed with 404 Client
Disconnected, and the very next case (THSL) got 404 client does not
exist. The checker's own _session_lost guard caught it and aborted
correctly. User asked directly ("Gen NX 뭐가 죽은 것 같은데?") mid-run;
confirmed via a direct verify_connection() call that status itself
had flipped to "disconnected" — not just a blocked-dialog false
"connected" (the documented verify_connection()-can't-see-a-blocked-
session landmine). This was a genuine session death, not a masked hang.
User restarted Gen NX, then explicitly asked to reproduce the same
scenario again ("다시 한번 같은 상황 연출해봐"). Re-ran the identical
tier on the freshly-restarted Gen NX session and the crash reproduced at
the exact same point: SPLC "Unknown Error" (alive), four clean
passes, THNL create=ok read_back=ok update=FAIL with the same 404
Client Disconnected, then the aborted follow-on call. Two independent
reproductions, same trigger, same build (v2.1, 08/14/2026) — this
project's usual "confirmed" bar.
Isolated the trigger precisely: POST /db/THNL succeeds and the
following GET echoes it back correctly, but the next PUT
/db/THNL ({"Assign": {"1": {"ITEMS": [{...}]}}}, only
SCALE_FACTOR changed from the create payload) is what kills the
session — not the POST itself. Civil NX's identical round trip is
completely clean.
User asked to write this up and file it in MIDASIT's internal Jira
("내용 정리하고 Jira에 올리자 이건"). Searched project = MAPI AND (text
~ "THNL" OR text ~ "Dynamic Nodal Load") first — no existing ticket for
this symptom (the only THNL hit, MAPI-177, is an unrelated closed 2023
delete-behavior ticket). Filed MAPI-2468, parented under MAPI-2427
("API 동작 중 프로그램 종료 이슈" — the same crash-symptom epic that
already holds MAPI-2378/NMAS, MAPI-2425/EDMP, MAPI-2426/USLC, and
MAPI-2431/CD-TABLE), priority 높음 (id: "3", matching all four
precedents), with the exact reproduction payload, both reproduction
timestamps, and an open "root cause not yet identified" framing — not
linked to the other four as a shared cause, since there's no evidence of
one, same call this project made for MAPI-2431.
live_crud_check.py's /db/THNL case is now restricted to
products=("civil",) rather than fully crash-quarantined, since only
Gen NX actually crashes and Civil's round trip is clean — re-enabling Gen
needs a deliberate decision once MAPI-2468 is resolved, not an assumption
that a vendor fix landed.
One more genuinely unresolved finding, same class as extras1/2/3's
NLLP/WVLD/GRDP/TDMF/RPSC/STRPSSM: /db/THMS answers
"Wrong Field" on both products even with the manual's own field names
and a required-fields-only payload. db/dynamic_loads.py's own docstring
already flags it as "Keyed by node/group id" (unlike THNL's plain node
id) — may need a real multi-support boundary/support group defined
first, not just any integer key.
Also product-asymmetric (mirroring LCOM-SEISMIC's reversed case from
batch 4): /db/SPLC passes clean on Civil NX but Gen NX answers
"Unknown Error" on the identical payload, reproduced twice — left at
level: read pending investigation (possibly needs a Gen-specific modal/
eigenvalue analysis-control setup).
Final tally: 6 endpoints (SPFC, THGC, THIS, THFC, THGA, THSL)
write-confirmed on both products; THNL write-confirmed on Civil only
(Gen crashes, MAPI-2468 filed); SPLC and THMS stay level: read as
genuine unresolved findings. docs/coverage.json and ROADMAP.md
updated accordingly.
Running total for today's write-coverage push (batches 1-5): 49 endpoints
flipped to level: write, 9 left as genuinely unresolved live findings
(NLLP, WVLD, GRDP, TDMF, RPSC, STRPSSM, LCOM-SEISMIC,
SPLC, THMS), plus one new confirmed live crash (THNL PUT on Gen NX,
MAPI-2468). Batch 6 (the deferred fiber/inelastic-hinge family, seismic
devices, db.analysis_control, db.design, db.moving_loads's
remainder, db.construction_stage's hydration family, db.pushover,
db.bridge, the tendon/prestress half of db.temperature_prestress, the
3 deferred Hyper-S dynamic_loads variants, and root-causing the 9 unresolved
findings above) is open for a future session.
2026-08-16 (last) — write coverage batch 6: seismic-device family from db.boundary, 0/5 -- genuine finding, not a fixture bug¶
Sixth write-coverage batch of the day. Picked up the seismic-device family
(SDVI/SDVE/SDST/SDHY/SDIS) that batch 1 deliberately deferred out
of extras1 for its deeply nested COMMON payloads. Transcribed each
payload from the manual's own POST worked examples (05_DB_Boundary.md,
items 16-20), not the leaner Specifications tables, per this project's
standing preference for worked examples over tables when they disagree.
First live run (Civil NX v2.2, build 08/14/2026): 0/3 (SDHY/SDIS are
Gen-only, correctly skipped). All three POSTs answered "Wrong Field".
Bisected by hand rather than assuming a fixture bug outright, given this
project's own caution about varying values before field names:
- Reproduced the manual's own bare literal
SDVIexample verbatim (DAMPER_TYPE=0,DASHPOT_TYPE=0— Linear Elastic, not the customized=2Exponential values the case used) — still"Wrong Field". - Fetched
SDVI.info()'s live JSON schema: field names match the manual exactly (COMMON.{NAME,DESC,INPUT_METHOD,COMPANY,PRODUCT_NAME, TYPE_NUMBER},DEVICE_TYPE,DAMPER_TYPE,DASHPOT_TYPE,INPUT_TYPE,ITEM[6]— plus an undocumentedINPUT_TYPE_EXFNand per-itemEXFN_*fields for the Exponential dashpot type), ruling out a field-name typo. - Tried a
COMMON-only payload, a payload withINPUT_TYPE_EXFNadded, noITEMarray, noDEVICE_TYPE, non-emptyCOMPANY/PRODUCT_NAME/TYPE_NUMBEReverywhere,INPUT_METHOD=1(Reference DB), and a single-entryITEMarray instead of 6 — every variant still answered"Wrong Field". - Extended the same manual-literal-payload test to
SDVE/SDST(Civil) andSDHY/SDIS(Gen) — all 4 failed identically, and a full--tier extras6run on Gen NX confirmed all 5 fail there too (SDHY/SDISincluded this time, since Gen is where they're actually implemented).
Not resolved as a fixture problem on either product. Notably, /db/NLLP
(General Link Properties, extras1's confirmed-broken endpoint) is the
table these five devices are meant to be referenced from
(APPLICATION_TYPE_D="VI"/"VE"/"ST"/"HY"/"IS") — two independently
confirmed-broken endpoint families in the same manual chapter raises
suspicion of something chapter-wide (a licensed isolator/damper-design
module gate not enabled on this session?) rather than five unrelated
defects, but that's unconfirmed speculation, not a finding to act on.
Left all 5 at level: read in docs/coverage.json, each with a dated
note; none of the extras6 cases are confirmed=True since none have
ever passed live. /db/DRLS (#24, the other endpoint extras1 deferred out
of this chapter) stays deferred for an unrelated, purely mechanical reason:
its payload is {<node id>: {}}, an empty object with no field to
distinguish a create from an update, so it doesn't fit this checker's
create/update/probe shape at all — a different problem from the
"Wrong Field" finding above. ROADMAP.md regenerated (399/399
implemented, write-count unchanged by this batch since nothing passed).
Running total for today's write-coverage push (batches 1-6): still 49
endpoints flipped to level: write (batch 6 added 0), 14 left as
genuinely unresolved live findings (NLLP, WVLD, GRDP, TDMF, RPSC,
STRPSSM, LCOM-SEISMIC, SPLC, THMS, SDVI, SDVE, SDST, SDHY,
SDIS), plus the one confirmed live crash from batch 5 (THNL PUT on Gen
NX, MAPI-2468). Batch 7 (the deferred fiber/inelastic-hinge family,
db.analysis_control, db.design, db.moving_loads's remainder,
db.construction_stage's hydration family, db.pushover, db.bridge,
the tendon/prestress half of db.temperature_prestress, the 3 deferred
Hyper-S dynamic_loads variants, /db/DRLS's empty-payload shape problem,
and root-causing the 14 unresolved findings above) is open for a future
session.
2026-08-17 — write coverage batch 7: standalone/frame-attachable remainder of db.static_loads, 4/5 (Civil) + 5/8 (Gen)¶
Seventh write-coverage batch, continuing without a fresh scope check —
picked the remaining db.static_loads endpoints that don't need real
plate/planar geometry beyond what the base seed model already has: PNLD,
PNLA, FBLA, FMLD, POSP, EPST, POSL, EPSE. (PNLA was
initially assumed to need real plate geometry and deferrable, but
_seed_model's own base model already has one — element 4, nodes 5-8 — so
it came along for free.)
First live run (Civil NX v2.2, build 08/14/2026): 1/5, only FMLD passed
clean. Triaged the rest:
/db/PNLD: create succeeded but read-back failed — same STLD/FBLD-family renumbering as extras1/extras5's seeds (the seed landed at id 1, not the requested 90; the case's own id 91 request actually landed at id 2). Fixed by pointing the case at id 2 and citing the seed's real id./db/PNLA:"Wrong Field"even after fixingPNLD_KEYto the seed's real id. Bisected by removing one field at a time — the manual marksLOAD_GROUPRequired, but sending any non-empty value for it answers"Wrong Field"; omitting the key (or sending"") succeeds. Fixed by dropping it;db/static_loads.py'sPlaneLoadPayloaddocstring now documents this./db/POSL:"Wrong Field"on every payload, including the manual's own literal example. Fetched.info()'s live schema: Civil NX's actual field set isNAME/SZ/SRF/SC/FA/FV/DAMP_RATIOonly — a completely different, smaller shape than the manual'sCODE/METHOD/EPA/SDS/SD1/USER_GROUP/IF/RMF. SendingCODEat all — even as""— was confirmed as the specific trigger via per-field bisection. Checked Gen NX's own.info()schema for comparison and found it does match the manual (plus two undocumented fields,EPGAeff/Kae) — this endpoint's real contract is product-asymmetric, not just wrong. Split the checker's onePOSLcase into two, one payload per product;SeismicLoadParamPayloadindb/static_loads.pynow documents both shapes.
Re-run clean on Civil after the PNLD/PNLA/POSL fixes: 4/5
(PNLD, PNLA, FMLD, POSL pass; FBLA is the one remaining
failure, "Unknown Error" on POST, not resolved as a fixture problem
despite trying the base model's plate-corner nodes and an unrelated
frame-chain node set, both winding orders, FLOOR_DIST_TYPE 1 and 2, and
the manual's full optional-field set).
Gen NX (v2.1, build 08/14/2026), same fixed cases plus the Gen-only
trio (POSP/EPST/EPSE): 5/8. POSP's first attempt answered
"Unknown Error" with a single soil layer — fixed by using the manual's
own 3-layer example, whose HEIGHT values sum to exactly the depth from
GROUND_LEVEL to BEDROCK_LEVEL (5+5+15=25m); a single layer that
doesn't reach that depth appears to be the trigger, the same undocumented
cross-field relationship class as /db/SPAN's item-count-vs-list-length
rule from batch 1. POSP, PNLD, PNLA, FMLD, POSL all passed
clean after fixture fixes. EPST and EPSE both failed "Wrong Field"
even with field names confirmed matching their own live /info schema
and several bisected variants (SEL_TYPE, EP_TYPE, blank SOIL_PROP,
omitted IN_PT, PRES_PROFILE_ITEMS) — not resolved as fixture
problems, left level: read alongside FBLA. EPST/EPSE are untested
on Civil NX since POSP (which their SOIL_PROP references) is
Gen-only, so there's no Civil fixture to build them against — genuinely
untested there, not confirmed broken.
6 endpoints flipped to level: write (PNLD, PNLA, FMLD, POSP,
POSL — POSL write-confirmed on both products despite the schema
split); FBLA, EPST, EPSE stay level: read as new unresolved
findings. docs/coverage.json and ROADMAP.md updated; pytest (701)
and ruff both clean after the source-level PlaneLoadPayload/
SeismicLoadParamPayload docstring fixes.
Running total for the write-coverage push (batches 1-7): 55 endpoints
flipped to level: write, 17 left as genuinely unresolved live findings
(NLLP, WVLD, GRDP, TDMF, RPSC, STRPSSM, LCOM-SEISMIC,
SPLC, THMS, SDVI, SDVE, SDST, SDHY, SDIS, FBLA, EPST,
EPSE), plus the one confirmed live crash from batch 5 (THNL PUT on
Gen NX, MAPI-2468). Batch 8 (the deferred fiber/inelastic-hinge family,
db.node_element's Domain feature, db.analysis_control, db.design,
db.moving_loads's remainder, db.construction_stage's hydration
family, db.pushover, db.bridge, the tendon/prestress half of
db.temperature_prestress, the 3 deferred Hyper-S dynamic_loads
variants, /db/DRLS's empty-payload shape problem, and root-causing the
17 unresolved findings above) is open for a future session.
2026-08-17 — write coverage batch 8: tractable subset of db.analysis_control, 5/9 (Civil) + 7/9 (Gen)¶
Eighth write-coverage batch, continuing without a fresh scope check.
Picked 9 of db.analysis_control's 21 endpoints: the singleton "control
data" tables (ACTL, PDEL, BUCK, EIGV, HHCT, MVCT, SMCT,
NLCT, BCCT) — each is one record at id 1, referencing only the base
seed model's own load cases, so no per-tier geometry was needed. Deferred
the 5 Hyper-S (-M1) variants and the 4 country-specific MVCT
variants (MVCTch/id/bs/tr) as before.
First live run (Civil NX v2.2, build 08/14/2026): 3/9. Triaged:
/db/EIGV: the manual's own first worked example usesTYPE: "EIGEN"(Subspace Iteration) and answered"FREQ_RANGE is required for LANCZOS."— the server doesn't recognize"EIGEN"as a validTYPEat all despite the manual and/info's own schema both listing it; only"LANCZOS"/"RITZ"work. Fixed by switching to the manual's own Lanczos example./db/BCCT:vBOUNDARY'svBGentries ("BG1"/"BG2", the manual's own example values) answered"Boundary Group not found: BG1"— they have to be real/db/BNGRboundary groups, not free-text labels. Fixed with abngr_seedstep.
Three did not resolve to fixture problems, each a distinct kind of finding:
/db/ACTL:TOLnever persists as written on Civil NX — POST succeeds and reads back correctly, but a follow-up PUT changing onlyTOLreads back the original value every time, confirmed even after a full DELETE + fresh POST with a differentTOL. On Gen NX the same payload fails outright with"Wrong Field", including a bare{ITER, TOL}-only payload — and Gen's own/infoschema turns out to differ from Civil's/the manual's (noCLATS, an undocumentedACWCthat answers"Wrong Key"when sent, ruling that field out too as the cause). Two different symptoms, same verdict: unresolved on both./db/NLCT: Civil NX answers"LINE_SEARCH_OPTION is required when OPT_ENABLE_LINE_SEARCH is true."— neither field is in the manual or in/info's own live schema. TriedOPT_ENABLE_LINE_SEARCH: falseexplicitly (same error) and a guessedLINE_SEARCH_OPTION: "AUTO"alongsidetrue(also unchanged). Passes clean on Gen NX with the exact same payload — product-asymmetric, so the checker now carries two cases, one per product./db/HHCT: Civil NX'sTHETAfield has the same "write doesn't stick" symptom asACTL'sTOL— POST succeeds with no error body, but the immediate GET readsTHETAback as0, not the1sent, reproduced twice. Also passes clean on Gen NX with the identical payload — another product-asymmetric split into two cases./db/MVCT: fails on both products, with different errors depending on payload completeness — the manual's full example answers"Unknown Error"on both Civil and Gen, a stripped-down minimal payload answers"Wrong Field"on Civil instead. Field names match/infoon both. Noted as possibly needing the full AASHTO LRFD moving-load fixture chain (code → lane → vehicle → case, see the"moving"tier) built first rather than being a standalone control table like its 8 siblings here — untested, not pulled into this tier's scope given the size of that prerequisite chain.
Final result after fixes, re-run clean on both products:
- Civil NX: 5/9 (
PDEL,BUCK,EIGV,SMCT,BCCTpass;ACTL,HHCT,MVCT,NLCTare the 4 failures). - Gen NX: 7/9 (same 5 plus
HHCTandNLCT;ACTLandMVCTare the 2 failures, confirmed as genuinely both-product issues rather than Civil-specific).
9 endpoints flipped to level: write total — 5 confirmed both products
(PDEL, BUCK, EIGV, SMCT, BCCT), 2 confirmed Gen-only (HHCT,
NLCT, with the level: write reflecting the Gen NX result specifically
per this project's convention of documenting the asymmetry rather than
averaging it away). ACTL and MVCT stay level: read as new
unresolved findings. docs/coverage.json and ROADMAP.md updated;
pytest (701) and ruff both clean.
Running total for the write-coverage push (batches 1-8): 64 endpoints
flipped to level: write, 19 left as genuinely unresolved live findings
(NLLP, WVLD, GRDP, TDMF, RPSC, STRPSSM, LCOM-SEISMIC,
SPLC, THMS, SDVI, SDVE, SDST, SDHY, SDIS, FBLA, EPST,
EPSE, ACTL, MVCT), plus the one confirmed live crash from batch 5
(THNL PUT on Gen NX, MAPI-2468). Batch 9 (the deferred fiber/
inelastic-hinge family, db.node_element's Domain feature, the
remaining 12 of db.analysis_control — 5 Hyper-S + 4 country-specific
MVCT + MVCT itself once its moving-load prerequisite chain is worked
out, db.design, db.moving_loads's remainder, db.construction_stage's
hydration family, db.pushover, db.bridge, the tendon/prestress half
of db.temperature_prestress, the 3 deferred Hyper-S dynamic_loads
variants, /db/DRLS's empty-payload shape problem, and root-causing the
19 unresolved findings above) is open for a future session.
2026-08-17 — write coverage batch 9: db.node_element's Domain feature, 0/3 -- /db/MADO silently drops writes¶
Ninth write-coverage batch. Picked up db.node_element's last 3
read-only endpoints: MADO, SBDO, DOEL (the "Domain" feature used
for 2D/plane-stress mesh assignment). Small, self-contained scope —
SBDO/DOEL both reference a MADO domain by name/id, so the tier
needed a mado_seed creating two named domains (DM1_SEED/DM2_SEED)
plus DOEL's own case targeting the base seed model's existing plate
element (id 4, nodes 5-8) rather than building new geometry.
First live run (Civil NX v2.2, build 08/14/2026): 0/3, all three
read_back failures with "id N missing after wrote". Initially looked
like the familiar STLD/FBLD-family renumbering gotcha from earlier
batches, but a manual GET on all three tables immediately after
create() came back completely empty — not renumbered, genuinely never
written. Bisected /db/MADO specifically since it's the root of the
dependency chain:
POST /db/MADOanswers{"message": ""}— HTTP success, no error body at all — but the record is absent from a follow-upGET, every time.- Reproduced with several payload variants:
MATL/PROPpointed at the base model's real material/section ids (1/1),SUB_TYPE1 and 2,TYPE3 (Plane Stress) instead of 4 (Plate), and — the clearest signal — the manual's own literal request-body example reproduced verbatim (NAME: "DM1",MATL: 0,PROP: 0,SUB_TYPE: 2). All silently no-ops. - Checked Gen NX independently: identical
{"message": ""}/ empty-GET result with the same literal manual payload.
Not resolved as a fixture problem on either product — a "message": ""
success response that doesn't persist anything is a different failure
shape than this session's usual "Wrong Field"/"Unknown Error" class,
closer to the /doc/SAVEAS "command complete but no file written"
pattern this project has already documented elsewhere, just on a /db/*
table instead of a file write.
SBDO and DOEL both fail as a direct consequence — they reference
DM1_SEED/DM2_SEED by name/id, and those domains were never actually
created — so their own field contracts remain genuinely untested, not
confirmed broken independently of MADO. Left all 3 at level: read
with dated notes making that dependency explicit; the checker's own
cases are kept (not skipped) so a future MADO fix can be verified to
unblock SBDO/DOEL without touching this tier's code again.
Caught and fixed one process mistake before finalizing: MADO's own
case was initially marked confirmed=True while drafting the fixture,
before it had actually been run live — the first real run correctly
flagged it as a regression (a confirmed case failing) rather than an
unverified failure, which would have been a false alarm. Reverted the
premature flag before this file/coverage.json were touched, so nothing
downstream saw the false regression.
docs/coverage.json and ROADMAP.md updated (all 3 stay level: read
— this batch added 0 to the write count, a clean miss rather than a
partial one). pytest (701) and ruff both clean.
Running total for the write-coverage push (batches 1-9): still 64
endpoints at level: write (batch 9 added 0), 22 left as genuinely
unresolved live findings (NLLP, WVLD, GRDP, TDMF, RPSC,
STRPSSM, LCOM-SEISMIC, SPLC, THMS, SDVI, SDVE, SDST,
SDHY, SDIS, FBLA, EPST, EPSE, ACTL, MVCT, MADO, SBDO,
DOEL), plus the one confirmed live crash from batch 5 (THNL PUT on
Gen NX, MAPI-2468). Batch 10 (the deferred fiber/inelastic-hinge
family, the remaining 12 of db.analysis_control, db.design,
db.moving_loads's remainder, db.construction_stage's hydration
family, db.pushover, db.bridge, the tendon/prestress half of
db.temperature_prestress, the 3 deferred Hyper-S dynamic_loads
variants, /db/DRLS's empty-payload shape problem, and root-causing the
22 unresolved findings above) is open for a future session.
2026-08-17 — write coverage batch 10: standalone subset of db.construction_stage's heat-of-hydration family, 5/7 both products¶
Tenth write-coverage batch. Picked 7 of db.construction_stage's 10
remaining read-only endpoints — the heat-of-hydration family
(ETFC/CCFC/HSFC/HAHS/HPCE/STBK/HSTG), deferring HECB and
HSPT (both keyed by a construction-stage id per the manual's own note)
and CSCS (references a stage name via ASTAGE) since none of the
three have a construction stage to attach to in this tier's fixture.
The chapter's own End-to-End workflow example covers 6 of these 7
(ETFC→CCFC→HSFC→HAHS→HECB→HSTG), so most payloads were
adapted from it rather than re-derived from the Specifications tables.
First live run (Civil NX v2.2, build 08/14/2026): 4/7. Triaged:
/db/HSFC:"Key Already Exist"— the case's own id (91) collided withhsfc_seed's second record, which the seed also placed at 91. Fixed by moving the case to id 92./db/HSTG: passed on the first try — the fixture used real/db/GRUP-family structure/boundary group names (SG10_SEED/BG10_SEED) from the start rather than the manual's own made-up group-name example, applying the/db/BCCTlesson from batch 8 proactively instead of hitting the same wall twice.
Two did not resolve to fixture problems:
/db/HAHS: answered"[Error] The element no. 1 is an element type in which Heat Source Assignment cannot be entered."for element 1 (a frame/beam). Switched to element 4 (the base model'sPLATE) — same error, just renumbered to element 4. Heat-of-hydration is normally applied to mass concrete (piers, footings) modelled asSOLIDelements, which the base seed model doesn't build — most likely a scope gap in this fixture rather than a confirmed product defect, since a realSOLIDelement was never tried. Left unconfirmed rather than treated as a genuine finding, pending that test in a future session./db/HPCE: answered"Wrong Key"— a different error class than this session's usual"Wrong Field"/"Unknown Error". Bisected field by field: every field exceptITEMSsucceeds individually (each answering the ordinary"Wrong Field"for an incomplete payload), but addingITEMS— with real frame node ids, real plate node ids, or a single node — always flips the error to"Wrong Key"instead. Live/info's own schema confirmsITEMSis a plain integer array, matching exactly what was sent, so this isn't a documented-vs-actual mismatch either. Also found two undocumented fields via/info(START_STAGE/END_STAGE, both strings, absent from the manual entirely) and tried them both empty and omitted — no change either way. Genuinely unresolved, same class as/db/FBLA//db/EPSTetc.
Re-run clean on both products after the HSFC/HSTG fixes:
- Civil NX: 5/7 (
ETFC,CCFC,HSFC,STBK,HSTGpass;HAHSandHPCEare the 2 failures). - Gen NX: same 5/7 split, confirming
HAHS/HPCEaren't Civil-specific.
5 endpoints flipped to level: write; HAHS and HPCE stay
level: read with dated notes. docs/coverage.json and ROADMAP.md
updated; pytest (701) and ruff both clean.
Running total for the write-coverage push (batches 1-10): 69 endpoints
flipped to level: write, 24 left as genuinely unresolved or
scope-limited live findings (NLLP, WVLD, GRDP, TDMF, RPSC,
STRPSSM, LCOM-SEISMIC, SPLC, THMS, SDVI, SDVE, SDST,
SDHY, SDIS, FBLA, EPST, EPSE, ACTL, MVCT, MADO, SBDO,
DOEL, HAHS, HPCE), plus the one confirmed live crash from batch 5
(THNL PUT on Gen NX, MAPI-2468). Batch 11 (the deferred fiber/
inelastic-hinge family, the remaining 12 of db.analysis_control,
db.design, db.moving_loads's remainder, db.construction_stage's
HECB/HSPT/CSCS — needs a real construction stage built first —
db.pushover, db.bridge, the tendon/prestress half of
db.temperature_prestress, the 3 deferred Hyper-S dynamic_loads
variants, /db/DRLS's empty-payload shape problem, retesting /db/HAHS
against a real SOLID element, and root-causing the 24 unresolved
findings above) is open for a future session.
2026-08-17 — correction: EIGV/BCCT were never actually confirmed on Civil NX¶
Re-reading batch 8's own raw result files (extras8_civil.json, checked_at
2026-08-16T15:47:37Z) while resuming the write-coverage push turned up a
mismatch: the code and docs/coverage.json both claimed /db/EIGV and
/db/BCCT were "confirmed both products," but that Civil NX run — the only
one ever made for these two cases — has both failing:
EIGV:"FREQ_RANGE is required for LANCZOS.", the identical error the batch-8 write-up already documents for the rejectedTYPE="EIGEN"attempt — except this run used the fixedTYPE="LANCZOS"payload (iFREQ/bMINMAX/FRMIN/FRMAX/bSTRUM) that passes clean on Gen. Civil answers the same error anyway, meaning it wants some additional, undocumented field literally namedFREQ_RANGEthatFRMIN/FRMAXdon't satisfy.BCCT:"Boundary Group not found: BG1"— the exact error thebngr_seedfix (creating real/db/BNGRgroups namedBG1/BG2) was supposed to clear, and did clear on Gen (extras8_gen.json, same day, 5 minutes later, both casesok). Civil rejects the same real groups under the same names.
No Civil retry for either case exists anywhere in this session's scratch
output (checked — extras8_civil2.json was never created, unlike
extras7_civil2.json/extras10_civil2.json which do exist for their
tiers' fixed re-runs). The "confirmed both products" claim was written
without actually re-running Civil after the Gen fix landed — caught this
time by cross-checking the code against its own raw evidence, per this
project's standing "verify before confirming already done" rule.
Fixed: both Cases split into products=("civil",) unconfirmed /
products=("gen",) confirmed=True, same pattern as HHCT/NLCT.
docs/coverage.json's method notes for both rewritten to state
"confirmed live on Gen NX; Civil NX fails" instead of "both products."
ROADMAP.md regenerated (399/399 implemented, unchanged — both stay
level: write since Gen alone still counts, same as HHCT/NLCT; the
batch 1-10 running total of 69 write / 24 unresolved is unaffected, only
the per-endpoint accuracy). pytest and ruff both clean.
Lesson for future batches: a product-split Case pair should be written
(and confirmed set) only after both products have actually been run
with the final payload — not after fixing one product's error and
assuming the fix generalizes.
2026-08-17 — batch 11a: /db/STCT (last tractable gap in db.analysis_control)¶
Of the 12 db.analysis_control endpoints left unattempted after batch 8, 11
are Hyper-S/-M1 variants or the four large country-specific MVCT
siblings (MVCTch/MVCTid/MVCTbs/MVCTtr) — all deferred as before.
/db/STCT (Construction Stage Analysis Control Data) was the one genuinely
tractable endpoint left, so it got its own tier (extras11) rather than
waiting for a bigger batch.
Needs a real construction stage to reference (FINAL_STAGE), so it reuses
the stage tier's own stage_1 seed (CS_SEED) — confirmed the manual's
own worked example makes the same mistake batch 8 already found on BCCT
(a made-up stage name, "CS1"), swapped for the real one from the start.
First Civil run failed immediately: POST /db/STCT answered "Key Already
Exist". Investigated directly (bypassing the harness) and found the real
shape of the problem — once a real construction stage is registered,
/db/STCT already holds an auto-populated default record at id 1,
before any explicit POST. Tried DELETE-then-POST to clear it first;
DELETE answered its own separate error: "[Error] Construction Stage
Analysis Control Data cannot be deleted when the Construction Stage is
registered." So this table is POST/DELETE-locked once construction
staging is in use — a real business rule, not a fixture bug.
Fell back to a manual PUT on the existing id-1 record instead. The PUT
itself succeeded and its response echoed iITER/TOL back correctly, but
a follow-up GET dropped both fields entirely (present in every other
respect — FINAL_STAGE, CPFC, bCONV/bTRUSS/bBEAM, bCAMBER,
bCHANGE_CABLE, iNLA_TYPE, bINC_TDE, bCNS, TYPE, iITER_CR,
TOL_CR all persisted). Repeated with a second iITER value to rule out
a one-off — same result both times.
Gen NX doesn't pre-populate a default record, so POST itself succeeds
there, but the identical iITER/TOL silent-drop reproduces on the very
first GET after create ("wrote 30, read back None") — confirming the
underlying defect is symmetric across both products, only the
POST-vs-already-exists wrinkle is Civil-specific. Likely cause: the
payload combines iINC_NLA=0 (Linear) with iNLA_TYPE=1 (Accumulative)
per the manual's own example, and the server may treat the two
Linear-only fields as inapplicable under Accumulative mode without saying
so.
Left as a genuine, product-symmetric finding — the Case in extras11
stays unconfirmed, documenting the Civil "Key Already Exist" failure
directly (closest to what a real caller hits first). docs/coverage.json
records the fuller story (both products, both failure modes) since the
generic harness can only exercise one of them per run. level stays
read. ROADMAP.md regenerated (399/399 implemented, unchanged);
pytest (701) and ruff both clean.
Running total for the write-coverage push (batches 1-11a): still 69
endpoints at level: write; 25 now carry a dated genuinely-unresolved or
scope-limited finding (the 24 from batches 1-10 plus STCT), plus the one
confirmed live crash (THNL PUT on Gen NX, MAPI-2468).
2026-08-17 — batch 11b: moving tier confirmed on Gen NX¶
The moving tier's own header comment had been sitting there since
2026-07-30 with a note that it should pass on Gen unchanged — the AASHTO
LRFD codes are the ones confirmed not gated by the region-code lock, and
the same fixture already round-trips clean on Civil — but that nobody had
actually run it against a Gen session. Ran it: core (base model) +
moving against Gen NX, identical fixture (MVCD "AASHTO LRFD", LLAN
line lanes, MVHL/MVHC HL-93 truck/tandem vehicles, MVLD vehicle
classes) — all 4 pass clean, full create→read→update→read→delete→read.
Re-ran Civil NX afterward too, to make sure widening products didn't
regress anything — also clean, 14/14 both times.
Widened all 4 Cases from products=("civil",) to both, kept
confirmed=True (already true from the Civil confirmation).
docs/coverage.json's method note for LLAN/MVHL/MVHC/MVLD
updated to record the Gen write-round-trip explicitly — they'd been
level: write already off the Civil result plus a separate GET-only Gen
sweep from 2026-08-10, so the write/read tally is unchanged; this closes
the Gen side from "route exists" to "write proven." ROADMAP.md
regenerated (399/399, unchanged); pytest (701) and ruff both clean.
2026-08-17 — batch 11c: /db/HECB//db/HSPT (construction-stage-keyed heat-of-hydration pair)¶
Batch 10 deferred HECB/HSPT/CSCS because they need a real construction
stage id, which this session's stage tier now provides (stage_1 seeds
CS_SEED at id 1). Added both to the extras11 tier alongside STCT.
Both are keyed by construction stage number in the Assign dict, not an
element or node id — the manual says so explicitly for each ("Assign의
키(ID)는 시공단계 번호입니다") — and both worked examples use made-up
group/function names ("BG_SURF", "CC_Standard", "AT_Summer" for
HECB; "BG_BASE" for HSPT), same mistake class as /db/BCCT's
"BG1"/"BG2". New hecb_seed creates real /db/BNGR, /db/CCFC, and
/db/ETFC records up front instead.
HSPT(Prescribed Temperature): passes clean on both products, first try.confirmed=True.HECB(Element Convection Boundary): fails on both products with"[Error] The element no. 1 is an element type in which Element Convection Boundary cannot be entered."— the exact same failure shape as/db/HAHSfrom batch 10.ITEMS[0].ID(documented as a plain serial number) lines up numerically with "element no. 1" in the error, so it's plausibly read as an element reference server-side despite the manual's description. GivenHAHShit the identical wall and heat-of-hydration boundary conditions are normally applied to mass-concreteSOLIDelements (piers, footings), this reads as the same fixture scope gap — the base model only builds frame and plate elements, noSOLID— rather than a fresh defect. Left unconfirmed, not re-bisected past that point.
1 endpoint (HSPT) flipped to level: write; HECB stays level: read
with a dated note pointing at the HAHS precedent. docs/coverage.json
and ROADMAP.md updated; pytest (701) and ruff both clean.
Running total for the write-coverage push (batches 1-11c): 70 endpoints at
level: write (69 from batches 1-10, +1 HSPT here — LLAN/MVHL/
MVHC/MVLD were already write before batch 11b, so widening them to
Gen doesn't add to this count); 26 with a dated genuinely-unresolved or
scope-limited finding (the 25 through batch 11a plus HECB), plus the one
confirmed live crash (THNL PUT on Gen NX, MAPI-2468). CSCS (composite
section for construction stage) is the one endpoint left in this family,
deferred again — it references a stage-specific section change, a bigger
fixture than this batch's scope.
2026-08-17 — batch 12: db.bridge in full, clean sweep¶
Picked db.bridge next (GSBG/GCMB/CAMB/ULFC, 4 endpoints) — fully
self-contained, no fiber/hinge dependency chain, and small enough to do in
one pass. Three of the four (GSBG/GCMB/CAMB) are Civil-only per
db/bridge.py's own docstring; ULFC answers on Gen too.
One seed: a real /db/GRUP structure group (SG12_SEED, plus a second
SG12_SEED_2 so CAMB's update step has something to switch to) —
GCMB's GRUP_NAME and CAMB's three group-name fields all reference
it by name, GSBG's BODY_ELEM_GRUP_K by its numeric key (12). The
manual's own worked examples use made-up group names for both ("CS_0"
.. "CS_18" for GCMB, "FSM"/"PSC-BN"/"Key-SegK1~K5" for CAMB) —
same lesson as /db/BCCT, used real ones from the start.
First Civil run: GCMB/CAMB/GSBG passed clean immediately. ULFC
failed with "Wrong Field" — the fixture had omitted POINT since the
manual only documents it as "required if TYPE=BEAM," but a direct check
confirmed it's actually required unconditionally: a TYPE="REAC"
payload without it is rejected, POINT=0 clears it. Corrected the
fixture and src/midas_nx/db/bridge.py's POINT field comment to
document this. Re-ran Civil clean (14/14), then Gen (11/11, ULFC only —
the other three are Civil-only by design, not attempted there).
All 4 endpoints flipped to level: write, all confirmed=True — the
first batch in this whole push where every endpoint passed with no
genuinely-unresolved finding left behind. docs/coverage.json and
ROADMAP.md updated; pytest (701) and ruff both clean.
Running total for the write-coverage push (batches 1-12): 74 endpoints at
level: write (70 through batch 11c, +4 here); 26 with a dated
genuinely-unresolved or scope-limited finding (unchanged this batch), plus
the one confirmed live crash (THNL PUT on Gen NX, MAPI-2468).
2026-08-24 — batch 13 (db.design non-rebar subset), Civil NX only¶
Resumed batch 13 (/db/DCON/DSTL/LENG/MEMB/DCTL/LTSR/MBTP/
WMAK) after the previous session ended blocked on both NX sessions being
disconnected. This session: Civil NX 2026 v2.2 (build 08/24/2026) was
open and connected; Gen NX stayed disconnected throughout, so this
batch only ever ran on Civil.
First Civil run: 3 of 8 failed. Triaged and fixed all three:
/db/DCON//db/DSTL(RC/Steel Design Code) — the manual's own worked-exampleDGNCODEvalues ("ACI318-19"/"ACI318M-19"/"ACI318-14"/"ACI318M-14"for DCON;"AISC(16th)-LRFD22"for DSTL) all answered"Wrong Field"/"[Error] Errors detected in Steel Design Control Data."— on both POST and PUT, and (for DSTL) with aSTEELmaterial present in the model, ruling out a model-state gap. Bisected a wider set ofDGNCODEvalues directly against the live server: for DCON, every non-KCI/Eurocode2/AASHTOcode tried ("KDS 24 14 21 : 2021"included) failed the same way; for DSTL, every code tried except"Eurocode3-2:05"and"AISC-ASD89"failed the same way (KDS/KBC/CSA/GB/BS/AS/IS/DIN/SIA/NBR/JGJ/AIJfamilies all rejected). Reads as a country-design-code license/module gate on this particular Civil NX license, not a request shape bug — switched the fixture toKCI-USD12→KCI-USD07(DCON) andEurocode3-2:05→AISC-ASD89(DSTL), both of which round-trip clean./db/MEMB(Design Member Assignment) —AELEM: [1, 2, 3]failed"No element among selected elements is designated as a member.(Not Same Member Type)". The shared base-model fixture's element 1 runs vertically (node 1→2, auto-classifiedCOLUMN) while elements 2-3 run horizontally (node 2→3→4,BEAM) — grouping a column with beams into oneAELEMtrips this check. Elements 2-3 alone shareBEAMand group fine; fixture changed toAELEM: [2, 3].
Re-ran Civil clean: 18/18 (10 core + 8 extras13). docs/coverage.json
updated for all 8 endpoints to level: write, products: ["civil"]
only — not ["gen", "civil"], since Gen was never actually run this
session; each entry's method says so explicitly. Case.confirmed
stays False in scripts/live_crud_check.py for all 8 until Gen NX
reconnects and runs the same tier — this batch is exactly the situation
the EIGV/BCCT correction (batch 11) warned about avoiding: don't infer a
second product's result from the first's. pytest (701) and ruff
both clean.
Running total for the write-coverage push (batches 1-13): 82 endpoints
at level: write on at least one product (74 through batch 12, +8
here, 8 of those Civil-only pending Gen); 26 with a dated
genuinely-unresolved or scope-limited finding (unchanged), plus the one
confirmed live crash (THNL PUT on Gen NX, MAPI-2468). Next session:
run --tier core,extras13 on Gen NX first — if it passes clean, flip
all 8 Case.confirmed=True and add "gen" to each coverage.json
entry's products; if any fail, split per-product like EIGV/BCCT rather
than guessing which fields need Gen-specific handling.
2026-08-24 (later) — OCHECK/MAPI-2429 re-repro'd on Civil NX v2.2, build 08/24/2026: still crashes¶
At the user's request, re-ran the crash reproduction for MAPI-2429
(perform_src_optimal_design, /TEMP/DESIGN/SRC/AIK-SRC2K/OCHECK) on
whatever Civil NX build happened to be open this session, to check
whether it's still live two builds after the last confirmation
(2026-08-13, build 08/12/2026).
Built the same dummy-model shape as 2026-08-13 on a fresh /doc/NEW
(confirmed blank first): Material.create (C24 concrete, KS01(RC)),
Section.create (600×600 DBUSER, SHAPE: "SB" — real,
non-SRC-eligible), two Nodes, one BEAM Element. All four succeeded.
Called perform_src_optimal_design with SECT_LIST: [{"SECT_NO": 1,
"SECT_DB": "USER"}], ANALYSIS_OPT.ANAL_TIME: 0,
OUTPUT.MODEL_UPDATE: False — the same conservative payload as every
prior repro.
Crashed again, same underlying signature but observed slightly
differently: the call itself timed out client-side (35s, no response),
and this time the immediate follow-up GET /db/NODE also timed out
(35s) rather than returning the fast 404 client does not exist seen
2026-08-13 — verify_connection() afterward showed status:
"disconnected". Same "session died mid-call" outcome, just a slower
symptom on this build. Recovered via the standard restart (dialog OK →
re-launch → New Project → close → reconnect with the same MAPI key);
reconnected cleanly with the same connectionID as before the crash.
Dummy model was disposable test data, nothing lost.
Conclusion: MAPI-2429 remains live on Civil NX v2.2, build
08/24/2026 — two builds after the last confirmation (08/12/2026),
still not build-dependent, still consistent with MIDASIT's "not a
defect, no fix timeline" stance from MAPI-2429's own closure.
docs/coverage.json's /TEMP/DESIGN/SRC/AIK-SRC2K/OCHECK entry updated
with today's repro and build; no Jira action needed since the ticket is
already closed on this exact finding. Not re-tested on Gen this
session.
2026-08-25 — checking MIDASIT's shipped fixes on Gen NX v2.1, build 08/20/2026: MAPI-2468 (THNL) and MAPI-2431 (CD-TABLE) both confirmed fixed¶
Followed up asking Jira status of the whole crash-family epic (MAPI-2427)
to see which tickets were closed with an actual verified fix vs. just
closed after MIDASIT shipped a patch we'd never independently retested.
Of the 6 crash tickets: MAPI-2378/NMAS and MAPI-2425/EDMP and
MAPI-2426/USLC already had our own confirmation comments on the
ticket; MAPI-2429/OCHECK is confirmed still broken (see above);
MAPI-2431/CD-TABLE and MAPI-2468/THNL had patches shipped
(2026-08-11 and 2026-08-17 respectively) but no retest from our side —
Gen NX happened to be open this session (v2.1, build 08/20/2026, newer
than both patches), so retested both.
MAPI-2468 (PUT /db/THNL killing Gen NX) — fixed. Raw repro first
(node + THFC_FORCE_SEED time-history function + THIS_SEED load case,
then POST/GET/PUT on /db/THNL with only SCALE_FACTOR changed):
the PUT that used to kill the session now returns in ~0.2s, session
stays healthy. MIDASIT's own comment (2026-08-17) explains the root
cause: the data layer deletes the old row when a time-history key
matches, and the API layer kept referencing it post-transaction,
dereferencing invalid memory. Then re-verified properly through the
harness: lifted scripts/live_crud_check.py's Case.products=("civil",)
restriction on the DynamicNodalLoad case and re-ran --tier
core,extras5 on Gen — /db/THNL now PASSes its full round trip
(create→read→update→read→delete→read), 17/19 in the tier (the 2
pre-existing unrelated failures, SPLC/THMS, are unchanged, documented
findings, not a regression). docs/coverage.json's /db/THNL entry and
the DynamicNodalLoad case's harness comment both updated; both
products now confirmed=True.
MAPI-2431 (Column/Brace/Beam Design Forces via
/DESIGN/RC/KDS-41-20-2022/TABLE, midas_nx.design.rc_kds.checks) —
fixed. This ticket's history was the messiest of the six: crashed
twice independently (2026-08-01, real apartment model + isolated empty
doc), MIDASIT couldn't reproduce it themselves and asked for the model,
re-crashed on a blank /doc/NEW retest 2026-08-07, then came back clean
on the same blank-doc shape 2026-08-11 — which the notes at the time
explicitly flagged as "not proof, could be intermittent, needs an
independent second re-test" given the call's history of not even being
monotonic with data complexity (crashed blank, clean on a 63-node real
model, on the same day). Today's retest — same blank-doc shape, Gen NX
v2.1 build 08/20/2026, a different and later build than the 08-11
patch — was the second consecutive clean pass: get_column_design_forces
_table(''), get_brace_design_forces_table(''), and
get_beam_design_forces_table('') all returned in <0.3s with {} and
{"message": ""}-shaped empty responses, session healthy throughout.
MIDASIT's 2026-08-11 patch comment names the actual fix: guard code
added for a Design API call made with no analysis run. Between the named
root cause and two consecutive clean passes on two different post-patch
builds, this clears the "needs an independent second re-test" bar.
docs/coverage.json's three /DESIGN/RC/KDS-41-20-2022/TABLE entries
(Column/Brace/Beam) and their docstrings in src/midas_nx/design/rc_kds/
checks.py updated.
Explicitly not covered by either fix: the sibling /post/TABLE code
path (midas_nx.post.design's get_column_design_forces_table,
get_brace_design_forces_table, get_beam_design_forces_table — a
different endpoint sharing only the TABLE_TYPE naming convention, per
the existing "independently-crashing siblings, not one shared root
cause" note) was not retested this session and stays flagged
crash-risk on Gen NX. Don't read today's fixes as clearing that endpoint
too.
Crash-family epic status after today: 5 of 6 confirmed fixed by us
(NMAS, EDMP, USLC, CD-TABLE via rc_kds.checks, THNL), 1 confirmed still
broken (OCHECK/MAPI-2429, MIDASIT's own "not a defect" stance), 0 left
unverified. MAPI-2431 and MAPI-2468 haven't had a confirmation
comment posted back to Jira yet — that needs the user's explicit
go-ahead per this project's standing Jira-consent rule before doing so.
2026-08-25 (later) — batch 14: the 12 Civil-only-by-design endpoints (5 db.moving_loads, 7 db.analysis_control Hyper-S/-M1), all confirmed on Civil NX v2.2, build 08/24/2026¶
User asked to continue the write-coverage push on Civil NX specifically
("civil nx 검증 진행해볼래?"). Picked the clearest Civil-only target: the
12 endpoints that are Civil-only by design rather than by an
undocumented Gen gap — 5 from db.moving_loads (CRGR/CJFG/DYLA/
DYFG/DYNF) and 7 Hyper-S (-M1) variants from
db.analysis_control (ACTL-M1/EIGV-M1/HHCT-M1/NLCT-M1/
STCT-M1/BCGD-M1/BCGA-M1). Hyper-S is a Civil NX-only solver, so
these were never reachable on Gen at all — unlike most of this
project's other Civil-only findings, which are just an undocumented gap
in an otherwise-shared endpoint.
First checked whether Hyper-S needs a model-level mode switch before
these endpoints respond: GET /db/STYP-M1 (Structure Type, Hyper-S)
answered its defaults on a completely fresh, non-Hyper-S document — no
switch needed, the -M1 endpoints are just always reachable on Civil.
Direct ad-hoc bisection (not yet through the harness) got 8/12 working
on the first attempt (CRGR/CJFG/DYLA/ACTL-M1/EIGV-M1/
HHCT-M1/STCT-M1/BCGD-M1); 4 failed and were triaged:
/db/DYFG— "Wrong Field" on every payload shape tried, including the manual's own verbatim worked examples, with/db/MVCD.CODEset toEUROCODE(the documented prerequisite). Bisected viaGET /info/db/DYFG(schema matched the manual exactly) and by varying the payload systematically: sending all six documented fields simultaneously, including the ones the manual marks conditionally required only for the otherINPUT_TYPE/OPT_REDUCE_EFFbranch, fixed it. Confirmed reproducible on a fresh document. Same defect class as/db/NMAS'srmX/rmY/rmZbug, just a clean rejection instead of a crash. The sibling/db/DYNFdoes not share this — its conditional requiredness works as documented; it only needed a real element id as theAssignkey (per the manual's own note that DYNF's key is an element id, not a serial number)./db/BCGA-M1— "Wrong Field" onBC_SELECTregardless of which manual-documented value was tried ("CONS","MCON", etc).GET /info/db/BCGA-M1revealed the live server's real enum is a completely different abbreviation scheme from the manual's own table —SSSF/ES/EW/PS/SP/PSS/GSS/SSS/EL/RL/GL/CGL/BER/BEO/PER/LCvs the manual'sSECF/ESSF/EWSF/PSSF/WSSF/CONS/NSPR/GSPR/SSPS/ELNK/RIGD/NLNK/CGLP/FRLS/OFFS/PRLS/MCON. Not a spelling-level typo like several earlier findings this project has documented — a real enum table substitution, most likely an editing artifact from a different, longer naming convention. Using the live values ("SP"/"LC") fixed it immediately./db/NLCT-M1— "Wrong Field" withLC_SCOPEset to a real load case name ("DL") andCONV_CRITERIAallOPT_USE: false. The manual's own worked example uses the literal keyword"ALL"forLC_SCOPE, not a load case name — switching to"ALL"and givingCONV_CRITERIA.DISPa realOPT_USE: true/VALUEfixed it./db/DYNF— see DYFG above; this one just needed a real element id, not a payload change.
With all 4 fixed, re-ran ad-hoc — 12/12 clean — then encoded the seeds
and cases properly into scripts/live_crud_check.py as a new
extras14 tier and ran it through the harness (the actual bar for
Case.confirmed=True, not an ad-hoc script): first attempt surfaced 2
more issues the ad-hoc script hadn't hit, both harness/fixture bugs
rather than SDK defects:
/db/DYLAneeds/db/MVCD.CODEin{KSCE-LSD15, AASHTO LRFD, PENDOT}— a different, mutually exclusive requirement from DYFG/DYNF'sEUROCODE. Since this harness runs all of a tier's seeds before any of its cases (no interleaving), a single seed can't satisfy both. Fixed by seedingKSCE-LSD15up front forDYLA, then adding a dedicated mid-list_MvcdSwitchcase (a localMovingLoadCodesubclass restricted toGET/PUTonly, to update the existing seeded record without re-POSTing over it orDELETEing it afterward) that flips the same singleton record toEUROCODEbeforeDYFG/DYNFrun./db/BCGA-M1'sBC_SELECTcomes back in a server-chosen order, not the order sent (["SP","LC","EL"]sent,["SP","EL","LC"]read back) — the case's probe now sorts both sides before comparing.
Re-ran: 23/23 clean (10 core + 13 extras14 — MVCD's own switch
case is a 13th row alongside the 12 real endpoints). docs/coverage.json
updated for all 12 endpoints (level: write, products: ["civil"],
Gen genuinely unreachable so no "pending" caveat needed here unlike
batch 13); src/midas_nx/db/moving_loads.py (RailwayDynamicFactorPayload)
and src/midas_nx/db/analysis_control.py
(AssignBoundaryCombinationHyperSPayload) docstrings corrected.
pytest (701) and ruff both clean.
Running total for the write-coverage push: 157 endpoints at level:
write on at least one product (145 through the 08-25 crash-family
session, +12 here).
2026-08-27 — sibling manual repo's 24-chapter "전수 재검증" pass: 3 live-evidence conflicts resolved, the rest surveyed but not yet applied¶
The sibling manual repo (E:\AI Study\MIDAS-API) moved from
fbd4f979... (this SDK's vendored_at_commit) to 05eb6c08... via a
"전수 재검증" (full re-verification) pass that re-checked all 27
chapters against MIDASIT's official pages — 24 chapters actually
changed. Far too large to reflect in one session; a general-purpose
agent surveyed all 24 diffs against the current SDK source and flagged
3 as directly contradicting something this SDK already documents as
independently live-verified. Per this project's standing rule, none of
the 3 were "corrected" from the manual's new text alone — each was
re-tested live first.
1. get_story_load_summary_table (post/pre_process.py) — SDK was
right, manual's new correction is wrong. The manual's 08-25 sync
(commit 05c0550) claimed the 2026-08-06 sync had confused this table
with its sibling Story Mass Summary Table, and the real params are just
TABLE_NAME/TABLE_TYPE(STORY_LOAD_SUMMARY_{dir})/EXPORT_PATH —
directly contradicting this SDK's own 2026-08-13 live confirmation
(TABLE_TYPE="STORY_LOAD_{dir}" plus unit/styles/components/
load_case_names, returning real per-story rows). Re-tested live on
Gen NX (v2.1, build 08/20/2026): TABLE_TYPE="STORY_LOAD_X" still
answers cleanly ({"message": ""} on a document with no story data,
same shape as the known-good sibling STORY_MASS_X); TABLE_TYPE=
"STORY_LOAD_SUMMARY_X" (every casing tried) consistently answers
"there was an error creating utbl" — an unrecognized-table-type
error. The manual's new correction is itself wrong; not applied.
2. get_story_properties (ope.py) — manual was right, SDK had a
genuine typo. Four historical 404s (2026-07-30 x3 Gen, 2026-07-31
Civil, 2026-08-01 Gen) were all attributed to "unexplained, possibly a
dead route." The manual's re-verification found the real URL is
/ope/STORYPROP (STORY+PROP), not /ope/STORPROP — the SDK had been
calling a URL with a missing letter the entire time. Re-tested live on
Gen NX: POST /ope/STORPROP still 404s; POST /ope/STORYPROP routes
through cleanly (200, "There is no valid story information." on a
document with no Story data — a domain error, not a routing error).
Also resolved a side puzzle: GET /info/ope/STORPROP's 404 (taken
earlier as routing-level confirmation the route doesn't exist) turns
out to be uninformative — GET /info/ope/STORY_IRR_PARAM 404s too,
for an endpoint independently confirmed working via POST, so /info/
ope/* apparently doesn't work for any /ope/* endpoint, working or
not. Fixed: get_story_properties() now posts to /ope/STORYPROP;
docs/coverage.json's /ope/STORPROP entry renamed and reconfirmed.
3. WallRebarItem.vSTORY_NAME (db/design.py, /db/REBW) — SDK
was right, manual's new correction is wrong. The manual's
re-verification claimed the field is vSTORY_KEY (Integer array), not
vSTORY_NAME (String array) — contradicting the 2026-07-29 rewrite,
which had confirmed the field three independent ways against a real
production Gen NX model (GET echo, /info/db/REBW schema, and a live
PUT round-trip). Re-checked GET /info/db/REBW live again today: the
server's own schema still names the field vSTORY_NAME, items.type:
"string" — exactly matching the existing TypedDict. The manual's new
claim is wrong on this field; not applied.
The other 21 changed chapters were surveyed (not deep-reviewed field
by field) and are NOT yet reflected in the SDK. Highlights worth
prioritizing next, none live-tested yet: /db/GSTP's 21-value spring
matrix is documented as upper-triangular when the manual's re-check
says it's diagonal-terms-first — the manual calls this "실무에 영향이
큰 정정" (high real-world impact; wrong DOF assignment if unfixed).
/db/NSPR's DIR enum and SK field are both wrong (STIFF/
FUNCTION don't exist as documented). /db/REBC's entire payload
shape is confused with a different endpoint. post/result_1.py has
two wrong TABLE_TYPE constants (BEAMFORCEBYMAX/BEAMFORCESIP
should be BEAMFORCEVBM/BEAMFORCESTP). 04_DB_Properties.md and
05_DB_Boundary.md carry the largest volume of under-documented
(missing, not wrong) fields — TDME's A/B vs KDS-2016's actual
iCTYPE/DENSITY requirement is probably the highest-value one there.
Full per-file breakdown is in this session's conversation, not
re-derived here — ask for it again if starting the next pass.
docs/coverage.json's vendored_at_commit stays at fbd4f979...,
not bumped to 05eb6c08... — only 3 of 24 changed chapters are
actually reflected; bumping now would falsely claim the rest are synced
too. python scripts/check_manual_drift.py will keep reporting
has_diff: true until the remaining 21 are addressed, which is
correct, not a bug. pytest (704) and ruff both clean after this
session's 3 fixes.
2026-08-27 (later) — working the 24-chapter drift survey's priority list: 5 more runtime-breaking bugs confirmed and fixed live on Gen NX¶
Continuing from the priority list the earlier survey left (GSTP, NSPR,
REBC, post/result_1.py's two TABLE_TYPE typos, and /db/TDME's
A/B vs KDS-2016 conflict) — Gen NX was open, so each item was
live-tested before applying any fix, per this project's standing rule.
/db/GSTP's 21-value matrix order — the manual's re-verification was
right, confirmed by direct GUI inspection. Posted a probe spring with
a unique value (11-31) at each of the 21 array indices, then had the
user open the General Spring Type dialog in Gen NX and read the 6x6
grid back. Every single cell matched the manual's new "diagonal terms
first, then off-diagonal row by row" order exactly — SDx/SDy/SDz/SRx/
SRy/SRz diagonal = indices 0-5, then row-1 off-diagonals at 6-10, row-2
at 11-14, row-3 at 15-17, row-4 at 18-19, row-5 at 20. The SDK's prior
"upper-triangular" claim (K11,K12,K13,...,K22,K23,...) put stiffness at
the wrong degrees of freedom for anyone who filled the array that way.
GeneralSpringTypePayload rewritten with the full index table. Note:
scripts/live_crud_check.py's own spring_types/GS_CRUD fixtures
were built under the old (wrong) assumption too — harmless in practice
since neither Case's probe function actually asserts SPRING array
values (GSTP's checks NAME, NSPR's checks SDR unrelated to GSTP), but
the physical spring those fixtures create doesn't mean what its
in-code comment implies. Not worth rebuilding the fixture data itself
since no assertion depends on it; the misleading comment on the LINEAR
NSPR case was fixed.
/db/NSPR's COMP/TENS/MULTI shape — manual right, SDK had a fully
fictional field. The old shape (DIR 1-4, DV, an SK array) was
confirmed live to answer "[Error] Point Spring value has(have) been
incorrectly entered."; SK doesn't exist as a field at all. The real
shape — STIFF (single number) for COMP/TENS, FUNCTION (an
/db/MLFC id) for MULTI, DIR 0-6 (six signed directions plus
Vector), DV only meaningful when DIR=6 — round-tripped cleanly,
confirmed separately for DIR=6+DV, DIR=0 with no DV, and
LINEAR's previously-undocumented Cr damping array. PointSpringItem
rewritten.
/db/REBC — manual right, SDK's whole payload was confused with a
different endpoint. The old shape (CREATE_SUB_SECTION/ELEMS/
HOOK_TYPE, a single-object MAIN_BAR, top-level DO) answered
"Wrong Field" on the first live attempt. The real shape (vMAIN_BAR
as an array of {NAME,NUM,ROW,D0,bUSE_CORNER,NAME_CORNER}, integer
HOOP_TYPE 1=Tied/2=Spiral, bSAME_SPACE_END_CEN,
NUM_BAR_BC_JOINT) round-tripped a full POST→GET→PUT→DELETE→GET cycle
— DELETE genuinely removed the record (confirmed via a follow-up GET
returning empty). Also not POST-only as previously documented —
the METHODS = frozenset({"POST"}) override was removed; full CRUD
confirmed live. ColumnRebarItem rewritten, ColumnMainBarSpec
renamed to ColumnMainBarItem to match the array-of-objects shape.
post/result_1.py's two TABLE_TYPE constants were unrecognized
values, not just misspelled labels. TABLE_TYPE_BEAM_FORCE_BY_MAX
(was "BEAMFORCEBYMAX") and TABLE_TYPE_BEAM_FORCE_STATIC_PRESTRESS
(was "BEAMFORCESIP") both answered "there was an error creating
utbl" (unrecognized table type) on Gen NX. The manual's corrected
values ("BEAMFORCEVBM", "BEAMFORCESTP") instead answer "Cannot
generate table data as there is no analysis result" — a materially
different error confirming the table type itself is now recognized;
not re-tested against a document with a real analysis run for
populated data, so coverage.json's level stays read.
/db/TDME's A/B vs KDS-2016 conflict — manual right, and it
explains an old open question. Live-confirmed: CODENAME="KDS-2016"
with A/B answers "[Error] Time Dependent Material(Comp. Strength)
input data contain errors."; the same material with iCTYPE/
DENSITY instead round-trips cleanly. CODENAME="Korean Standard"
(a separate, differently-named code) confirmed to work with A/B as
expected. This resolves a finding already on record from an earlier
session (KDS-2016 recognized but rejected with A/B, cause
unidentified at the time, this file's own 2026-07-2x sections) — the
missing fields were iCTYPE/DENSITY, not a naming problem.
TimeDependentMaterialStrengthPayload rewritten with a full
per-CODENAME field group table; only the KDS-2016/Korean
Standard/ACI groups were live-tested, the rest (Russian, the two
Japan variants, etc.) are transcribed from the manual's
re-verification and not independently confirmed.
docs/coverage.json updated for /db/GSTP//db/NSPR//db/REBC/
/db/TDME (all flipped or reconfirmed level: write) and the
post/result_1.py aggregate entry (route/type confirmed, level
stays read). Global write coverage: 158/399. Tests updated to match
(tests/db/test_design_setup.py's REBC tests, tests/post/
test_result_1.py's TABLE_TYPE assertions). pytest (704) and ruff
both clean. Remaining from the priority list, not yet done: the
04_DB_Properties.md/05_DB_Boundary.md under-documented (missing,
not wrong) fields flagged in the earlier survey — PlasticMaterialPayload's
DP/MA/DM sub-objects, InelasticMaterialKentParkParam's 4 missing
fields, SectionStiffnessItem's J-end block, SectionReinforcementPayload's
MBAR_ITEMS, FiberDivisionPayload's wrong FIBR_BASE_KEY type plus
missing fields, GroupDampingPayload's Rayleigh-damping branch,
TaperedGroupPayload's Y-axis POLY branch, SeismicDeviceIsolatorPayload's
SDIS_DEV_TYPE enum and nested shapes, LinearConstraintSlave's
COEFF/WEIGHT split, the three badly-incomplete seismic-device
classes, GeneralLinkPropertyPayload's missing fields, and
GeneralLinkHyperSPayload's outdated stub — lower severity (additive
gaps, not actively-wrong values that break a live call) so deferred
rather than blocking. Still 21 of the 24 changed manual chapters not
yet reflected at all; vendored_at_commit stays unbumped.
2026-08-27 (even later) — clearing most of the deferred properties/boundary gaps, plus 9 more chapters; 12/24 chapters now reflected¶
Continuation of the previous entry's deferred list, worked in three
parallel passes (Gen NX live throughout; Civil NX's session key answered
client does not exist/404 the whole time, so every Civil-only or
Hyper-S-only item below is manual-sourced/schema-confirmed only, not
round-tripped). All three passes ran until this Claude Code account hit
its monthly spend limit mid-session and were finished by hand afterward
— noted per item below as "agent pass" vs. "finished by hand".
04_DB_Properties.md (agent pass, completed in full):
- /db/EPMT PlasticMaterialPayload: added the entirely-missing DP
(Drucker-Prager → DRUCKER), MA (Masonry → MASONRY), DM (Concrete
Damage → CONCDMG) branches, and corrected HARDENING_COEF from
Optional to Required-when-OPT_HARDENING-defaults-to-0. Manual-sourced
(article id 35808376517913), not independently live-tested.
- /db/FIMP InelasticMaterialKentParkParam: added EC1_METHOD/EC1/
Z/STRENGTH_AFTER. Manual-sourced only (article id 35944335180569).
- /db/TSGR TaperedGroupPayload: added the Y-axis polynomial fields
(YEXP/YFROM/YDIST).
- /db/SECF SectionStiffnessItem: added the Tapered-section J-end block
(W_SF/IPART/bDiffIJ/etc.).
- /db/RPSC SectionReinforcementPayload: added the previously-missing
required MBAR_ITEMS (longitudinal reinforcement) plus its sibling
shear-reinforcement fields.
- /db/FIBR FiberDivisionBaseItem.FIBR_BASE_KEY: corrected from bool
to int — both the manual's JSON Schema and Request Example
("FIBR_BASE_KEY": 752) show an integer key, not a boolean. Also added
OPT_MONITORED_FIBER/MONITORED_FIBER. Manual-sourced only.
- /db/GRDP GroupDampingPayload: added the entire Element Mass &
Stiffness Proportional / Rayleigh-damping scheme (bExistElement + 17
fields, GROUP_DAMPING_ITEMS[], two priority fields) that was missing
outright — only the Strain Energy Proportional scheme was typed before.
Live-confirmed root cause of a standing failure: /db/GRDP had been
stuck at level: read since 2026-08-16 because a write attempt using
the (at-the-time-incomplete) manual's worked example answered "Wrong
Field"; retested 2026-08-27 on Gen NX with the full field set via a
throwaway /db/MATL fixture — POST/GET/DELETE round trip succeeded.
docs/coverage.json bumped to level: write (Gen only).
- /db/TDMT code table: 5 previously-undocumented CODE values added to
the docstring (INDIA_IRC_112_2020/AS_2017_AMD_2024/
AS_2018_AMD_2021/NEWZEALAND_2022/CHJTG_T_D65_2015) — purely
documentation, CODE was already untyped str.
05_DB_Boundary.md:
- (agent pass) /db/NLLP GeneralLinkPropertyPayload: added
DIST_RATIO_DY/DIST_RATIO_DZ/COUPLED_INPUT_METHOD, schema-confirmed
via GET /info/db/NLLP on Gen NX (types match). A live POST round trip
was attempted but every /db/NLLP create that session — including the
manual's own unmodified example — answered "Unknown Error" while an
unrelated /db/GSTP write succeeded moments earlier/later in the same
session; treated as a session-specific anomaly, not evidence against
the fields.
- (agent pass) /db/NLNK-M1 GeneralLinkHyperSPayload: rewritten from
a 3-field stub to the full /db/NLNK-equivalent shape
(REF_SYSTEM/INPUT_METHOD branching + ANGLE/POINT/VECTOR value arrays)
plus IEHP_NAME. Not live-verified — Hyper-S/Civil-only, Civil session
unavailable (GET /db/NLNK-M1 and GET /info/db/NLNK-M1 both answered
client does not exist).
- (agent pass, live-confirmed) /db/SDVI SeismicDeviceViscousDamperItem:
added the six EXFN_*/OPT_EXFN_CE fields (Exponential dashpot type).
Confirmed via a clean POST/GET/DELETE round trip on Gen NX
(DASHPOT_TYPE=2); the manual's own Request Example sends all 12
fields regardless of DASHPOT_TYPE and the server didn't reject the
Exponential-only fields under Linear/Bilinear in ad-hoc testing either,
so the SDK now sends the full set unconditionally.
- (agent pass, live-confirmed) /db/SDVE SeismicDeviceViscoelasticDamperPayload:
rewritten from a 3-field stub (COMMON/MATERIAL_TYPE/SHEAR_AREA) to
17 fields — the manual's Specifications table only documents those same
3, but its own Request Example sends 14 more, confirmed real via a
round trip.
- (agent pass, partially live-confirmed) /db/SDST
SeismicDeviceSteelDamperPayload: rewritten. The manual's official
Specifications table lists MATERIAL_TYPE/MULTIPL — fields that
actually belong to the sibling SDVE page, apparently cross-contaminated
in the vendor's source docs. GET /info/db/SDST on Gen NX confirms no
such properties exist server-side; it lists exactly K0/P1/ALPHA1/
KB plus 4 hysteresis-model sub-objects (BL2/LY2/LY3/IK2).
K0/P1/ALPHA1/KB+BL2 confirmed via a live round trip; LY2/
LY3/IK2 are schema-confirmed only.
- (finished by hand, live-confirmed) /db/SDHY
SeismicDeviceHystereticIsolatorPayload: added P1/P2/ALPHA1/
ALPHA2/BETA/Phi/LAMBDA (previously only COMMON/
SDHY_HYS_MODEL/MSS/K0 were typed). Root-caused a standing
level: read failure: /db/SDHY had been stuck since 2026-08-16
because the write attempt (using the then-incomplete manual example)
answered "Wrong Field"; retested with the full field set — clean
POST/GET/DELETE round trip on Gen NX. docs/coverage.json bumped to
level: write (Gen only). The manual's own table also lists a
MULTIPL field absent from its JSON Schema/Request Example — left out,
same cross-contamination pattern as SDST/SDVE.
- (finished by hand, partially live-confirmed) /db/SDIS
SeismicDeviceIsolatorPayload: rewritten from 3 loose Any fields to
proper LRB/NRB/SB sub-TypedDicts, correcting five errors the
manual repo's own 2026-08-25 re-verification found in its prior text:
(1) SDIS_DEV_TYPE's 3rd value is "SLD", not "SB" ("SB" is only
the data object's key); (2) LRB's OPT_CONS_NONL/BETA/ALPHA/
SIGMA_V nest inside a DX sub-object, not siblings of KE/AR/TR;
(3) LRB has two distinct stiffness fields, KE and K0 — K0 was
missing; (4) NRB has AR/TR/KH/DX, not just KH; (5) SB was
missing QD(Index)/Pi_VALUE. Root-caused part of the same standing
level: read failure as SDHY/GRDP: retested on Gen NX — the SLD
variant round-tripped cleanly (POST/GET/DELETE), confirming the fix;
docs/coverage.json bumped to level: write (Gen only) on the
strength of that. The LRB variant still answers "Wrong Field" even
with the corrected shape, but GET /info/db/SDIS independently
confirms the corrected LRB nesting matches the live schema exactly —
per this project's established pattern that "Wrong Field" usually
means an unrecognized value rather than a wrong shape, this is
suspected to be SDIS_HYS_MODEL="BiLinear" not being a recognized
literal, not a structural defect; left unresolved, flagged in the
docstring. NRB untested either way.
- (finished by hand, live-confirmed) /db/MCON LinearConstraintItem
/ SLAVES[]: split into LinearConstraintSlaveExplicit
(NODE_KEY+COEFF+DOF, when TYPE="EX") and
LinearConstraintSlaveWeighted (NODE_KEY+WEIGHT, when TYPE="WD")
— the old single LinearConstraintSlave TypedDict only had
NODE_KEY+COEFF and was silently wrong for TYPE="WD" (no WEIGHT
field existed at all) and incomplete for TYPE="EX" (missing DOF).
Live-confirmed via two separate POST/GET/DELETE round trips on Gen NX
(one per TYPE) using the manual's own worked example values.
Nine smaller chapters (agent pass, all completed):
- 02_DB_Project_Structure.md: /db/STYP gained default-value
documentation for 5 booleans + SMASS (manual-sourced, not
live-tested — /db/STYP is new-file-only data, can't be probed without
/doc/NEW against a session that might hold real work). /db/NPLN:
corrected TOL (default 0, was undocumented) and COORD (plain
Optional default 0, was wrongly marked conditionally-Required) — both
live-confirmed on Gen NX via a POST omitting both fields, GET
reading back the defaults, then deleting the probe record.
- 03_DB_Node_Element.md: SkewPayload.iMETHOD defaults to 1 (Angle)
when omitted — live-confirmed on Gen NX via a probe-node round trip.
- 09_DB_Dynamic_Loads.md: HyperSAnalysisCase.ANAL_METHOD gained a 3rd
value (2=Static), manual-sourced only (THIS-M1 is Hyper-S/Civil-only,
session unavailable).
- 10_DB_Construction_Stage.md: /db/CSCS
CompositeSectionPartInfo.WAREA (self-weight stiffness scale factor —
the manual's table jumps IZZ→IW but the schema/examples all show WAREA
between them) and OPT_UPDATE_ALL_H added; manual-sourced only.
- 11_DB_Settlement_Misc_Loads.md: /db/WVLD WaveLoadPayload.CREST/
UNIT corrected from an unsourced guess ("MAX"/"MANUAL") to the
only values the manual's own Request Example actually shows
("MXM"/"PHASE") — flagged as example-confirmed, not an exhaustive
enum, since neither version of the manual's table lists literal values
for these fields at all. GRID_X/GRID_Z comments clarified. Not
live-tested — /db/WVLD is Civil-only, session unavailable.
- 12_DB_Analysis_Control.md: /db/STCT iBSC relabeled from "Bi-Section
Control" to "Beam Section Property Option" (Constant=0/Change with
Tendon=1) — a different concept entirely; the old label described a
concept actually covered by the unrelated BSSTEP/ADSTEP fields.
/db/STCT-M1: ANAL_TYPE.iINC_NLA gained a 4th value (Geometric+
Material Nonlinear=3) and a new bIEMF field; CREEP_SHRINKAGE.TYPE
corrected from "SHRINK" to "SHRINKAGE" (STCT-M1 differs from legacy
STCT's spelling); top-level gained iBSC (default 1, deliberately
different from legacy STCT's default 0), FRAME_OUTPUT, bSAVE_OCS,
NONL_CONTROL. All Hyper-S/Civil-only, manual-sourced only (session
unavailable).
- 13_DB_Load_Combinations.md: investigated the manual's 2026-08-26 claim
that a phantom NO field should be dropped from all six LCOM-*
endpoints — live-tested and found the manual wrong: POST/GET on
/db/LCOM-GEN (Gen NX, 2026-08-27) confirms the response's NO field
is real and server-populated, not a client-side artifact. No SDK change
made; docs/coverage.json's LCOM-* entries annotated with this
contradiction so a future manual sync doesn't silently "fix" it away.
- 14_DB_Pushover.md: /db/POGD-M1 GEO_NONL_TYPE enum order corrected
— this file had it as None=0/P-Delta=1/Large Displacements=2 (following
a JSON Schema description's word order that turns out to contradict its
own Specifications table), while db/dynamic_loads.py's two
same-concept fields already had the table's order (None=0/Large
Displacement=1/P-Delta=2); reconciled to match those two — this file
was the inconsistent one. /db/PHGE AssignPushoverHingePropertiesPayload.TYPE
gained the 4th documented value, "G-LINK" (General Link), previously
omitted by an unbounded "e.g." phrasing.
Still not started (ran out of session budget): 15_OPE.md,
16_VIEW.md, 19_/20_POST_AnalysisResult...md, 21_POST_StoryTables.md
— none of ope.py/view.py/post/*.py were touched this pass. Combined
with the 3 conflicts + 5 priority items from the previous entry, 12 of
the 24 changed chapters are now reflected; 12 remain, all previously
surveyed (see the prior entry's punch list for 15/16/19-20/21's
specific items). vendored_at_commit stays unbumped
(fbd4f9796824b8967ea748f3bcd0d329fe39fb55). pytest (706), ruff, and
mypy all clean after this pass.
2026-08-27 (yet later) — the last 4 chapters: 15_OPE, 16_VIEW, 19-20_POST result tables, 21_POST story tables; all 24 chapters now reflected¶
Finished by hand (no background agents this pass — still rate-limited). All live checks on Gen NX; Civil NX remained unreachable all session.
15_OPE.md/ope/STORY_PARAMStoryCheckParameterArgument.COUNTRY_CODE: corrected"NTCS2020"→"NTC2020"(no S) — the manual's 2026-08-26 re-verification (article id49514705474457) found this endpoint's own Specifications table uses the no-S spelling, distinct from the siblingStoryIrregularityCheckParameterArgument(§11) which genuinely does use"NTCS2020"/"NTCS2023"(with S) — the manual explicitly flags the two endpoints as using different literals for the same code. Table-sourced only, not live-tested (needs a real story model).15_OPE.md/ope/MEMBMemberAssignmentArgument.ELEM_LIST: the manual's 2026-08-26 re-verification claimed the real key is"AELEM"(reasoning from the worked examples and the response body, which does useAELEM). Live-tested on Gen NX and found the manual's claim backwards: with real elements in the model, a request using"ELEM_LIST"succeeded (and its response echoed"AELEM", matching the manual's response example — that's where the confusion came from); the identical request using"AELEM"failed with"There is no valid element information."— the server didn't recognize it as a request field. No SDK change;ELEM_LISTwas already correct. Second example this session (after13_DB_Load_Combinations.md'sNOfield) of a manual "correction" that doesn't survive a live test — see the Caveat section's underlying point, restated inreference_midas_api_manual.md.15_OPE.md/ope/AUTOMESHAutoMesher.METHOD/TYPE(andAutoMeshProperty.ELEMENT_TYPE): the manual's 2026-08-26 re-verification makes the same "table says spaced, example says stripped, trust the example" argument that turned out backwards forStoryIrregularityCheckParameterArgumentearlier this session (see the 2026-08-27-first entry above). Attempted to settle it live on Gen NX; inconclusive — a POST using only single-word values for these three fields (so it didn't actually exercise the disputed spacing) failed with a generic"MIDAS GEN NX second query is wrong"unrelated to spelling. Not pursued further. Left unchanged at the table's spaced form, explicitly not applying the manual's unverified claim — flagged in the docstring as needing a real multi-word-value round trip to resolve either way.16_VIEW.md/view/ACTIVEActiveArgument: addedIDENTITY_TYPE="STORY"and its companionSTORY_ACTIVEfield ("FLOOR"/"ABOVE"/"BELOW"/"BOTH") — the manual's 2026-08-26 re-verification (article id35523395368985) found this mode was added to the Specifications table/Request Example without a matching JSON Schema update. Live-confirmed on Gen NX: both a plain{"ACTIVE_MODE": "All"}and{"ACTIVE_MODE": "Identity", "IDENTITY_TYPE": "STORY", "IDENTITY_LIST": ["1F"], "STORY_ACTIVE": "FLOOR"}(against a document with no story data defined) answered"... command complete".19-20_POST_AnalysisResult_*.mdpost/base.pyget_table(): addedaverage_nodal_result/node_flagkwargs (→AVERAGE_NODAL_RESULTboolean,NODE_FLAG{CENTER, NODES}object). These apply to a named subset of ch20's 39 plate/plane-stress-and-strain/axisymmetric tables (not universal, and not in the ch19/ch20 common-parameters table) — the manual's 2026-08-26 re-verification found both fields missing from every affected section's own docs, not previously called out as table-scoped at all. Live-confirmed accepted (not rejected) on Gen NX viaPLATESTRESSL: with both fields set, the call still fails on a fresh document, but with the same "no analysis result" error as any ordinary call to that table type — not a shape-rejection error.19_POST_AnalysisResult_1.mdpost/result_1.pyTABLE_TYPE_BEAM_STRESS_BY_MAX = "BEAMSTRESSVBM": added — missing entirely before (the siblingTABLE_TYPE_BEAM_FORCE_BY_MAXalready existed; this max-value-basis variant of Beam Stress did not). Live- confirmed recognized on Gen NX (same "no analysis result yet" signal as above, not "unrecognized table type"). ItsITEM_TO_DISPLAYfilter parameter is not exposed byget_beam_stress_table()— noted in both places, not implemented (no existing kwarg pattern fits a single-table extra field cleanly; deferred rather than bolted on).21_POST_StoryTables.mdpost/story.pyStiffnessCalculationMethod: corrected both fields' documented default from the first enum value ("Drift at the Center of Mass"/"1 / Story Drift Ratio") to what the manual's own table (re-checked against article id49513107644057) actually says: the literal string"System"— a sentinel meaning "use the document's current calculation setting," not one of the listed enum values. Comment-only (TypedDicts here are documentation, not runtime-enforced); not live-tested.
All 24 changed manual chapters are now reflected. vendored_at_commit
bumped to 05eb6c08d1af5d61db517d63eb274f7038c80caa;
scripts/check_manual_drift.py --manual-api-repo "E:\AI Study\MIDAS-API"
now reports {"has_diff": false, "commit":
"05eb6c08d1af5d61db517d63eb274f7038c80caa"}. pytest (706), ruff, and
mypy all clean.
2026-08-27 (final) — closing the Civil-only gaps this drift work left unverified, now that a working Civil NX key is available¶
The user provided a fresh Civil NX MAPI key after the above; the
previously-stored one had gone stale (verify_connection reported
status: "disconnected", and a plain GET /db/NODE 404'd with client
does not exist") even though it decoded to the same session id — the
underlying product just hadn't been reconnected yet. Once reconnected,
went back through every item this drift pass had left as "Civil-only,
session unavailable" and closed as many as the model state allowed:
/db/WVLD(misc_loads.py): bisected the manual's full worked example down to a bare{"NAME": "WV1"}payload — even that minimal form still answers the identical"Wrong Field"first seen 2026-08-16. Confirms the standing failure is unrelated to theCREST/UNITvalue correction specifically; the entire write path is blocked (suspected licensed offshore/marine module gate, per the existing coverage.json note).CREST/UNITremain unverified by a live round trip./db/NLLP(boundary.pyGeneralLinkPropertyPayload): reconfirmed the manual's own unmodified example still answers"Unknown Error"on Civil NX too (previously only confirmed on Gen) — this is a genuine standing cross-product failure, not the "session-specific anomaly" this session had speculated for the Gen-only attempt. Docstring corrected. The newDIST_RATIO_DY/DIST_RATIO_DZ/COUPLED_INPUT_METHODfields stay schema-confirmed only (GET /info/db/NLLP)./db/NLNK-M1(boundary.pyGeneralLinkHyperSPayload): schema fully confirmed viaGET /info/db/NLNK-M1on Civil NX — exactly the 10 fields this SDK now types, confirmingIEHP_NAMEreally is absent server-side. A live POST attempt (two real nodes,REF_SYSTEM=0) answered"Unknown Error", almost certainly becausePROP_NAMEhad no real/db/NLLPproperty to reference (see above) — this endpoint's own write path was never actually exercised.THIS-M1(dynamic_loads.pyHyperSAnalysisCase.ANAL_METHOD): schema-confirmed viaGET /info/db/THIS-M1on Civil NX — the field's own description literally reads "Analysis Method (Modal:0, Direct:1, Static:2)", independently corroborating the manual's addition ofStatic=2. Not round-tripped (needs a fullDAMPING/NONL_CTRL_PARAMsetup not built this session).STCT-M1(analysis_control.py, three classes): the most fully closed of the five. A plainPOST+GETround trip on Civil NX confirmediBSC/FRAME_OUTPUT/bSAVE_OCS/NONL_CONTROLare all real (server auto-assignediBSC: 1, matching the documented STCT-M1-only default, plus a fully-populatedNONL_CONTROLshape now recorded in the docstring for whoever next wants to type it out instead ofAny).TIME_DEP_CONTROL.CREEP_SHRINKAGE.TYPE="SHRINKAGE"round-tripped explicitly (and a separate creation that omittedTYPEdefaulted to"BOTH", confirming that value too).iINC_NLA's new3value andbIEMFare schema-confirmed only (GET /info/db/STCT-M1's own field descriptions list both) — a livePUTattempt to set them failed with"Wrong Field", but so did aPUTusing an already-documented known-good value pair (iINC_NLA=1/iNLA_TYPE=1) on the same record, so this object is write-once in practice and the rejection isn't evidence against the new values specifically.
None of these needed an SDK behavior change — all were either
reconfirmations of already-documented standing failures (WVLD, NLLP) or
upgrades from "manual-sourced only" to "schema-confirmed"/"live-confirmed"
evidence for fields already added (NLNK-M1, THIS-M1, STCT-M1). pytest
(706), ruff, and mypy all clean; Civil NX scratch document confirmed
empty after cleanup.
2026-08-27 (final, really) — pushing STCT-M1/THIS-M1/NLNK-M1 past schema-only into real round trips¶
The user asked to actually try live-verifying the three items the previous entry left at "schema-confirmed only" rather than settle for that. Two came all the way through; the third stayed genuinely blocked.
STCT-M1iINC_NLA=3/bIEMF— fully closed. The previous entry's "write-once, PUT rejects everything" read was a red herring: the block was PUT specifically, not these values. Creating a fresh record at POST time with{"iINC_NLA": 3, "iNLA_TYPE": 1}, and separately{"iINC_NLA": 1, "iNLA_TYPE": 0, "bIEMF": true}, both round-tripped exactly through GET on Civil NX.docs/coverage.json's/db/STCT-M1entry updated with this evidence (level was alreadywritefrom an earlier batch).THIS-M1ANAL_METHOD=2(Static) — fully closed, and expanded further than asked. No worked JSON example exists for THIS-M1's Static case in the manual (only a parameter table) — legacy/db/THIShas its own Static example under a completely different key convention (COMMON.iAMETHOD/iISTEP/...) that doesn't apply here and would have been a trap to copy from directly. Built a fresh payload from the §7-2 parameter table instead:ANAL_TYPE=1,ANAL_METHOD=2,INC_STEP=10,INC_CTRL={"INC_METHOD":0,"SF":1}, deliberately omittingENDTIME/TIME_INC/DAMPING(documented as required by this SDK's existing TypedDict, but the manual's own table scopes them to Modal/Direct-Integration only). It round-tripped cleanly on Civil NX — POST, GET (server auto-filled a completeNONL_CTRL_PARAMincluding a nestedBOUNDARY_NL_ANALeven though neither was sent), DELETE. This also surfaced thatGEOM_NL_TYPE/INC_STEP/SUBSEQ/INC_CTRL/TIME_PARAMwere missing fromTimeHistoryLoadCaseHyperSPayloadentirely (not just theANAL_METHODenum value the manual flagged) — added, with a note thatENDTIME/TIME_INC/DAMPING's "required" marking is really conditional onANAL_METHODand this TypedDict doesn't branch on it (a known imprecision, not fixed this pass).docs/coverage.json's/db/THIS-M1bumped fromreadtowrite.NLNK-M1— stayed blocked, confirmed genuinely unblockable today. Bisected/db/NLLPdown to a single{"PROPERTY_NAME": "..."}field across four different(APPLICATION_TYPE, APPLICATION_TYPE_D)combinations — every one answers the identical"Unknown Error", regardless of content./db/NLLPwrites are unconditionally broken on this account/session, not something a cleverer payload works around. This also isn't new: the legacyGeneralLinkPayload's (/db/NLNK) own docstring already recorded on 2026-08-16 that its write test was scaffolded but never run for this exact reason.NLNK-M1's docstring updated to cite both findings so the next person doesn't re-attempt the same dead end.
pytest (706), ruff, and mypy clean; Civil NX scratch document
confirmed empty after cleanup.
2026-08-27 (post-mortem) — pre-Jira due diligence: cross-checking the 4 "manual is wrong" findings against MIDASIT's live official pages, plus a dual-product re-test¶
Before filing anything against MIDASIT, went back to each of the 4 findings
above and fetched the actual live Zendesk article directly (per this
project's own established rule — see the vendor-report boundary note: an
internal vendored-repo citation is not the same as the actual published
text, and 4 of 7 claims in an earlier vendor-report draft turned out to be
citing the vendored copy's own transcription errors, not MIDASIT's real
pages). Used https://support.midasuser.com/api/v2/help_center/en-us/
articles/<id>.json (the HTML page 403s WebFetch); found article ids via
the sibling manual repo's own citations where present, and via
.../help_center/articles/search.json?query=...&locale=en-us where not.
Then re-ran every live test on both Gen NX and Civil NX (not just
whichever product happened to be handy when each was first found).
All 4 survive intact — official docs corroborate every one, sometimes adding a plausible explanation for how the sibling manual repo's re-verification went wrong:
- Story Load Summary Table (
TABLE_TYPE). Official article id49514148775705("Story Load Summary", GEN NX),updated_at2026-08-05 — its own worked JSON example literally sends"TABLE_TYPE": "STORY_LOAD_SUMMARY_X". Re-tested live just now: Gen NX still answers"there was an error creating utbl"(unrecognized) for that exact literal, and still accepts the undocumented"STORY_LOAD_X"cleanly. Civil NX rejects both identically (this table type is Gen-only, already established — not informative either way there). This is now the most interesting of the 4: it's not that the sibling manual repo mis-transcribed anything — they quoted MIDASIT's real page accurately — it's that MIDASIT's own published example doesn't match their own live server. Worth flagging to MIDASIT as exactly that (a docs/API mismatch on their end), not as a transcription error. /db/REBW'svSTORY_NAME. Official article id49514033006745("Modify Wall Rebar Data") turned out to describe a third, older schema entirely (VERTICAL_REBAR/HORIZONTAL_REBAR/CREATE_SUB_WALL_ID/STORY:{FROM,TO}) — neither this SDK'svSTORY_NAMEnor the sibling repo's claimedvSTORY_KEYappear anywhere in it, so that article is itself stale relative to both. The decisive check was a freshGET /info/db/REBWon Gen NX just now: the live schema names the fieldvSTORY_NAME(array of strings) — matching this SDK exactly — but its owndescriptionreads "Story Key List", which is almost certainly why the sibling repo's re-verification concluded the field itself must be namedvSTORY_KEY. Civil NX 404s on this endpoint entirely, already documented as Gen-only (GEN_ONLY, confirmed twice 2026-07-29) — expected, not a new data point./db/LCOM-*'sNOfield. Official article id35990806887065("Load Combinations - General", CIVIL NX+API) documentsNOin all three places the sibling repo's re-verification claimed it was absent from: the JSON Schema ("NO": {"description": "CombinationNumber"}), the Specifications table (Combination Number | "NO" | Integer | - | Read Only), and both request/response examples. Re-tested live just now on both products (the original test was Gen-only): a freshPOST /db/LCOM-GENthat never sendsNOgets it back onGETas"NO": 1on Gen NX and Civil NX identically./ope/MEMB'sELEM_LIST. Official article id49514964272665("Member Assignment", GEN NX) — Specifications table lists"ELEM_LIST"("Element List", Required), and the request example sends"ELEM_LIST": [640, 692]; only the response example uses"AELEM". This confirms exactly the mix-up already suspected: the sibling repo's re-verification cited the response'sAELEMkey as if it were the request field. Re-tested live just now on both products:ELEM_LISTsucceeds (assigns the member) andAELEMis rejected as "no valid element information" on Gen NX and Civil NX identically.
Re-verified 2026-09-06 after the sibling manual repo asked for a
re-check, claiming the article's request example carries
"AELEM": [1, 2] and that [640, 692] was our own example value.
Re-fetched the same article (updated_at 2026-07-30T05:16:25Z, the same
revision as 8/27) and the claim does not hold: the Input JSON example
sends "ELEM_LIST": [640, 692], the Output example returns
"AELEM": [640, 692], and the Specifications table row 3 is
"ELEM_LIST" / Array / Required(*). Whole-body counts: ELEM_LIST 2
(example + table), AELEM 1 (response only). The table and the request
example agree; only the response differs, which the article states
plainly. AELEM belongs to the neighbouring /db/MEMB (Design Member
Assignment, ch24), an "Assign"-wrapped id-keyed record - an easy pair
to confuse, and both are implemented here with their own key.
Two things this re-check did produce, and both are on us:
- The official Specifications table row 2 spells the key
"SELETION_TYPE", missing a C, while both request examples and the live server useSELECTION_TYPE. Our vendored copy normalised it, so nobody had seen it. Recorded as MD-51. - The 2026-08-27 test's own record is thinner than it reads. The
AELEMrejection's HTTP status and full response body were never written down - only the message string - the two-keys-at-once case was never tried, and no build was recorded for that session;docs/coverage.json's/ope/MEMBentry still describes only the 2026-07-30ASSIGN_TYPE=AUTO/SELECTION_TYPE=ALLprobe and is stilllevel: read. There is no case for it inlive_crud_check.pyeither, so it cannot be re-run mechanically. Answering the rest takes a new live session. Reply drafted indocs/ope_memb_elem_list_response.md(git history,fa1332b).
No SDK or docs changes needed — all 4 already match the SDK's current
code; this pass only strengthens the evidence trail before any of them
go to Jira. Test fixtures (nodes/elements/STLD/LCOM-GEN records) created
on both products during this pass were all cleaned up. pytest (706),
ruff, mypy unaffected (no source changed this entry).
2026-08-27 (yet again) — the sibling manual repo reverted its own REBB/REBC/REBW re-verification, and got 2 of 3 wrong¶
While the above was in progress, the user reported the manual repo had
been updated again: commit af21cd7 ("24장 REBB/REBC/REBW 오정정 되돌림")
reverts its own 8/26 re-verification for all three endpoints, saying
that pass had confused them with a different endpoint's schema and
introduced fictional fields (vMAIN_BAR/vSTORY_KEY/integer HOOP_TYPE
etc.). Checked each of the three independently — live schema pulls, and
for REBC a live POST comparison — rather than trusting the revert at
face value, same as every other manual claim this session:
/db/REBC— the revert is right that 8/26 was wrong, but the revert's own replacement is also wrong. Fetched the official Zendesk article directly (id49513980544793, "Modify Column Rebar Data") — it documents a single-objectMAIN_BAR(NAME/NUM/ROW/USE_CORNER),DO, andActive Methods: POSTonly, matching exactly what the revert restored. Live-tested both shapes on Gen NX: the official/reverted single-object shape answers"Wrong Field"(rejected outright); this SDK's existing array-basedvMAIN_BARshape answers"Column Rebars has been entered in the section no. 1, which has not been specified"— a domain error, meaning the shape itself was accepted. A freshGET /info/db/REBCindependently confirms the array shape field-for-field, plus one field this SDK didn't have yet:HOOK_TYPE(added).GET /db/REBCalso answers cleanly, contradicting "POST only." The official MIDASIT article is wrong for this endpoint, not just the vendored copy — this is now the second confirmed case of that this session (the first was Story Load Summary Table, a docs/example mismatch rather than a wrong field name)./db/REBW— unaffected. Re-pulled the completeGET /info/db/REBWschema (every field, not just the previously-checkedvSTORY_NAME) — matches this SDK exactly. Nothing to change./db/REBB— the revert is wrong, and so is the SDK, in different ways. The revert restored a{LAYER1, LAYER2}object shape forMAIN_BAR_TOP/MAIN_BAR_BOT(matching the official article). A freshGET /info/db/REBBschema pull shows neither that nor exactly what this SDK had: the live server uses an array of{NAME, NUM}items (noLAYER1/LAYER2, but also noLAYERfield like this SDK's ownBeamMainBarLayerEntryhad inferred) — array position encodes the layer instead. The schema also shows noCREATE_SUB_SECTION/ELEMSat all, which this SDK had carried over from the REBC/REBR pattern without independent confirmation for REBB specifically. RemovedLAYER/CREATE_SUB_SECTION/ELEMSfromBeamMainBarLayerEntry/BeamRebarItem. Not round-tripped with a real POST: every attempt this session (with or without these fields) failed with a generic"Wrong Field"before reaching a usable target section — inconclusive on its own, so this fix rests on the schema pull alone, not a write confirmation. Interesting side note: this SDK's 2026-07-29 rewrite of the neighboringWallRebarItemdocstring says REBB was checked that same session and "uses the manual's long-form names correctly" — that was before 8/26 ever touched REBB, and refers to whatever the manual said at the time, not necessarily this array shape; not re-derivable now without the 2026-07-29 session's own notes.
Net effect: of the 3 endpoints the manual repo just reverted, 1 revert
was fully correct (REBW, moot — already fine), 1 revert corrected a real
problem but replaced it with a still-wrong shape whose real source is
now identified as a bug in MIDASIT's own official docs (REBC), and 1
revert introduced a new problem where none existed (REBB, un-reverted
here based on fresh schema evidence). pytest (706), ruff, mypy all
clean.
2026-08-27 (yet again, later) — REBB: pushed for a real write round trip, concluded the write path itself is broken¶
The user asked to actually live-verify REBB rather than settle for
schema evidence. Built a full real target from scratch on Gen NX
specifically for this (the earlier attempts this session had no real
section/element to write against): a concrete MATL (C24), a SECT
(SHAPE: "SB", the confirmed-working fixture pattern from
scripts/live_crud_check.py, not the shapes that had been failing all
session), a BEAM element using it, and a DCON design code — then
retried POST /db/REBB many different ways:
- This SDK's existing array-based shape (
vMAIN_BAR_TOP/BOT, flatSKIN_BAR_NAME/NUM,MAIN_BAR_DC_TOP/BOT) —"Wrong Field". - Fetched the official Zendesk article's raw HTML directly and found it
embeds a full JSON Schema block distinct from its own rendered
Specifications table — using
LAYER1/LAYER2objects,DT/DBcover names, and"additionalProperties": false. Tried that exact shape —"Wrong Field". - Mixed variants (
DT/DBwith the array shape,DT/DBwithLAYER1/LAYER2) —"Wrong Field". - A literally empty item (
{"ITEMS": [{}]}) against the real section —"Wrong Field", identically.
The empty-item result is the deciding one: if an empty object fails the
same way as a fully-specified one, the failure can't be about which
field names or nesting are used. Ruled out the last remaining
non-content explanations too — verify_connection() shows a clean
connected status (not a blocked-modal false positive) and an unrelated
sanity GET /db/NODE succeeds normally in the same session, so the
client/session itself is fine. Conclusion: /db/REBB's write path is
broken on this account/session regardless of payload, the same class of
finding as /db/NLLP and /db/WVLD (both already documented
elsewhere in this SDK as standing failures) — not a shape question this
pass can resolve by trying yet another field-name permutation.
One more thing worth keeping: the official article's own JSON Schema
block contradicts its own Request/Response Example, in the same
document. This SDK follows the example (which also matches the
independent GET /info/db/REBB schema pull from earlier this session) —
the closest thing to a tiebreaker available — but with the write path
itself down, this can't be confirmed with an actual round trip. All test
fixtures (MATL/SECT/ELEM/NODE/DCON) cleaned up after. pytest (706),
ruff, mypy all clean; no source changed this entry beyond the
coverage.json/docstring notes already made.
2026-08-30 — two documented method sets measured, both wrong (Civil NX 2026 v2.2)¶
Live, against an empty Civil NX document (0 nodes/elements/materials/sections, checked first). Every write was captured and restored or deleted; nothing was left behind.
Both findings came out of the same question — what does a documented method actually do — and they fail in opposite directions.
The two response shapes¶
The server distinguishes "this method is not served here" from "this method ran and rejected your data", and it does not use HTTP status to do it:
| response | meaning |
|---|---|
{"message": "error status"} |
the method is not served on that endpoint |
{"error": {...}} |
the method ran; the payload or the model was wrong |
| the table, echoed back | it worked |
The control that establishes this: POST /db/NODE then DELETE /db/NODE/1
returns {"NODE": {"1": {...}}} — a served DELETE echoes the record it
removed — and the following GET answers {"message": ""}. So error status
is a refusal, not an empty result, and neither is an {"error": ...} body.
Note also that {"message": "error status"} carries no error key, so
MidasResultError does not fire on it: another case for the "not every failure
carries an error key" rule.
/db/STYP-M1 does not serve DELETE, though the article says it does¶
The official article (56375311138201) tags GET, PUT, DELETE in its own
activeMethods field — read from the source HTML, not inferred — and
02_DB_Project_Structure.md transcribes that faithfully.
All three DELETE shapes answer {"message": "error status"} and change
nothing:
DELETE /db/STYP-M1/1 -> {"message": "error status"}
DELETE /db/STYP-M1 {"Assign": {"1": {}}} -> {"message": "error status"}
DELETE /db/STYP-M1 (no body) -> {"message": "error status"}
POST /db/STYP-M1 answers the same. The classic /db/STYP, which the manual
documents as GET/PUT-only, answers identically to all of them — so the two
endpoints behave the same way, and the chapter's general rule ("신규 파일 필수
데이터는 GET / PUT만 동작") holds for the Hyper-S variant too. The article is
the thing that is wrong.
Repeated later the same session with the dummy frame in place (3 nodes, 2
beams, a material, a section, a support and a load case) and with the record
first set to a deliberately non-default state — STYPE: "XZ", GRAV: 9.81,
TEMP: 15, both align flags true, MASS_TYPE: "CONSISTENT". A DELETE that
reset the record to defaults would have been visible against that; all three
shapes again answered error status and left every field untouched. So the
question the manual section leaves open — whether DELETE resets to defaults or
empties the record — has a third answer: it does neither, because it does
nothing. An empty document was not what made the first result come out that
way.
StructureTypeHyperS keeps _GET_PUT_ONLY. It was already right; it had been
right by analogy rather than measurement, which is why this was worth checking.
GET /info/db/STYP-M1 also confirms MASS_CONTROL is a nested object with
MASS_TYPE, MASS_POS, SELFWEIGHT, MASS_AXIS inside it — independent
confirmation that the extractor's 2-(N) flattening is a defect, not a
reading of the payload. And GET /db/STYP-M1 returns a record with no
MASS_AXIS at all while SELFWEIGHT is false, which is the documented
condition behaving as documented.
/db/POLC-M1 does serve POST, though the chapter says it does not¶
The reverse case, and the more expensive one. 14_DB_Pushover.md normalizes
this endpoint to GET/PUT/DELETE and warns in a ⚠️ callout that the official
article's POST, GET, PUT, DELETE row is an untrimmed copy of another
endpoint's template. Earlier the same day this SDK trimmed POST out of the
contract, Python and npm on the strength of that callout.
POST works:
POST /db/POLC-M1 {"Assign": {"1": {…LCNAME PROBE_POST…}}}
-> {"POLC-M1": {"1": {"LCNAME": "PROBE_POST", …}}}
GET /db/POLC-M1
-> {"POLC-M1": {"1": {"LCNAME": "PROBE_POST", …}}}
Two earlier attempts had failed — first {"error": {"message": "INCFUNC_NAME
not found."}}, then Load Case does not exist — identically under POST and
PUT. Those were the empty model missing the objects the payload referenced,
not the method being absent; seeding /db/STLD with a DEAD load case was
enough to make the same POST succeed. A failure that reproduces identically
under a method the manual accepts is evidence about the model, not the route.
PushoverLoadCaseHyperS gets its full method set back, and the contract
records the disagreement under manualDefects with describes: method rather
than silently matching the manual.
/db/STYP-M1 is the classic /db/STYP, not a separate record¶
Measured the same session, on a 3-node 2-beam frame with a material, a section, a fixed base and a self-weight case — an empty document cannot show any of this, which is why the dummy model was built.
Writing either endpoint changes the other. PUT /db/STYP-M1 with
STYPE: "XZ", TEMP: 11 makes the classic read STYP: 1, TEMP: 11; PUT
/db/STYP with TEMP: 22 makes the Hyper-S one read TEMP: 22. They are two
spellings of one model setting, which is also why neither serves POST or
DELETE: the document cannot exist without exactly one of these records.
/db/STYP-M1 |
classic /db/STYP |
|---|---|
STYPE: 3D / XZ / YZ / XY / RZ |
STYP: 0 / 1 / 2 / 3 / 4 |
MASS_CONTROL.MASS_TYPE: LUMPED / CONSISTENT |
MASS: 1 / 2 |
MASS_CONTROL.MASS_POS: CENTROID / OFFSET |
bMASSOFFSET: true / false |
MASS_CONTROL.MASS_AXIS: XYZ / XY / Z |
SMASS: 1 / 2 / 3 |
MASS_CONTROL.SELFWEIGHT |
bSELFWEIGHT |
GRAV, TEMP, ALIGNBEAM, ALIGNSLAB |
same, b-prefixed for the booleans |
MASS_POS maps the way round that reads backwards: CENTROID is
bMASSOFFSET: true. Do not "correct" it. When MASS_TYPE is CONSISTENT,
bMASSOFFSET is absent from the classic response entirely; when SELFWEIGHT
is false, so is SMASS.
STYPE selects the model's active degrees of freedom¶
Same model, same supports, self-weight in −Z, one analysis per structure type. Node 3 displacement:
STYPE |
DX | DY | DZ | RX | RY |
|---|---|---|---|---|---|
3D |
0.015020 | 0.006429 | −0.021727 | −0.002223 | 0.005007 |
XZ |
0.015020 | 0 | −0.017444 | 0 | 0.005007 |
YZ |
0 | 0.006429 | −0.009211 | −0.002223 | 0 |
XY |
0 | 0 | 0 | 0 | 0 |
RZ |
as 3D |
XZ keeps DX/DZ/RY, YZ keeps DY/DZ/RX, and XY produces nothing at all here
because the load is along the one axis that plane has no freedom in. DZ
differs between 3D and XZ (−0.021727 vs −0.017444) because the out-of-plane
contribution is gone, not merely hidden. So a structure type is not a display
setting: it changes the answer.
A caution learned the hard way in the same session: an earlier run of this
comparison had no supports at all, because /db/CONS was sent a 6-character
CONSTRAINT where it wants 7 ([DX,DY,DZ,RX,RY,RZ,RW]) and the failure was
not checked. That model still answered {"message": "MIDAS CIVIL NX command
complete"} for four of the five types and produced a plausible-looking
difference. Verify the fixture with a GET before reading anything into a
result.
Conditional rules on MASS_CONTROL, as enforced¶
| sent | result |
|---|---|
MASS_TYPE: LUMPED with no MASS_POS |
rejected, Wrong Field — genuinely required |
MASS_TYPE: CONSISTENT, SELFWEIGHT: true, MASS_AXIS: XY |
rejected, MASS_AXIS is XYZ if MASS_TYPE is CONSISTENT |
MASS_TYPE: CONSISTENT with MASS_POS sent |
accepted, and MASS_POS silently dropped |
STYPE: "_3D" |
rejected, Wrong Field |
STYPE: "3D" |
accepted |
Two of these settle open questions. The manual documents MASS_POS under
CONSISTENT as 불가 — the server does not refuse it, it discards it, so a
caller who sends it gets no signal that it was ignored. And the chapter's ⚠️
choosing "3D" over the article's "_3D" enum is correct: _3D is rejected.
Gen NX: the same dummy frame, and where the two products differ¶
Everything above was Civil. Repeated on Gen NX with the same model built the
same way — 3 nodes, 2 beams, one material, one section, a fixed base and a
self-weight case — with each piece asserted by a GET before anything was read
out of it.
Hyper-S is still Civil-only on this build. /db/STYP-M1, /db/POLC-M1,
/db/MATL-M1, /db/EIGV-M1 and /db/ACTL-M1 all answer 404 on Gen, and so
do their /info routes. HYPER_S_ONLY matches reality as of 2026-08-30; that
constant is still the right place to widen if Hyper-S ever reaches Gen.
The two products agree exactly. Same model, same supports, same self-weight, node 3 displacement per structure type — Gen's numbers are identical to Civil's to the last digit, including which components are zeroed:
STYP |
DX | DY | DZ | RX | RY |
|---|---|---|---|---|---|
0 (3D) |
0.015020 | 0.006429 | −0.021727 | −0.002223 | 0.005007 |
1 (XZ) |
0.015020 | 0 | −0.017444 | 0 | 0.005007 |
2 (YZ) |
0 | 0.006429 | −0.009211 | −0.002223 | 0 |
3 (XY) |
0 | 0 | 0 | 0 | 0 |
4 (RZ) |
as 3D |
So the degrees-of-freedom finding is a property of the setting, not of Civil.
DELETE /db/STYP is refused on Gen too — all three shapes, with the model
present and from a non-default state, {"message": "error status"}, nothing
changed.
bROTRIGID is in both schemas and only one product's responses.
gen GET /db/STYP : {..., "bMASSOFFSET": true, "bROTRIGID": false, "bSELFWEIGHT": false}
civil GET /db/STYP : {..., "bMASSOFFSET": true, "bSELFWEIGHT": false}
GET /info/db/STYP returns the same ten keys on both products, bROTRIGID
among them. Civil accepts a PUT carrying it — no error either way — and then
never echoes it back, whether it was sent true or false. Gen always reports
it.
That is a response-shape difference the schema does not predict, on an endpoint
neither the manual nor /info distinguishes by product. Code written against
Gen that reads STYP["bROTRIGID"] raises KeyError on Civil. Read it with a
default, and do not add it to a payload-shape check that runs against both.
StructureTypePayload documents bROTRIGID without qualification, which is
right for the request; the difference is in what comes back.
What this says about normalization¶
The manual repo's ⚠️ callouts exist because the official docs contradict
themselves, and following them is normally right — that rule is in CLAUDE.md
and it stays. But a normalization is a judgement about a product, and this one
was reasoned from consistency with sibling endpoints rather than measured. It
was wrong, and it was wrong in the direction that removes a capability users
have.
Both of these were caught by asking the server. Neither would have been caught by any amount of re-reading, because both surfaces agreed with the document they were derived from.
/db/MVCTch exposes the documented BRIDGE2 branch on both products (2026-08-30)¶
Read-only GET /info/db/MVCTch against the supplied Civil NX and Gen NX
sessions returned BRIDGE2 under Argument.properties on both products.
The official manual's China moving-load-control section documents it as the
object required when iCODETYPE is 2 or 3 (TB 10002-2017 / Q·CR
9300-2018). The Python and generated TypeScript payload surfaces had omitted
the field; it is retained as an untyped object because its BTYPE branches
have different members. No model data was read or changed by this check.
/db/MVLD exposes Australia's documented ASL branch on both products (2026-08-30)¶
Read-only GET /info/db/MVLD against the same Civil NX and Gen NX sessions
returned the identical ASL object: MULTIPLE_FACTOR, both vehicle-name
members, the loaded-lane bounds, and LINE_ITEMS. Its nested properties were
exactly NA_LLAN_NAMES, STRAD_LLAN1_NAMES, and STRAD_LLAN2_NAMES, matching
the manual's Australia Heavy Load Platform table. The SDK had omitted this
top-level branch; it is now structured on both Python and generated TypeScript
surfaces. No model data was read or changed by this check.
/db/MVLDch Python payload now matches its contract branch (2026-08-30)¶
Civil and Gen /info/db/MVLDch both expose the five members of the
OPT_AUTO_OPTIMIZE=true branch: MIN_VEHICLE_DIST, LOADED_LANE_NAME, the
two vehicle-count bounds, and AUTO_OPTIMIZE_ITEMS. The promoted contract and
generated TypeScript discriminated union already contained that manual-defined
branch, but Python had only the false/general-load branch. The Python payload
now carries the same documented conditional fields. No model data was read or
changed by this check.
/db/STCT exposes documented Grid Model fields on both products (2026-08-30)¶
Civil and Gen /info/db/STCT both include bSDLE and vSDLE, the Grid Model
secondary-dead-load option and its load-case list. They are documented in the
Erection Load table but had been omitted from the Python and generated
TypeScript payload surfaces. Both now match the server's top-level schema. No
model data was read or changed by this check.
The npm package's first live session (2026-08-31)¶
Until this date the npm package had never spoken to a MIDAS NX server. All
three live harnesses — live_crud_check.py, live_readonly_sweep.py,
live_smoke.py — are Python, and every npm test mocks fetch. Its HTTP layer,
its error mapping and its /post/TABLE adapter are hand-written, and a mock
agrees with whatever the author assumed.
midas-nx@2.7.1 was installed from the public npm registry into an empty
project and run against both supplied sessions, read-only. Six checks per
product, ten passing:
| check | gen | civil |
|---|---|---|
verifyConnection() |
status: connected |
status: connected |
resources.db.nodeElement.node.get() |
{"message": ""} |
{"message": ""} |
.info() |
3 properties | 3 properties |
client.request("GET", "/db/STYP") |
full record | full record |
404 route -> MidasNotFoundError |
/info/db/WVLD |
/info/db/SDIS |
/post/TABLE NODE (POST-shaped read) |
MidasResultError |
MidasResultError |
The last row is the interesting one and it is not a defect. Both models are
empty, so the server answers HTTP 200 with an error body — there was an
error creating utbl. The npm client detected the error inside a 200 and raised
MidasResultError, which is the documented hazard this project exists to
handle. The identical call from the Python SDK on the same two sessions
produced the identical exception with the identical message, so the two
surfaces agree against a real server, not merely against each other.
What this does not establish. No npm write has ever reached a live product:
POST/PUT/DELETE, and with them the /db/NMAS rmX/rmY/rmZ
payloadDefaults rule, remain verified by test only on the npm side. And
unwrapTable() was reached but never given a populated table, because the
empty model errored first — the unstable-top-level-key behaviour it exists for
is still unobserved from JavaScript.
Reproduction at the time: install midas-nx from the registry, call the six
checks above. No repository harness existed yet; the next entry records the
subsequent write-capable harness.
npm public-API write and populated-table verification (2026-08-31)¶
The repository now has that reproducible harness at
packages/typescript/scripts/live-crud.mjs. It imports the built npm package
entry point (dist/index.js) and uses only its public resources.db.* and
post.* APIs; it does not issue raw HTTP requests or import Python. Its
payloads are read from the checked-in, language-neutral
schema/live-cases.json fixture emitted by scripts/live_crud_check.py.
On the confirmed-empty Gen NX 2026 v2.1 and Civil NX 2026 v2.2 sessions (both build 08/26/2026), the following npm-package round trips passed on both products:
| npm public API | check | gen | civil |
|---|---|---|---|
resources.db.nodeElement.node |
create, read, update, read, per-id delete, final read | pass | pass |
resources.db.staticLoads.nodalMass |
same CRUD cycle, with its fixture omitting rmX/rmY/rmZ |
pass | pass |
resources.db.project.loadGroup |
create, read, update, read, per-id delete, final read | pass | pass |
resources.db.analysisControl.settlementAnalysisControlData |
same CRUD cycle for independent Boolean control data | pass | pass |
post.getTable("MASS_SUMMARY_X") + post.unwrapTable() |
seed a fixture Node and Nodal Mass, then read a populated table | pass | pass |
For Nodal Mass, the record read back after both POST and PUT contained
the generated resource's payloadDefaults (rmX, rmY, and rmZ, each
0.0). This is live evidence that the npm public DB resource supplies the
three omission-sensitive values before sending the request, rather than only
declaring them in metadata.
The populated MASS_SUMMARY_X responses had a top-level key of empty
on both products while carrying a two-row HEAD/DATA table. unwrapTable()
found that table by shape, as intended; treating the empty key as “no data”
would have discarded real result rows. The table seed used its own Node/Nodal
Mass id and both were removed with individual-id DELETE calls. Final public
items() reads for /db/NODE and /db/NMAS returned {} on both products.
This is explicitly npm-specific live evidence. docs/coverage.json remains
unchanged: its historical level field means verification through the Python
package, so an npm run must not silently widen that meaning.
One runner limitation was also made explicit rather than misreported as an
SDK regression. /db/STLD ignores the requested Assign id on a blank model
and creates the next sequential id; its Python case intentionally runs after
the base model has already allocated ids 1–2. The small npm batch does not
recreate that base model, so it rejects that case as not equivalent instead of
claiming it is npm evidence. The npm harness now tracks every id newly created
by a selected case and deletes those ids individually even when a server has
renumbered the requested record. A Gen NX probe confirmed the failing STLD
case left its server-assigned id cleaned up ({} afterward). No coverage level
was changed for STLD.
Caveat — read before acting on this file¶
/db/MVLDpl exposes all documented conditional objects on both products (2026-08-30)¶
Civil and Gen GET /info/db/MVLDpl return the same three conditional payload
objects: DEFAULT, AUTO_OPTIMIZE, and PERMIT_LOAD. The latter two had been
documented in the Poland moving-load table but were absent from the Python and
generated TypeScript surfaces. Their nested members also match the manual's
Vehicle S/2S, Vehicle K/Military, and permit-vehicle rows. No model data was
read or changed by this check.
/db/IEHC distinguishes Civil beam fields from Gen wall fields (2026-08-30)¶
Both products return the eight documented beam fields, including
BeamDivNumNyCover and BeamDivNumNzCover; the earlier Python surface had
instead exposed obsolete CoverDivNum* names. Gen additionally returns the
nine Wall members documented as GEN-only, while Civil correctly omits them.
The live drift checker now reads the corresponding contract product gates, so
that documented product variation is not reported as a false discrepancy. No
model data was read or changed by this check.
/db/MATL-M1 round-trips all three documented live P_TYPE branches (2026-08-31)¶
On a fresh Civil NX scratch model, Standard (P_TYPE=0), Isotropic (1), and
Orthotropic (2) Hyper-S materials each passed POST -> GET -> PUT -> GET ->
DELETE /db/MATL-M1/{id} -> GET. The returned Standard branch includes CODE,
DB, USER_DEFINED, and THERMAL_TRANS; the two user-defined branches return
the nested USER_DEFINED and THERMAL_TRANS objects. This confirms the
0-based P_TYPE branches and their nested shape through writes, not merely
/info introspection.
The product rejected all three first attempts solely because the material names
exceeded its 16-character limit. Shorter names then passed unchanged. The
manual's Hyper-S section has no field-level Specifications table and does not
state that limit. The scratch model was reset with /doc/NEW after individual
per-id deletion checks completed.
/db/MATL-M1 is not /db/MATL plus Hyper-S additions (2026-08-31)¶
The manual's 04_DB_Properties.md statement that the Hyper-S endpoint has the
same base material structure as /db/MATL, with additional Hyperelastic
support, is contradicted by Civil NX /info output:
/db/MATL NAME, TYPE, PARAM, DAMP_RAT, HE_COND, HE_SPEC, PLMT, P_NAME, bMASS_DENS
/db/MATL-M1 MATL_NAME, MATL_TYPE, PARAM, DAMP_RAT
The endpoint has different name/type wire keys and fewer top-level members;
HE_COND and HE_SPEC are on /db/MATL, not /db/MATL-M1. The two material
families also use different PARAM[].P_TYPE numbering and nesting, as the
write round trips above confirm. A parent-field delegation would therefore be
a wrong contract, not a useful fallback. This is a manual-structure defect to
report upstream, not an SDK source for contract transcription.
/db/IEHC WAreaSize is a live string, not the table's integer (2026-08-30)¶
Gen NX /info/db/IEHC types only WAreaSize as string; the sibling
WAreaSizeCover is integer. The chapter's Specifications table calls
WAreaSize Integer, while its own Request Example sends "WAreaSize": "AUTO".
The promoted contract deliberately retains the manual's Integer declaration
and records this conflict separately under manualDefects plus the Gen
verification record. It is not silently retyped from one live observation.
SDST, SDIS, MVCTch and WVLD re-check on fresh scratch models (2026-08-31)¶
/db/SDST: the current official BL2 payload passedPOST -> GET -> PUT -> GET -> DELETE /db/SDST/{id} -> GETon both Civil NX and Gen NX. The storedBL2.BETAand updatedP1values were read back. This replaces the oldWrong Fieldresult, which predated the manual's SDST/SDVE correction./db/SDIS: Civil again returned 404 for/info/db/SDIS. On Gen, the correctedSDIS_DEV_TYPE="SLD"plusSBpayload passed the same complete round trip, including an updatedKV. The officialNRBexample subsequently passed the same complete round trip and returned its updatedKV; its record was removed individually and a final GET returned an empty table. LRB still returnsWrong Fieldwith the official correctedK0/nested-DXshape, even though Gen/infoexposes that shape. This leaves the LRB model-literal/precondition unresolved rather than treating it as a field-shape defect./db/MVCTch: Civil and Gen both passed the full round trip for theiCODETYPE=0/FREQbranch.FREQ.USER_F=0fails explicitly withf > 0;USER_F=3.0passes. The manual's request example omitsiSLCMandiBCeven though its table calls them required. Both values can be sent as zero, but the server normalizesiSLCMout of the GET response./db/WVLD: Gen remains a route and/info404. Civil still returnsWrong Fieldfor the full official example, including the live-schemaDRAG_COEF_X/Y/ZandINER_COEF_X/Y/Zkeys. It had also rejected a bareNAMEpayload in the earlier probe. The live evidence therefore points to an undocumented product precondition or module gate, not the documented payload spelling. Every test record was targeted by its individual-id delete; the scratch models contain no test records from this pass.
/db/NLLP fresh-model re-check (2026-08-31)¶
On both empty current-build scratch documents, the manual's exact
APPLICATION_TYPE="ELEMENT" / APPLICATION_TYPE_D="SPG" request example
again returned HTTP 201 with the error body Unknown Error. This is the same
result as the seeded and fresh-document attempts recorded on 2026-08-16 and
the Civil re-check on 2026-08-27. The record never materialized; individual-id
cleanup and a final GET confirmed each NLLP table remained empty. The finding
therefore remains an undocumented product precondition or module gate, not an
SDK or documented-field-shape conclusion.
This is evidence from one MIDASIT account, one product license/edition,
one point in time, not from the manual. It is plausible some of the
20 + 7 "product-only" endpoints above are actually gated by license tier,
Civil/Gen build version, or model state rather than being permanently
unavailable for that product. Do not change any PRODUCTS frozenset in
the SDK based solely on this file. If the same restriction is
independently reproduced (different account, different session, or a
future manual revision adds an explicit product note), that's the trigger
to revisit PRODUCTS for the specific classes involved — cite this file's
date and findings in that future change, and re-verify before trusting it,
since MIDASIT's platform can change between now and then.
npm public-API Gen re-check: Node and Skew (2026-08-31)¶
Before mutation, direct public GETs on the supplied Gen NX 2026 v2.1 build
08/26/2026 session returned the documented empty-model shape for both
/db/NODE and /db/ELEM. The built midas-nx@2.7.3 package was then run
through packages/typescript/scripts/live-crud.mjs, using only the shared
schema/live-cases.json fixture and an author-approved C:/temp checkpoint:
| npm public API | result |
|---|---|
resources.db.nodeElement.node |
POST -> GET -> PUT -> GET -> DELETE {id} -> GET passed |
resources.db.nodeElement.skew |
the same cycle passed after the fixture's disposable node-2 seed |
The runner saved C:/temp/midas-nx-live-gen-1788162734155.mgbx before the
mutations and reported both cases as PASS; it verifies every target and seed
with individual-id DELETE before reporting success. A subsequent independent
GET could not run because the supplied Gen MAPI key then returned HTTP 401
(MAPI-Key is invalid). That is an authentication-session interruption, not
evidence about either endpoint; no coverage level changed because this remains
npm-specific evidence.
npm public-API checkpoint and unresolved-case re-check (2026-08-31)¶
The npm live harness now saved a checkpoint before every mutation. The
author explicitly selected C:/temp as a known writable directory on the NX
machines — a directory they created themselves — after the old inference from
the authenticated MAPI account produced an invalid-path dialog. SAVEAS
answered command complete on both sessions.
Correction, 2026-08-31 — and the repo got this wrong twice before landing
on it. That run wrote .mgbx on Gen and .mcbx on Civil. Gen's is right.
Civil's was first "corrected" to .mcb, which is also wrong: .mcb is the
pre-NX Civil extension. The author, a MIDAS IT employee, gives the full set:
| Gen | Civil | |
|---|---|---|
| pre-NX | .mgb |
.mcb |
| NX | .mgbx |
.mcbz |
Civil NX's own Export menu lists "MCBZ File", which settles it. Both harnesses now write the NX pair.
Two adjacent facts, so the next person does not re-derive them. /doc/STAGAS
is the exception that genuinely wants the legacy .mcb — .mcbx failed there
in 2026-07 with "Please check the file name or extension". And Civil does
tolerate .mcbx for SAVEAS: the 2026-07 round trip wrote one and reopened
it with all 273 nodes intact (see the /doc/* lifecycle entry above). Being
accepted is not being native, and that tolerance is exactly what let the wrong
spelling survive a live run without complaint.
Note also that command complete is not evidence a file was written — this
project's own rule — so nothing establishes what the Civil .mcbx checkpoints
from this run actually are. They were never read back.
Export menus differ by product (observed 2026-08-31, both products' own
menus). Civil NX: MIDAS/Civil MCT, MXT (for FEA/GTS), AutoCAD DXF, Frame
Section for Solid and for Plate, IDEA, IFC, MIDAS CIVIL NX JSON File, and
MCBZ File. Gen NX: MGTX (for GEN NX), Batch midas Gen MGTX, MGT (for Gen),
MGT (v885 for nGen), MXT, AutoCAD DXF, Midas Drawing, Frame Section for Solid,
IDEA, IFC, and MIDAS GEN NX JSON File — with no MGBX entry, because that
is a save format rather than an export. So /doc/EXPORTMXT's text format is
product-specific (MCT on Civil, MGT/MGTX on Gen), while /doc/EXPORT's JSON
is offered by both.
Using only the built npm package's public resources.db.* surface, /db/STLD
passed POST -> GET -> PUT -> GET -> DELETE {id} -> GET on both products.
The runner first created its documented DL and LC_SCRATCH static-load
cases, so STLD's server-assigned sequential id matched the Python fixture;
it then removed each target and prerequisite by its individual id.
/db/THIK also passed the same public-API CRUD sequence on both products;
the changed T_IN value was observed after PUT, and the final per-product
items() call returned {} after the individual delete.
/db/SKEW requires an existing target node, so its first npm attempt against
an empty document correctly received the server's explicit “node no. 2 has
not been specified” rejection. The shared fixture now declares a disposable
node-2 seed. With that modelled prerequisite, SKEW passed the same CRUD cycle
on both products; final public items() calls returned {} for both NODE
and SKEW after the target and seed were each deleted by id.
The following shared-fixture cases remain unconfirmed and reproduced their existing product rejections rather than becoming npm regressions:
- Gen
/db/SDISLRB case: HTTP 201 withWrong Field. The fixture now uses the manual's corrected nestedLRB.DXobject and includesK0; Gen's/infoexposes that exact nesting. The same response therefore remains an unresolved product-value/precondition result, not evidence for changing field names or nesting. - Civil
/db/WVLD: HTTP 201 withWrong Fieldfor the full fixture payload. - Gen and Civil
/db/NLLP: HTTP 201 withUnknown Errorfor the minimalELEMENT/SPGfixture payload.
Final npm public-API items() calls returned {} for Gen STLD/SDIS/NLLP
and Civil STLD/WVLD/NLLP. No coverage level changed: that ledger still
denotes Python-package verification, while this entry records independent npm
transport and public-resource evidence.
npm post-analysis result-table verification (2026-08-31)¶
Pre-process CRUD is not sufficient evidence for result APIs. The npm package
therefore now has a separate live:analysis runner that first refuses a
non-empty fixture scope, then builds a minimal 0.6 m square C24 cantilever
column through public resources (material, section, two nodes, beam, fixed
base, DL, and self weight). It saves the completed dummy model under the
author-selected C:/temp checkpoint directory before calling doc.analyze().
On both Gen NX and Civil NX, the solved model returned populated HEAD/DATA
tables through the built npm package for REACTIONG (1 row), DISPLACEMENTG
(1 row), and BEAMFORCE (5 rows). All three responses used the unstable
top-level key empty; post.unwrapTable() found the table by shape rather
than treating that key as no data. The runner deleted self weight, load case,
constraint, element, both nodes, section, and material individually in reverse
creation order. Final npm public-API GETs returned {} for each of those seven
tables on both products.
npm blank-model design-control re-check (2026-08-31)¶
With author-confirmed empty scratch documents, re-ran the shared npm fixture
for /db/DCON and /db/DSTL exclusively through the built package's public
resources.db.* surface. The runner saved native-format checkpoints before
each mutation: C:/temp/midas-nx-live-gen-1788171188500.mgbx and
C:/temp/midas-nx-live-civil-1788171201694.mcbz.
/db/DCONcompletedPOST -> GET -> PUT -> GET -> DELETE {id} -> GETon both Gen NX 2026 v2.1 and Civil NX 2026 v2.2 (both build 08/26/2026), using the manual-listedKCI-USD12andKCI-USD07codes./db/DSTLcompleted the same sequence on Civil withEurocode3-2:05andAISC-ASD89. On Gen's otherwise empty document, its initial POST returned HTTP 201 with the result error[Error] Errors detected in Steel Design Control Data.(Item:). The same response remained after creating the manual'sEN05(S)/S450steel material, anH300x150section, two beam elements, and a design-member record. It is therefore not an empty-model prerequisite. The response still does not distinguish a Gen product/license gate from another server-side design-control condition, so no request shape is inferred from it.
Final npm public-API items() calls returned zero records for NODE, ELEM,
DCON, and DSTL on both products. This is npm-specific transport evidence;
it does not change the Python write-coverage ledger.
The next small blank-model batch saved
C:/temp/midas-nx-live-gen-1788171319232.mgbx and
C:/temp/midas-nx-live-civil-1788171326304.mcbz before testing /db/DCTL
and /db/LTSR.
/db/DCTLcompleted its full CRUD sequence on both products./db/LTSR's original fixture target id1was rejected on both products at POST with HTTP 201 andNot Found Key. The manual describes it as an element-keyed record, and id 1 is not a BEAM in the scratch fixture. A disposable manual-derived steel-beam model established that the actual BEAM id2completes POST, GET, PUT, GET, DELETE-by-id, GET on both products. The shared fixture now uses id2and declares its material, section, node, and beam prerequisites so npm can make the same empty-document test without copying a payload into JavaScript.
The corrected npm run saved
C:/temp/midas-nx-live-gen-1788172728458.mgbx and
C:/temp/midas-nx-live-civil-1788172738478.mcbz; /db/LTSR passed through
the built public package on both products. A separate Gen probe found the
manual's KS21(S) / SS400 material example returns Unknown Error, whereas
the manual's EN05(S) / S450 example round-trips. This is recorded as a
product observation, not a manual correction: the server did not explain
whether the difference is a license or supported-standard gate.
Both products again returned zero records for NODE, ELEM, DCTL, and
LTSR after the run; the modeled prerequisite runs likewise returned zero
records for MATL, SECT, NODE, ELEM, MEMB, and LTSR.
/db/MBTP is likewise element-keyed. Using the same official-manual-derived
material, section, nodes, and BEAM id 2, it completed the full public npm
CRUD sequence on both products. Its shared fixture now declares those same
four seeds rather than trying to write to an empty document. The final npm
checks saved C:/temp/midas-nx-live-gen-1788173302760.mgbx and
C:/temp/midas-nx-live-civil-1788173320331.mcbz; all target and prerequisite
tables were empty after individual cleanup.
/db/LENG is another element-keyed design record. With the same BEAM id 2
and four reusable prerequisites, it completed the public npm CRUD sequence on
both products. The shared fixture now uses that actual element id and declares
the same setup. Its checkpoints were
C:/temp/midas-nx-live-gen-1788173496472.mgbx and
C:/temp/midas-nx-live-civil-1788173505730.mcbz.
/db/MEMB needs two compatible BEAM elements rather than one. The fixture now
adds node 4 and BEAM id 3 after the reusable element-2 chain, then groups
[2, 3] exactly as its documented case specifies. It passed the full public
npm CRUD sequence on Gen and Civil, with checkpoints
C:/temp/midas-nx-live-gen-1788173602613.mgbx and
C:/temp/midas-nx-live-civil-1788173614217.mcbz. Individual cleanup again
left the target and all material, section, node, and element prerequisites
empty on both products.
/db/WMAK is also model-keyed. Its WID_LIST: [4] fixture now declares a
disposable material, thickness, rectangular nodes, and PLATE element 4,
rather than relying on Python's prebuilt base model. Through the built npm
package, the full POST -> GET -> PUT -> GET -> DELETE {id} -> GET sequence
passed on Gen and Civil. The saved native checkpoints were
C:/temp/midas-nx-live-gen-1788174074805.mgbx and
C:/temp/midas-nx-live-civil-1788174088855.mcbz; individual cleanup removed
the WMAK target and every prerequisite.
The setup deliberately uses a PLATE only as a tested fixture prerequisite. A
separate complete manual TYPE: "WALL" example (including STYPE, WALL,
W_CON, and W_TYPE) succeeded on Gen but Civil NX v2.2 build 08/26/2026
returned [Error] Unable to add/modify the element. The element type no. 5 for
the element no. 4 is not supported. The manual's type table numbers PLATE as
5 and WALL as 6, whereas a zero-based internal type number would make WALL 5.
That numbering observation is recorded as MD-06; it does not establish that
PLATE and WALL are interchangeable, so neither contract nor SDK behaviour was
inferred from it.
/db/SDST originally failed in the npm harness because its fixture stopped at
the three selector fields. The manual marks K0, P1, ALPHA1, KB, and
the selected BL2.BETA as required; after adding its documented BL2 example
values, the built package completed the public CRUD sequence on both products.
It read back the changed P1 value after PUT, then deleted the record by id.
The checkpoints were C:/temp/midas-nx-live-gen-1788174337218.mgbx and
C:/temp/midas-nx-live-civil-1788174348471.mcbz.
/db/MVCT was then exercised unchanged from the shared fixture through the
built npm public resource on both empty scratch models. Gen returned HTTP 201
with Unknown Error after saving
C:/temp/midas-nx-live-gen-1788174456882.mgbx; Civil returned the same result
after saving C:/temp/midas-nx-live-civil-1788174467843.mcbz. The fixture is
not changed from that result: neither response identifies a field or enum to
correct, so treating it as a payload-shape finding would be speculation.
extras7 fixture re-check and Civil WALL response quote (2026-08-31)¶
With both scratch documents empty, the Python live runner re-ran extras7 on
Gen NX and Civil NX 2026 (v2.1/v2.2, build 08/26/2026). /db/PNLD completed
POST -> GET -> PUT -> GET -> DELETE {id} -> GET on both products using its
existing manual-derived fixture and disposable seed. The earlier coverage ledger
already correctly recorded that write evidence; this run corrects the stale
fixture confirmed flag. The checkpoints were
C:/temp/midas-nx-live-gen-extras7-20260831.mgbx and
C:/temp/midas-nx-live-civil-extras7-20260831.mcbz.
The same run reproduced the established outcomes without changing their
fixtures: Gen /db/FBLA returned Unknown Error; Gen /db/EPST and
/db/EPSE returned Wrong Field; Civil /db/FBLA returned Unknown Error.
The Civil runner skipped Gen-only earth-pressure cases and reported its existing
incompatible POSL seed, while the independent PNLD case still completed and
cleaned up. These remain product/precondition findings rather than shape changes.
For MD-06, a separate Civil probe used the manual's complete TYPE: "WALL"
element example and returned exactly [Error] Unable to add/modify the element.
The element type no. 5 for the element no. 4 is not supported. It deleted every
seed record individually; the final NODE and ELEM reads were both empty.
The same PNLD fixture then passed through the built npm package's public
resources.db.* surface on both products. The npm runner saved
C:/temp/midas-nx-live-gen-1788187237711.mgbx and
C:/temp/midas-nx-live-civil-1788187248388.mcbz before the round trips and
reported PASS /db/PNLD for each. This is npm-specific evidence and therefore
does not alter docs/coverage.json's Python-package write ledger.
extras8 current-build re-check (2026-08-31)¶
On empty scratch documents, the Python extras8 runner re-ran the existing
manual-derived control-data fixtures on Gen NX 2026 v2.1 and Civil NX 2026 v2.2,
both build 08/26/2026. /db/EIGV completed the documented LANCZOS round trip
on both products with TYPE, iFREQ, bMINMAX, FRMIN, FRMAX, and bSTRUM;
no FREQ_RANGE field was sent. This supersedes the older Civil failure for this
exact fixture on the current build, but does not establish a version-independent
Civil behaviour or add an undocumented field to a contract.
/db/BCCT likewise completed on both products when its vBOUNDARY.vBG values
referenced the real BG1 and BG2 /db/BNGR seed records. This supersedes the
older Civil failure for this fixture on the current build only. Both endpoints
now have current Gen-and-Civil write evidence; the runner marks their Civil
fixtures confirmed and deletes each disposable record after the test.
The unresolved observations were kept distinct: Gen rejected /db/ACTL with
Wrong Field; Civil accepted its request but read TOL=0.0005 back as 0.001.
Both products returned Unknown Error for /db/MVCT; Civil still failed /db/HHCT
by reading THETA=0 after sending 1, and /db/NLCT required
LINE_SEARCH_OPTION when OPT_ENABLE_LINE_SEARCH was true. None of those
outcomes identifies a manual-backed payload correction, so their fixtures and
contracts remain unchanged.
extras6 fixture re-check (2026-08-31)¶
The existing /db/SDST steel-damper fixture completed its full CRUD sequence
on both empty scratch models (Gen NX v2.1 and Civil NX v2.2, build 08/26/2026).
It was already write-covered, so this only corrects its stale fixture
confirmed state. /db/SDVI and /db/SDVE both returned Wrong Field on
both products; Gen's /db/SDHY and /db/SDIS did too. Their existing fixtures
remain unconfirmed because the responses do not identify a manual-backed value
change. Each run saved its checkpoint under C:/temp and deleted test records
individually.
extras13 Gen/Civil design fixture re-check (2026-09-01)¶
After saving the pre-existing test model to C:/temp, the runner created and
cleaned up fresh scratch models on Gen NX 2026 v2.1 and Civil NX 2026 v2.2,
both build 08/26/2026. /db/DCON, /db/LENG, /db/MEMB, /db/DCTL,
/db/LTSR, /db/MBTP, and /db/WMAK each completed
POST -> GET -> PUT -> GET -> DELETE {id} -> GET on both products. The
previous Civil-only coverage records are therefore now current dual-product
evidence.
/db/DSTL remains intentionally unconfirmed. Its existing Eurocode3-2:05 /
AISC-ASD89 fixture completed on Civil, but Gen returned exactly
[Error] Errors detected in Steel Design Control Data.(Item:) at POST. That
is a product/build observation, not a basis for changing its manual-backed
payload or contract. The checkpoints were
C:/temp/midas-nx-live-gen-extras13-20260901.mgbx and
C:/temp/midas-nx-live-civil-extras13-20260901.mcbz; all test records were
deleted by individual id.
The built npm package independently completed the same seven endpoints through
its public resources.db.* API on both products. Before every npm batch, the
harness saved the open document to C:/temp, called doc.newProject(), and
verified /db/NODE and /db/ELEM were both empty before inserting fixture
records. This caught a harness defect: it had previously saved a checkpoint but
continued in the caller's open model. The fixture now explicitly permits only
the new-document baseline records (MATL/SECT/THIK id 1) to be replaced by
its own individually-cleanable prerequisites; every other setup collision still
refuses to mutate. The Gen checkpoints included
C:/temp/midas-nx-live-gen-1788189466400.mgbx and
C:/temp/midas-nx-live-gen-1788189527322.mgbx; Civil used
C:/temp/midas-nx-live-civil-1788189535828.mcbz and
C:/temp/midas-nx-live-civil-1788189577919.mcbz. Follow-up reads confirmed
both products ended with zero nodes and elements.
Civil response-spectrum load fixture re-check (2026-09-01)¶
/db/SPLC again completed POST -> GET -> PUT -> GET -> DELETE {id} -> GET
on Civil NX 2026 v2.2, build 08/26/2026, using the existing SPFC_SEED
function prerequisite. The same fixture remains unconfirmed on Gen NX: its
POST returns Unknown Error. The fixture is therefore recorded as two
product-specific cases (Civil confirmed; Gen unconfirmed), rather than letting
a Civil result claim a uniform cross-product result. The Civil checkpoint was
C:/temp/midas-nx-live-civil-extras5-20260901.mcbz.
In the same empty-scratch-model batch, /db/SPFC, /db/THGC, /db/THFC,
/db/THGA, /db/THNL, and /db/THSL completed their existing Civil cases.
/db/THMS returned Wrong Field at create; that response does not identify a
manual-backed fixture correction, so it remains unconfirmed.
Domain feature current-build re-check (2026-09-01)¶
On both empty scratch models, /db/MADO, /db/SBDO, and /db/DOEL again
accepted their POSTs but had no requested record in the immediately following
GET. /db/MADO is the prerequisite: it was absent at id 92 on both Gen NX
v2.1 and Civil NX v2.2, build 08/26/2026. The SBDO and DOEL results remain
downstream observations rather than independent failures, because their
manual-shaped records reference that missing domain. No payload, contract, or
coverage level was changed. Checkpoints are
C:/temp/midas-nx-live-gen-extras9-20260901.mgbx and
C:/temp/midas-nx-live-civil-extras9-20260901.mcbz.
Heat-source function fixture re-check (2026-09-01)¶
/db/HSFC completed its full round trip on both current builds after the
fixture created its two named prerequisite functions at ids 90 and 91, then
used independent id 92 for the test record. The previous confirmed: false
fixture state was stale evidence, not a product failure, and is now corrected.
/db/HAHS still requires a SOLID element that this deliberately minimal model
does not create; /db/HPCE still rejects its documented ITEMS array with
Wrong Key. Both remain unconfirmed without any inferred payload change. The
checkpoints are C:/temp/midas-nx-live-gen-extras10-20260901.mgbx and
C:/temp/midas-nx-live-civil-extras10-20260901.mcbz.
The built npm package independently completed /db/EIGV and /db/SDST through
its public resources.db.* surface on both products. It saved
C:/temp/midas-nx-live-gen-1788187895868.mgbx and
C:/temp/midas-nx-live-civil-1788187934137.mcbz before the checks. The npm
harness now selects the product-specific fixture when one endpoint has separate
Gen and Civil cases; previously it selected the first duplicate and incorrectly
skipped Gen /db/EIGV. /db/BCCT is deliberately not counted as npm evidence:
its Python fixture needs the tier-local bngr_seed, which the language-neutral
fixture does not yet serialize for the npm harness, so the public API correctly
returned Not Found Key without that prerequisite.
The documented PowerShell invocation with two selected paths also completed
after the harness normalized npm 12's retained cmd.exe caret quoting and its
space-split comma value. npm run live:crud -- -- --product gen --endpoints
/db/EIGV,/db/SDST --save-dir C:/temp saved
C:/temp/midas-nx-live-gen-1788188480567.mgbx and passed both endpoints.
extras1 and extras3 current-build re-check (2026-08-31)¶
The existing /db/NLLP seed again returned Unknown Error on both empty
scratch models. Its dependent /db/NLNK, /db/NLNK-M1 (Civil), and /db/CGLP
were therefore correctly reported as blocked rather than tested against a
missing prerequisite. No fixture was changed. The extras3 re-check likewise
left /db/TDMF and /db/RPSC failing at create on both products, and
/db/STRPSSM failing at create on Civil. These are current-build reproductions,
not evidence for changing fields, values, or contracts. All runs saved to
C:/temp and left the throwaway documents empty after individual cleanup.
Session-close scratch-state check (2026-09-01)¶
Before closing this batch, the two latest scratch documents were saved as
C:/temp/midas-nx-live-gen-final-scratch-20260901.mgbx and
C:/temp/midas-nx-live-civil-final-scratch-20260901.mcbz, then each product
received /doc/NEW. Read-only table reads afterward returned zero /db/NODE
records and zero /db/ELEM records on both products. The open documents are
therefore empty at session end.
Both SDKs swept read-only across the whole generated surface (2026-09-01)¶
Every earlier npm entry exercised a handful of endpoints. This is the breadth
check - scripts/live_readonly_sweep.py and a JavaScript counterpart written to
match it - run on both language surfaces against the same two sessions on
the same day. It is GET only: no create/update/delete, no /doc/*, no
/doc/NEW, no /post/TABLE. It ran against the documents the sessions already
had open and left them untouched.
The npm subject was the packed artifact, not the source tree: npm pack
produced midas-nx-2.7.3.tgz, which was installed into a throwaway project with
npm install and imported as midas-nx. Only resources.db.* and
resources.design.* were called. The Python side ran the repo's own sweep plus
two probes mirroring the npm ones, without --record-coverage.
| check | calls per SDK | npm | PyPI |
|---|---|---|---|
get() on every GET-capable resource, per declared product |
549 | 549 answered, 0 errors | 549 answered, 0 errors |
| GET on the product a single-product resource does not declare | 57 | 57 refused with 404 | 57 refused with 404 |
info() on every GET-capable resource, per declared product |
549 | 399 schemas, 150 404s | 399 schemas, 150 404s |
The two SDKs swept exactly the same 549 (product, endpoint) pairs - set
equality, not just equal counts - and returned the same result for every one.
validate_contracts.py already checks endpoint parity statically; this is the
first time it has been checked against running products from both languages at
once. Gen swept 267 resources and Civil 282; the npm passes took 22.9s and 25.3s.
Product gating is correct in both directions. All 549 declared resource/product pairs answered, so the metadata is not wider than the server, and all 57 single-product resources 404 on the product they do not declare, so it is not narrower either. This is the systematic version of the check that found 32 wrongly-Civil-only endpoints in 2026-07; nothing of that kind remains.
Thirteen resources returned data on an otherwise-empty document, all
new-document defaults: /db/CO_F, /db/CO_M, /db/CO_S, /db/CO_T,
/db/STYP and /db/UNIT on both products, plus /db/STYP-M1 on Civil only,
which is consistent with Hyper-S being Civil NX's solver. The other 536 returned
{"message": ""}.
/info is served for /db/* only. All 147 /DESIGN/* resource-product
pairs 404 on introspection while the endpoint itself answers a plain GET. That
is an API fact, not a URL-construction bug in either SDK - three casings were
tried by hand on Gen:
GET /DESIGN/RC/KDS-41-20-2022/DCTL -> {"message": ""}
GET /info/DESIGN/RC/KDS-41-20-2022/DCTL -> 404
GET /info/design/RC/KDS-41-20-2022/DCTL -> 404
GET /info/DESIGN/rc/kds-41-20-2022/dctl -> 404
GET /info/db/NODE -> full JSON Schema
This matters beyond the harnesses. GET /info{endpoint} is one of the three
permitted contract sources, and for the design-code family it does not exist:
those contracts can only be checked against the manual and against recorded live
behaviour. contracts/README.md and CLAUDE.md now say so.
Three /db/* endpoints also lack introspection, all Civil Hyper-S:
/db/IEHG-GL-M1, /db/IEHG-PSS-M1 and /db/IEHG-TRUSS-M1. They are the only
exceptions among 402 /db resource-product pairs, and both SDKs found the same
three.
Both SDKs expose info() on design resources, where it can only ever 404. That is a
documentation question, not a defect found here, and no SDK behaviour was
changed on the strength of this run.
Sessions were connected before and after, and /db/NODE and /db/ELEM
returned zero records on both products afterwards - the sweeps issued no writes,
and none of the roughly 2,300 GETs raised a modal dialog that blocked a session.
The products were MIDAS Gen NX 2026 (v2.1) and MIDAS Civil NX 2026 (v2.2); the
build string was not re-read this session, so this entry does not establish it.
No docs/coverage.json level changed - every endpoint swept is already recorded
at read or better, and level denotes verification through the Python package
in any case.
LCOM-SEISMIC real response-spectrum prerequisite re-check (2026-09-01)¶
The earlier product asymmetry was re-tested with the manual's actual
response-spectrum shape, rather than treating a static load case as a proxy.
The Civil scratch fixture first created /db/SPFC SPFC_LCOM_SEED, then a
real /db/SPLC Response Spectrum Load Case SPLC_LCOM_SEED referring to it.
/db/LCOM-SEISMIC was then posted with ANAL="RS" and that real LCNAME.
Civil NX 2026 v2.2, build 08/26/2026 still answered exactly:
This removes the missing-fixture explanation, but does not justify inventing a different Civil payload: the documented RS path itself is refused on the current server. The Civil case remains explicitly unconfirmed.
Gen NX 2026 v2.1, build 08/26/2026 independently completed the existing
documented static-member ANAL="ST", LCNAME="DL" create -> GET -> update
-> GET -> delete sequence. /db/LCOM-SEISMIC therefore moves to Python write
coverage for Gen only; it is not a claim that Civil supports the same
operation. The built npm package's public resources.db entrypoint completed
the same Gen round trip after its empty-document harness created the explicitly
declared static_load_cases prerequisite. Both reports and checkpoints were
saved under C:/temp.
Stage and extra resource re-check (2026-09-01)¶
STAG, TMLD, CRPC, and HSPT completed their current fixtures on both
products; Civil's CMCS completed as its Civil-only case. The remaining
observations reproduce known product/server behaviour and do not change a
contract: Gen accepted STCT but omitted the submitted iITER value on the
readback, Civil returned Key Already Exist for the same resource, and HECB
on both products rejected the scratch beam with the server message that the
element type cannot receive an Element Convection Boundary. Checkpoints and
reports were saved under C:/temp.
Complete SDVI and SDVE Request Examples re-check (2026-09-01)¶
The earlier Wrong Field results for /db/SDVI and /db/SDVE pre-dated the
manual's 2026-08-25 Request-Example corrections. The old SDVI fixture omitted
INPUT_TYPE_EXFN and the six exponential-function fields in each ITEM; the
old SDVE fixture contained only COMMON, MATERIAL_TYPE, and SHEAR_AREA.
Those were incomplete test payloads, not evidence that the current documented
routes reject their documented shapes.
Using the complete current examples, both endpoints completed
POST -> GET -> PUT -> GET -> DELETE(id) -> GET on Gen NX 2026 v2.1 and
Civil NX 2026 v2.2, build 08/26/2026. SDVI sent all twelve documented fields
for each of six DOFs; SDVE sent the fourteen Request-Example fields from
THICKNESS through KINETIC_FRIC. Both fixtures are now confirmed and their
coverage entries are write-level on both products. The old Wrong Field
finding is superseded by this manual-backed rerun, not hidden by a weaker
payload.
The built npm package's public resources.db entries completed the same two
full CRUD cycles on each product from a fresh /doc/NEW document. That adds
SDVI and SDVE to the npm harness evidence without changing the Python-only
meaning of docs/coverage.json's level field.
After this batch, each latest scratch document was saved under C:/temp with
its product-native extension, then /doc/NEW was issued. Final read-only
checks found NODE=0 and ELEM=0 on both Gen and Civil, so both open documents
are empty.
Hydration SOLID-fixture re-check: HAHS and HECB (2026-09-01)¶
The previous HAHS and HECB failures were deliberately re-run with a real
dummy model, not the baseline frame/plate fixture. The fixture follows the
official /db/ELEM manual's eight-node hexahedral SOLID form
(TYPE="SOLID", MATL=1, SECT=0) and creates the needed nodes, element,
real structure group, boundary group, functions, and construction stage from
an empty /doc/NEW document.
/db/HAHSused an isolated SOLID at element 50. Both Gen and Civil completedPOST -> GET -> PUT -> GET -> DELETE(id) -> GET; the heat-source function changed fromHSFC_SEEDtoHSFC_SEED_2on readback./db/HECBinitially still failed when itsITEMS[].IDwas changed to 51. The manual calls this value a serial number, so the final fixture retainedID=1and made the first element itself the SOLID. With that model and a real activated construction stage, both products completed the same full CRUD cycle, including a persistedFACE_NOchange from 1 to 2. The earlier "element no. 1" response was therefore a fixture symptom, not evidence to reinterpret the documented field as an element id.
These runs used MIDAS Gen NX 2026 v2.1 and MIDAS Civil NX 2026 v2.2, both
build 08/26/2026. Reports and saved scratch checkpoints are under C:/temp;
each product was returned to a new empty document after the run.
Pipe-cooling SOLID-fixture re-check (2026-09-01)¶
/db/HPCE was re-tried before calling its existing Wrong Key result a
product defect. Each product started from a new scratch document with the
same manual-backed 8-node hexahedral SOLID used for HAHS/HECB. The exact
documented payload was then posted with its ITEMS array populated by that
SOLID's real nodes: first all 8 nodes, then the 6-node length used by the
manual Request Example. Gen was also tried with 4 and 2 of those real nodes.
Every attempt returned the identical Wrong Key response on Gen NX 2026 v2.1
and Civil NX 2026 v2.2, build 08/26/2026. This eliminates the earlier
frame/plate-node fixture as the explanation, but does not license an invented
wire shape: the manual and current /info both state ITEMS is an integer
array. HPCE therefore remains read-level/unconfirmed pending product evidence
or corrected documentation. The latest scratch checkpoints are under
C:/temp, and both sessions were reset to an empty document afterwards.
STCT documented Linear/Independent branch re-check (2026-09-01)¶
The original STCT fixture put the linear-only iITER/TOL fields beside the
Accumulative stage choice (iNLA_TYPE=1). The manual instead assigns those
fields to the Linear + Independent branch, so a fresh scratch model with a
real construction stage was tested on both products with
iINC_NLA=0, iNLA_TYPE=0, iITER=30, and TOL=0.01.
The result is the same defect on the correct branch: Gen NX POST echoes both values but its first GET omits them; Civil NX's stage creates the locked default record as before, and PUT echoes both values but its following GET omits them. Thus this is not a branch-selection or dummy-model issue. The live fixture now uses the documented Linear/Independent combination and remains unconfirmed; the two fields cannot currently be verified as persisted. Both products were MIDAS Gen NX 2026 v2.1 / Civil NX 2026 v2.2, build 08/26/2026, and were reset to empty scratch documents afterwards.
Seismic-device fixture completion: SDHY and SDIS (2026-09-01)¶
The reusable Gen-only extras6 fixture had drifted behind the corrected
official manual: SDHY still sent only COMMON, SDHY_HYS_MODEL, MSS, and
K0, omitting the documented P1, P2, ALPHA1, ALPHA2, BETA, Phi,
and LAMBDA fields. It now sends the complete current Request Example.
From a new saved scratch document, the public Python resources completed all
five seismic-device cases. In particular, /db/SDHY persisted K0 from 5000
to 6000 and /db/SDIS used the manual's successful SDIS_DEV_TYPE="SLD"
branch with its SB object, persisting KV from 150000 to 160000. Each did
POST -> GET -> PUT -> GET -> DELETE(id) -> GET; the prior LRB Wrong Field
finding is intentionally not hidden or reclassified by this endpoint-level
SLD success. Gen NX 2026 v2.1 build 08/26/2026 was reset to an empty document
after the run; SDHY and SDIS are Gen-only declared endpoints.
The built npm package independently repeated /db/SDHY and /db/SDIS through
the public resources.db API (npm run live:crud, not raw HTTP) on the same
Gen NX build. Both completed their full CRUD cycles from a separately saved
and newly created scratch document, which was left empty by the harness.
Dynamic-load fixture completion: SPLC and THMS (2026-09-01)¶
The remaining extras5 failures were also abbreviated fixtures, not product
findings. /db/SPLC had retained only five core fields even though the manual
no-damping Request Example also supplies ANGLE, bDAMP, INTERP,
COMTYPE, bADDSIGN, iSIGNTYPE, bMODE, and three aUSEMODE entries.
/db/THMS had sent only its X-direction function while the worked example
includes the Y/Z functions and all three arrival-time fields.
With the complete manual shapes and real SPFC_SEED, THIS_SEED, and
THFC_SEED prerequisites in new scratch models, both endpoints completed
POST -> GET -> PUT -> GET -> DELETE(id) -> GET on Gen NX and Civil NX.
SPLC persisted SCALE 1.0 to 1.2; THMS persisted SCALEX 1.0 to 1.5.
This supersedes the former Gen-only SPLC Unknown Error and cross-product
THMS Wrong Field observations. Both products were Gen NX 2026 v2.1 / Civil
NX 2026 v2.2, build 08/26/2026, and the harness returned both documents to an
empty state after each run.
CSCS composite-section fixture boundary (2026-09-01)¶
/db/CSCS was rechecked on both products from a new scratch model with the
manual's minimum construction-stage record and the complete documented CSCS
part-information body. The request was sent with the required Assign
envelope. Gen NX and Civil NX both rejected the base model section at
Item:Section Type, which is expected: the manual says this route requires a
COMPOSITE section.
The only manual COMPOSITE/SOD_BOX sample available for the prerequisite
section omits the dimensions needed for a valid section; Gen NX rejects that
literal sample with Section Dimensions has(have) been incorrectly entered.
The missing geometry is not supplied by the /db/CSCS chapter, so the test
does not invent it or infer it from either SDK. CSCS therefore remains
read-level/unconfirmed pending a complete manual composite-section fixture or
new live evidence. Both products were reset to empty scratch documents after
the probe (Gen NX 2026 v2.1 and Civil NX 2026 v2.2, build 08/26/2026).
Hyper-S /info schema artifact capture (2026-09-02)¶
Civil NX's relay reported program civil. Read-only GET /info/db/... calls
captured the complete response bodies in schema/hyper-s-info.json; no model
GET response body was captured and no model data was changed. The top-level
Argument.properties fields match the two earlier prose probes exactly:
MATL-M1 has MATL_NAME, MATL_TYPE, DAMP_RAT, and PARAM; EPMT-M1 has
NAME, MODEL_TYPE, TRESCA, VMISES, MOHRCL, DRUCKER, MASONRY, and
CONCDMG; IMFM-M1 has CONCRETE and STEEL; IEHG-BEAM-M1 has
INEL_PROP_NAME; and contracted STYP-M1 has STYPE, GRAV, TEMP,
ALIGNBEAM, ALIGNSLAB, and MASS_CONTROL.
GET /info/db/IEHG-TRUSS-M1, /info/db/IEHG-GL-M1, and
/info/db/IEHG-PSS-M1 each returned the expected 404. The split still holds:
they serve GET but expose no introspection schema, so their assumed
INEL_PROP_NAME shape remains labelled as sibling analogy rather than live
schema evidence.
/db/STYP-M1's contract and its /info schema were written from different sources and agree exactly (2026-09-02)¶
schema/hyper-s-info.json deliberately includes /db/STYP-M1, which is not
one of the seven uncontracted stubs. It is the one Hyper-S endpoint with a
real manual section, so its contract was derived from the Specifications
table with no reference to introspection - which makes the captured schema an
independent check on it rather than a restatement.
They agree on all ten paths, type for type:
| path | /info |
contracts/endpoints/db-styp-m1.yaml |
|---|---|---|
STYPE |
string | string |
GRAV |
number | number |
TEMP |
number | number |
ALIGNBEAM |
boolean | boolean |
ALIGNSLAB |
boolean | boolean |
MASS_CONTROL |
object | object |
MASS_CONTROL.MASS_TYPE |
string | string |
MASS_CONTROL.MASS_POS |
string | string |
MASS_CONTROL.SELFWEIGHT |
boolean | boolean |
MASS_CONTROL.MASS_AXIS |
string | string |
The four nested members are the point. The manual never writes the path
MASS_CONTROL.MASS_TYPE; it numbers those rows 2-(1) through 2-(4) under
a row named MASS_CONTROL and leaves the reader to infer the nesting. The
contract carries four notes saying exactly that, and the server's own schema
now confirms the inference was right.
That is a statement about the extractor, not just this endpoint. Rebuilding a structure the manual addressed by numbering is the most common finding in the whole contract set - 592 of them across 95 contracts - and this is the first time one has been checked against a source that states the path directly.
The /info schemas are malformed in two ways (2026-09-02)¶
Captured verbatim, so both are in schema/hyper-s-info.json as served:
apostrophes inside description strings are escaped \', which is not a JSON
escape (8 occurrences), and maxItems is stated on an array's items
subschema rather than the array (4 occurrences on /db/MATL-M1). Registered
as MD-12; a contract written from this artifact must not transcribe
either.
What the capture did not record¶
The session's Civil NX build string. schema/hyper-s-info.json carries
"nxVersion": null and says so rather than naming a build it does not have,
and the eight docs/coverage.json entries keep the nx_versions of the
sessions that set their level. Every other live record in this repo carries a
build; re-stamp this one on the next Civil NX session rather than inferring
it from the dates around it.
2026-09-02 (later) — an /info sweep of the 18 endpoints no contract could reach¶
Read-only GET /info/db/... for every remaining uncontracted /db/* resource,
on each product it declares: 27 probes, all answered. Captured verbatim in
schema/info-schemas.json. No /doc/NEW, no write, and no GET response body
recorded, so nothing here is model data. Both sessions verified as
sjj0507@midasit.com; neither product's build string was recorded, and the
artifact says so rather than naming one.
Each of these endpoints was blocked by an ambiguity the manual states but does not resolve. The server resolves most of them outright.
/db/TDME: the duplicate "SCALE" is a wrong key, and the right one is aDATA¶
MD-13. The Specifications table gives "SCALE" to both "Scale Factor"
(Number) and "Function Data" (Array of {TIME, COMP, TENS, ELAST}), and the
vendored manual's own ⚠️ callout says there is no example to tell them apart.
There is now:
Row 5 is right and row 6's key is wrong: the array is aDATA. Civil and Gen
return byte-identical schemas. This is the manual's error to fix, not a choice
between two documented names, and it closes MD-13.
Three compact key rows name real, separate fields¶
| endpoint | the manual's one cell | what /info lists |
|---|---|---|
/db/MVLDeu |
"SCALE_FACTOR1"/"SCALE_FACTOR2"/"SCALE_FACTOR3" |
all three, each number |
/db/STCT-M1 |
bSDLE" / "vSDLE |
bSDLE boolean, vSDLE array of names |
/db/THIS-M1 |
FREQ1/PERIOD1 |
DAMPING.FREQ1, DAMPING.FREQ2, DAMPING.PERIOD1, DAMPING.PERIOD2 |
/db/THIS-M1's is the most useful: the row names two of four real fields, and
they are nested under DAMPING rather than at the root, which the table never
says.
/db/POGD's refused cell is different in kind - AIK-G-001-2021 is a design
code name, not a wire property, and none of the endpoint's nine real
properties is called anything like it.
/db/REBW's field names, confirmed a third time and in full¶
GET /info/db/REBW returns one ITEMS array whose members are ID,
bUSE_MODEL_THICK, THICK, DW, DE, VER_BAR, HOR_BAR, END_BAR,
NUM_END_BAR, BE_HOR_BAR, BE_LENGTH, vSTORY_NAME. That matches the
2026-07-29 live PUT round trip exactly and adds the four the round trip never
touched. The manual's Specifications table names none of them.
/db/PRES and all four /db/REB* endpoints are the same shape: a single
ITEMS array with everything inside it.
/db/POGD is not the same endpoint on both products¶
The only pair in the sweep whose two schemas differ. Same nine top-level keys,
but NONL_OPT and PHOP_OPT carry different members - Gen's PHOP_OPT opens
with bCONSREBARAREA1D and BEAM_CORE_SIZE (fiber-model options), Civil's
with bASSIGNBYMEMBER and bTRI_SYM. A contract for /db/POGD has to tag
those members by product; a single shape would be wrong on one of them.
Every other both-product endpoint returned byte-identical schemas on Gen and
Civil - eight pairs, which is also the first systematic check that /info
itself agrees across products.
Superseded in part, 2026-09-04. "The only pair in the sweep" was accurate about a sweep of nine endpoints, and it is not true of the API.
scripts/info_baseline.py --divergenceasks the same question of all 177 pairs that answer/infoon both products and finds ten that differ:/db/ACTL,/db/BCCT,/db/EPSE,/db/IEHC,/db/POGD,/db/POLC,/db/POSL,/db/SBDO,/db/SPLC,/db/THGC./db/SPLCdiffers by fifteen fields and/db/POGDby twenty, so this one was not even the widest. What stands is the conclusion drawn from it - "a contract has to tag those members by product; a single shape would be wrong on one of them" - which is now done for nine of the ten. See MD-46.
2026-09-03 — /db/TDME's code-name branches, tested one at a time¶
Both documents were confirmed empty first — GET /db/NODE, /db/ELEM,
/db/MATL and /db/TDME all answered {"message": ""} on Gen NX and Civil NX
— so no /doc/NEW was needed and none was called. Every record created was
deleted by its own id, and both tables end empty.
The manual splits /db/TDME into eight "전용 추가 필드" tables, one per group of
CODENAME values, and the extractor refuses to promote a contract from them
because nothing says what review decided about the split. This tests the split
directly. Payloads come from the section's own tables, and the KDS-2016 case
is the manual's Request Example copied verbatim.
The manual's Required is not the product's, and it differs per branch¶
CODENAME |
sent | result |
|---|---|---|
CEB-FIP(2010) |
base fields only | stored, server filled iCTYPE |
European |
base fields only | stored, server filled iCTYPE: 2 |
Russian |
base fields only | rejected, "input data contain errors" |
ACI |
base fields only | rejected, "input data contain errors" |
KDS-2016 |
base fields only | rejected, "input data contain errors" |
KDS-2016 |
+ iCTYPE: 1, DENSITY: 230 |
stored |
Every one of those extra fields is marked Required in its branch table. For
CEB-FIP(2010) and European the server supplies a value instead of refusing,
and for ACI, Russian and KDS-2016 it does refuse. That is exactly the
documentedOptional / safeToOmit split this repo keeps as two booleans: the
documentation's claim is uniform, the product's behaviour is not.
Identical on both products, checked case for case.
Two of the documented code names belong to a different product¶
Japan(hydration) and Japan(elastic) — entries 16 and 17 of the chapter's own
CODENAME table, each with its own branch of extra fields — answer
Wrong Field on Gen NX and Civil NX. Seven spellings were tried
(Japan(hydration), Japan(elastic), Japan (Hydration), JAPAN(HYDRATION),
Japan(Hydration), Japan(Elastic), bare Japan); all seven, both products.
The refusal is correct and the search was misdirected. Those two codes are iGen's, and this API is not talking to iGen (author, 2026-09-03). Nothing is wrong with the product.
Two things are worth keeping from it. The chapter's code table mixes another
product's values into a list it presents as this endpoint's, with no marking —
recorded as MD-14, owned by the manual repo. And this file's own diagnostic
rule, Wrong Field = "the value is unknown, vary the value not the fields",
is true but incomplete: it points at spelling, and the answer here was not a
spelling. A value the product has never heard of and a value that belongs to a
sibling product produce the identical error, so after two or three spellings
the next question is which product the value is from, not which capitalisation.
/info/db/TDME lists every field those two branches require
(TENS_STRN_FACTOR, bUSE, A, B, D, iCTYPE, iECTYPE), so the
endpoint's schema is shared across products even where the code names are not.
The server renumbers a posted record, and it cost a cleanup pass¶
POST /db/TDME under key 901 echoed {"TDME": {"901": {...}}} and then
stored the record as id 1. The first probe's cleanup keyed off the id it had
posted, found nothing, and left eight records behind; a second pass deleted
them by the ids a GET actually reported. This is the same behaviour recorded
for /db/STLD in 2026-07-26 (a POST under key 7 produced id 3), so it is a
/db/* property and not news — but a harness that deletes by the id it sent
will silently fail to clean up. Match on a field you set, then delete by the id
the table reports.
2026-09-03 (later) — /db/PRES: B-4 measured, with the error string¶
The last surviving claim of the vendor report's section B, tested against a
real plate. The Gen document was confirmed empty first, seeded with
live_crud_check.py's own _seed_model — the repo's confirmed payloads, not a
hand-written model — and every record deleted by id afterwards. /doc/NEW was
neither needed nor called; all nine tables the seed touches read
{"message": ""} at the end.
Element 4 is the seed's plate. ELEM_TYPE: "PLATE", FACE_EDGE_TYPE: "FACE",
EDGE_FACE: 1, FORCES: [-10, -10, -10, -10], varying only DIRECTION:
DIRECTION |
result |
|---|---|
| omitted | rejected — [Error] Errors detected in Pressure Loads Data.(Item:Load Direction) |
"NORMAL" |
rejected — same message |
"LZ" (local z) |
stored |
"GZ" (global Z) |
stored |
B-4 holds, and both halves of the row are wrong for this combination.
DIRECTION is marked Optional with default "NORMAL"; omitting it fails,
and the default it names is the one value this combination refuses. The
official article's footnote availability matrix already said so — Normal is
- for PLATE + FACE while Local x/y/z and Global X/Y/Z are O — so the
matrix and the product agree and only the Specifications row is out of step.
That is the whole of what survived section B's re-audit, now with a reproduction and the exact error text rather than an inference.
The Assign key is what selects the element¶
The first attempt sent {"Assign": {"1": {"ITEMS": [{"ID": 4, ...}]}}} — the
plate named in ITEMS[].ID, under key 1 — and was refused with
[Error] The element no. 1 is an element type in which Pressure loads cannot be
assigned, which is true of the seed's beam 1 and not of its plate 4. Moving
the payload to key 4 stored it.
So the server resolved the element from the Assign key, and ITEMS[].ID
echoed back. DbResource.create() already keys by id, so both SDKs send this
correctly; what the run corrects is the reading of the confirmed fixture, whose
ID field looks like the selector and is not.
2026-09-03 (later still) — what the manual's "Create Only" actually means¶
Create Only appears in exactly two Required cells in the whole manual, and
both are a field named CALC_OPT: /db/SECT's SECTTYPE: "VALUE" branch
(default true) and /db/SPFC's design-spectrum branch (default false).
The extractor does not recognise the value and emits a note instead of a
requiredness, so /db/SECT and /db/SPFC have both been sitting on it.
Measured on Gen NX against an empty document, with every record deleted by id
afterwards. /doc/NEW was neither needed nor called.
The two rows say the same thing and the product means two different things by it. That is the finding: "Create Only" cannot be read off the manual into a contract as one shared semantic, because the manual's own two uses of it do not agree with each other.
/db/SECT — literal, and it leaves stale stiffness behind¶
CALC_OPT is not a stored property. No GET on any of the seven sections
created here returned the key. What it does is decide whether the server
computes SECT_I.STIFF (AREA, ASY, ASZ, RXX...) and SECT_I.DESIGN
from vSIZE, and it decides that only on POST:
| POST | STIFF in the body |
result |
|---|---|---|
CALC_OPT omitted |
absent | computed from vSIZE |
CALC_OPT: true |
absent | computed from vSIZE |
CALC_OPT: false |
absent | refused - [Error] Section input data contain errors. |
CALC_OPT omitted |
present | stored verbatim |
CALC_OPT: true |
present | stored verbatim |
CALC_OPT: false |
present | stored verbatim |
So the documented default true is confirmed, and false is a real gate — it
forbids the computation, which is why it fails when there is nothing to fall
back on. But a supplied STIFF wins under every value, including true:
AREA: 0.999 on a 0.3 m H section was stored as 0.999.
The asymmetry that names the row is exact. The identical body that POST refuses is accepted as a PUT:
POST {"CALC_OPT": false, ...no STIFF} -> [Error] Section input data contain errors.
PUT {"CALC_OPT": false, ...no STIFF} -> accepted, record keeps the STIFF it had
And CALC_OPT: true on a PUT does not compute anything:
| step | vSIZE[0] |
STIFF.AREA |
|---|---|---|
POST, CALC_OPT omitted |
0.3 | 0.004533 (computed) |
PUT to 0.9, STIFF stripped, no CALC_OPT |
0.9 | 0.004533 |
PUT to 0.9, STIFF stripped, CALC_OPT: true |
0.9 | 0.004533 |
| POST a fresh section at 0.9 | 0.9 | 0.008433 |
A section deliberately corrupted to AREA: 0.777 stayed at 0.777 through a
PUT with CALC_OPT: true and STIFF stripped.
⚠️ Resizing a VALUE section through PUT leaves the model carrying the new
dimensions with the old section properties — 200, no error, and the record
reads back looking self-consistent unless the caller knows what AREA should
have become. Same silent-corruption family as /db/CONS truncating an
8-character CONSTRAINT and /db/MVHL's empty VEH_DEFAULT no-op. Deleting
and re-POSTing is the only way to recompute through the API.
/db/SPFC — the same words, and "Create Only" is wrong¶
Here CALC_OPT: true is what makes the server build the 103-point aFUNC
spectrum from the code parameters in STR/OPT/VAL. Omitted or false
with no aFUNC supplied is refused:
Which means the manual's own KDS(41-17-00:2019) worked example does not
run — it omits CALC_OPT and supplies no aFUNC. Registered as MD-15.
Unlike /db/SECT, CALC_OPT is fully honoured on PUT. Starting from a record
whose aFUNC had been hand-set to a 2-point flat curve at 0.5, against code
parameters that generate a peak of 0.0528:
PUT (aFUNC stripped each time) |
stored aSRA |
stored curve |
|---|---|---|
CALC_OPT: true |
[0.22, 0.154] | 103 pts, peak 0.0528 - recomputed |
CALC_OPT: false, aSRA doubled |
[0.44, 0.308] | 103 pts, peak 0.0528 - untouched |
CALC_OPT omitted, aSRA doubled |
[0.44, 0.308] | 103 pts, peak 0.0528 - untouched |
true on a PUT rebuilt the curve; false and omission left it alone. So the
documented default false is confirmed for this endpoint too, and the
Create Only cell is simply not true of it.
Rows two and three are the stale-derived-data shape again, in a milder form:
new code parameters can be stored against a curve they do not generate. Here,
unlike /db/SECT, the caller has a fix — resend with CALC_OPT: true.
/db/SPFC also renumbers a POSTed record, joining /db/STLD and /db/TDME.
2026-09-03 (later still) — /db/MVHL: the finding was real, the reading was not¶
VEHICLE_LOAD_NUM has been quoted in three places in this repo as a
documented value that is wrong live, and as a silent-data-corruption case
alongside /db/CONS. Measured properly on Civil NX, it is neither. It is
the endpoint's branch discriminator, and it does exactly what the manual's own
worked examples show.
VEHICLE_LOAD_NUM |
companion fields | result |
|---|---|---|
1 |
VEHICLE_TYPE_NAME + STANDARD_CODE |
stored intact - standard DB vehicle |
2 |
USER_LOAD_TYPE + LOAD_ITEMS |
stored intact - all three axle loads kept |
2 |
VEHICLE_TYPE_NAME + STANDARD_CODE |
branch-1 fields discarded, user-defined Truck/Lane stored |
1 |
no VEHICLE_TYPE_NAME |
refused - (Item:Length of Vehicular Load Type(0 ~ 40 characters)) |
3 |
- | refused - Wrong Field |
| omitted | - | refused - Wrong Field |
Row three is the 2026-07-26 observation, reproduced exactly. What it shows is
not a product discarding a caller's data: it is branch 2 ignoring branch 1's
fields, which is what selecting branch 2 means. The manual has said so since
2026-07-30, when the KSCE-LSD15 article added a User Defined example carrying
"VEHICLE_LOAD_NUM": 2 with USER_LOAD_TYPE and no VEHICLE_TYPE_NAME.
Sent properly, branch 2 is not lossy at all — LOAD_ITEMS' three axle loads
came back field for field.
This is the fourth finding in the same family as the retracted B-1/B-2/B-3 and the iGen code names: a real observation, correctly recorded, with a conclusion about the manual that the source did not support. The observation was made before the branch was documented, and nobody re-read it afterwards.
What is actually wrong is narrower, and it is requiredness¶
The common Specifications table marks every branch-1 and branch-2 field without reference to the branch. Measured:
| field | table says | measured |
|---|---|---|
VEHICLE_TYPE_NAME |
Required | required only when VEHICLE_LOAD_NUM: 1 |
STANDARD_CODE |
Required | not required at all - omitted, accepted, stored without it |
USER_LOAD_TYPE |
Optional | ignored on input under MVLD_CODE: 2; the server always stored "Truck/Lane", for "Train", "Lane", "Truck", "TruckLane" and omission alike |
Same shape as /db/FIMP's table stating child keys without their parents.
Registered as MD-16. STANDARD_CODE confirms by a write what
VehiclePayload's docstring already recorded from a read of a real Eurocode
model: its Load Model 1 entry carries no STANDARD_CODE key at all.
Two things that are not validated on write¶
STANDARD_CODEis checked against its own enum —"NOT-A-CODE"answersWrong Field— but not against the vehicle or the moving-load code."KS-RB"was accepted and stored on anMVLD_CODE: 2(AASHTO LRFD)HL-93TRKvehicle.VEHICLE_TYPE_NAMEis not validated at all."NOT-A-VEHICLE"was accepted and stored verbatim. Since that name is what selects which standard vehicle's axle loads the analysis uses, a typo here is silent.
/db/MVHL renumbers a POSTed record too — keys 10-14, 20, 21 landed at ids
4-10.
2026-09-03 (patch) — build 09/02/2026 on both products, and a read-only sweep from each SDK¶
The author installed the latest patch mid-session and read the build off each product's About dialog:
| product | version | build |
|---|---|---|
| MIDAS Gen NX 2026 | v2.1 | 09/02/2026 |
| MIDAS Civil NX 2026 | v2.2 | 09/02/2026 |
The API still does not report this. /mapikey/verify answers only
{"user", "program", "connectionID", "keyVerified", "status"}, and
/doc/VERSION, /doc/INFO, /version and /doc/ABOUT all 404 on both
products after the patch as before it. So the About dialog remains the only
source, and a build string can only be attached to a session someone was
watching. That is why the four records written earlier today say the build is
unknown rather than citing 09/02/2026: those runs happened before this patch
was installed, and back-stamping them with a build that did not exist yet
would turn a gap into a false citation. schema/info-schemas.json and
schema/hyper-s-info.json keep nxVersion: null for the same reason.
Both sessions survived the patch: the connectionIDs (tZwG5G-fSg for Gen,
maTuEDSLQw for Civil) were unchanged afterwards.
The sweep, run from a different SDK per product¶
Deliberately split, so each language surface drove a real product rather than both being checked by the one that is easier to script:
| product | driver | resources | result |
|---|---|---|---|
| Civil NX | Python, scripts/live_readonly_sweep.py |
282 GET-capable | 282 ok, 0 failed |
| Gen NX | npm, the built dist/ walked resource by resource |
268 declare gen, 267 serve GET | 267 ok, 0 failed |
No route moved, disappeared or changed shape across the patch, on either product or through either SDK.
On Gen, 261 tables were empty and six carried data — /db/UNIT, /db/STYP
and the four colour tables /db/CO_F, /db/CO_M, /db/CO_S, /db/CO_T.
Those are what any document has: units and a structure type are not optional,
and the colour tables are product defaults. They are not residue from this
session's earlier write probes, all of which were deleted by id and confirmed
empty before the patch went on.
The npm sweep was written for the session at first, because
packages/typescript/scripts/ carried only live-crud.mjs and
live-analysis.mjs, both of which call /doc/NEW and discard unsaved work -
so the npm package had no safe harness at all. [Corrected 2026-09-20: only
live-crud.mjs calls /doc/NEW. live-analysis.mjs never has - git log -S
finds no newProject in it, ever. It is still unsafe against a model you care
about, because it adds a column to the open document and runs a solve before
deleting what it added, but it does not discard the document. The conclusion
this paragraph draws - that the npm package needed a GET-only harness - is
unaffected.] It has one now:
packages/typescript/scripts/live-readonly.mjs, npm run live:readonly,
committed the same day and re-run against both products to the same counts.
Having one per SDK is not duplication. Each imports its own package, so a wrong endpoint string, a wrong product gate or a broken response unwrapping in that package answers 404 there and nowhere else - the Python sweep cannot see an npm defect. That the two agree exactly (282 Civil, 267 Gen) is itself the cross-check.
2026-09-03 (patched build) — MD-14's two Japan code names, re-measured on 09/02/2026¶
The earlier /db/TDME probe ran before the 09/02/2026 patch was installed, so
its build was never recorded. This re-runs the narrow part of it against a
build both About dialogs name — MIDAS Gen NX 2026 (v2.1) and MIDAS Civil NX
2026 (v2.2), both build 09/02/2026 — because "we do not know which build that
was" is a weak place to leave a claim that a documented value does not work.
Both documents were confirmed empty first (GET /db/NODE, /db/ELEM,
/db/MATL, /db/TDME all {"message": ""}), so no /doc/NEW was needed or
called. The payload is live_crud_check.py's confirmed /db/TDME case with
CODENAME varied and nothing else. Both tables were empty again afterwards,
each record deleted by the id a GET reported.
| sent | Gen NX | Civil NX |
|---|---|---|
CEB-FIP(2010) (control) |
stored | stored |
Japan(hydration), name only |
Wrong Field |
Wrong Field |
Japan(hydration) + TENS_STRN_FACTOR, bUSE, A, B, D |
Wrong Field |
Wrong Field |
Japan(elastic), name only |
Wrong Field |
Wrong Field |
Japan(elastic) + iECTYPE |
Wrong Field |
Wrong Field |
MD-14 stands, on a build that is now on the record. The control stored on both products in the same session, so the write path was working and the refusal is about the value.
One thing is new. The earlier pass varied only the spelling — seven of
them. This pass supplied each branch's own documented companion fields as well,
and the answer did not move: still Wrong Field, never [Error] ... input data
contain errors. Those two error strings are this file's standing diagnostic
pair — the second means the value was recognised and its companions were wrong.
Getting the first with the companions present rules out the remaining reading
in which the code name is known and only its extra fields were missing. What
is left is the value itself being unknown to this API, which is what "these are
iGen's" predicts.
A live call cannot confirm why, and this one does not try to. That the two codes belong to iGen is the author's knowledge (2026-09-03); what a probe can establish is that the refusal is real, reproducible on a known build, on both products, and not an artefact of the companion fields. It is.
2026-09-03 (patched build) — the three uncontractable Hyper-S endpoints, re-checked¶
"Uncontractable in principle" is a strong claim, and it was resting on an
/info capture dated 2026-09-02 — the day before the 09/02/2026 patch went on.
Re-probed on the patched build. GET only.
| Civil NX v2.2 | Gen NX v2.1 | |
|---|---|---|
/info/db/IEHG-BEAM-M1 (control) |
schema returned | 404 |
/info/db/MATL-M1 (control) |
schema returned | 404 |
/info/db/IEHG-GL-M1 |
404 | 404 |
/info/db/IEHG-PSS-M1 |
404 | 404 |
/info/db/IEHG-TRUSS-M1 |
404 | 404 |
GET /db/IEHG-{GL,PSS,TRUSS}-M1 |
{"message": ""} |
404 |
Nothing moved. The claim stands, and now on a build that is on the record.
The controls are what make that worth writing down. /info/db/IEHG-BEAM-M1 —
the sibling in the same family, same chapter, same product — answers in the
same session, so the 404 on the other three is a property of those three
endpoints rather than of the session, the key or the build.
Two things this re-confirms rather than discovers. The routes themselves are
served on Civil: GET /db/IEHG-GL-M1 answers {"message": ""}, so these are
real endpoints with no schema route, not absent ones — already recorded, and
still true. And Gen 404s on every row including both controls, which is
HYPER_S_ONLY behaving as db/base.py documents.
So the three keep no permitted source: the manual gives them a URL and a
methods line, /info gives nothing, and this repo does not read a request
shape out of an SDK. They stay uncontracted until one of those changes.
2026-09-03 (patched build) — the standing write failures, re-asked¶
A new build can fix things, so the failures this repo carries forward were
re-asked rather than assumed. Payloads come from schema/live-cases.json, the
committed fixture the harness emits; none of these six declares a needs seed,
so a direct probe reproduces what the harness would send. No /doc/NEW — the
tables were checked empty first, and a refused write changes nothing.
| endpoint | Civil NX v2.2 | Gen NX v2.1 |
|---|---|---|
/db/NLLP |
Unknown Error |
Unknown Error |
/db/WVLD |
Wrong Field |
not declared for Gen |
/db/GRDP |
Wrong Field |
Wrong Field |
/db/TDMF |
Wrong Field |
Wrong Field |
/db/RPSC |
Wrong Field |
Wrong Field |
/db/STRPSSM |
Wrong Field |
not declared for Gen |
/db/REBB (empty item) |
not declared for Civil | Wrong Field |
Nothing was fixed by the patch. Every one reproduces, with the same message as before.
Two of these are root-caused and five are not, and the difference matters.
/db/NLLP was bisected on 2026-08-31 to a single field across four
(APPLICATION_TYPE, APPLICATION_TYPE_D) combinations, all answering the
identical Unknown Error; /db/REBB was tested down to a literally empty item
on 2026-08-27, which cannot contain a wrong field. Those two are product-side
by elimination. /db/WVLD, /db/GRDP, /db/TDMF, /db/RPSC and
/db/STRPSSM are confirmed=False cases whose cause has never been isolated —
this repo's own rule is that an unconfirmed failure is not an SDK defect until
someone triages the fixture, and across three earlier runs most such failures
turned out to be a fixture or a wrong documented value rather than the product.
Re-running them proves the symptom survives the patch. It does not promote any
of the five to a product defect, and this entry is not evidence for that claim.
What the re-check is worth: db-rebb-write-path-refuses-every-payload now has
a lastChecked on a build that is on the record, and the five unconfirmed
cases are known to be still worth triaging rather than possibly already fixed.
2026-09-04 — /db/NMAS's crash does not reproduce, on either product¶
Re-test of the 2026-07-29 root cause, at the author's explicit request and with
explicit consent that a crash was acceptable. Civil NX 2026 v2.2 and Gen NX
2026 v2.1, both build 09/02/2026 — see the build note at the end of this entry. It did not crash. Roughly 500
omitted-rmX/rmY/rmZ writes across both products, in three escalating
rounds, and neither session ever stopped answering.
Both documents were confirmed empty first — /db/NODE, /db/ELEM and
/db/NMAS all returned the empty-table {"message": ""} — so /doc/NEW was
never called and there was no unsaved work at risk. Every payload came from
scripts/live_crud_check.py's confirmed cases rather than being hand-written.
verify_connection() was not used as the liveness probe, because the relay
answers "connected" while a modal dialog holds the product; each probe is a
GET /db/NODE with a 20s timeout.
| Round | What it did | Civil NX | Gen NX |
|---|---|---|---|
| 1 | control (NodalMass.create, rm* filled) then 8 omission variants on fresh nodes: all three omitted, mX alone, rmZ alone missing, rmX alone missing, empty record, PUT |
alive | alive |
| 2 | 200 sequential POSTs with rm* omitted, one per fresh node, probing every 50 |
alive | alive |
| 3 | an eight-node frame with real BEAM elements and a constraint, rm* omitted on every connected node, then 40 PUT/DELETE/POST cycles |
alive | alive |
Round 3 exists because round 2 did not test what it claimed to. Its element
seed failed Key Already Exist on nodes that round 1 had already created, so
the elements were never made and the "connected node" writes went to nodes that
did not exist — which is what the Unknown Error replies in that round mean.
Rebuilt on an untouched id range, the frame came up with 8 elements on Civil and
10 on Gen, and the omission still did not crash either.
The server now applies the documented default, on both products. The write
response is a poor witness: a full-fields POST echoes all six fields back, an
omitted-fields POST echoes back only what was sent, and reading the echo alone
suggests the record is stored without them. It is not. GET /db/NMAS/3002 on a
record written with rm* omitted returns
{"mX": 10, "mY": 10, "mZ": 10, "rmX": 0, "rmY": 0, "rmZ": 0} — identically on
Civil and Gen. So the default is applied; the write response just does not
report it. This confirms the 2026-08-13 finding, which saw the same thing on
Civil NX v2.2 build 08/12/2026 on one installation, and extends it to Gen.
Worth naming the trap, because this session fell into it: the response body of a write is what the server accepted, not what it stored. Only a read says what was stored.
One long call is worth recording. In round 2 on Civil, one of the 200 writes took 21.7 seconds while every other call in the same run was ~0.1s. That is inside the 15–60s window the crash used to present as, and it is the only trace of the old behaviour seen all day. It did not recur, and the session answered normally immediately afterwards. Not evidence of anything on its own; recorded because a latency spike in exactly that range on exactly that call is not a coincidence worth discarding either.
The workaround stays. NodalMass.create()/.update() still fill
rmX/rmY/rmZ with 0.0, and contracts/safety/known-product-risks.yaml
still carries the risk. Three reasons, in order of weight: one clean session on
one build on one machine does not overturn 15+ reproductions across multiple
versions, builds, models and calling machines; the products auto-update, so an
SDK release cannot assume its users are on this build or later; and the
workaround costs a caller nothing, since it sends the values the manual already
documents as the default. This repo's own rule applies — a mitigated crash risk
is still a crash risk, and risk and mitigation are separate axes.
The build is on the record: Civil NX 2026 v2.2 and Gen NX 2026 v2.1, both
build 09/02/2026. The author confirmed it, and the session evidence agrees
independently. verify_connection() returned connectionID maTuEDSLQw for
Civil and tZwG5G-fSg for Gen today — the same two ids the 2026-09-03 patch
entry recorded after the author read the build off each About dialog. A
connectionID does not survive a product restart, so both processes have been
running continuously since that reading, which is also why no auto-update can
have slipped in between. The API still reports no version itself
(/doc/VERSION and /doc/INFO 404, as that entry documents), so this is the
strongest anchor available short of reading the dialog again, and it is a
checkable one rather than an assumption.
That makes this a build MIDASIT can be given a name for. The 2026-08-13 observation was Civil NX v2.2 build 08/12/2026 on one installation; this is both products on 09/02/2026.
What this does not establish. Not that the defect is fixed: an uninitialized-value read is exactly the kind of bug that hides when memory happens to be zero, and the scratch documents here were about as clean as a session gets. It establishes that it no longer reproduces on demand, which is weaker and still worth knowing — the vendor report's A-1 can say so.
The model left behind on each product is a scratch document holding ~230 nodes, 8–10 beam elements and their nodal masses. Nothing was deleted; both documents were empty throwaways when the run started.
2026-09-04 (later) — the two unresolved /post/TABLE spellings, compared live¶
POST-shaped reads only: no /doc/NEW, model mutation, export path or deletion.
The calls used midas_nx.post.base.get_table() with an empty TABLE_NAME and
sent each spelling of each disputed TABLE_TYPE against the same open document.
Both products were connected under the same continuously-running sessions
recorded above: MIDAS Gen NX 2026 v2.1 and MIDAS Civil NX 2026 v2.2, both build
09/02/2026 (connectionID tZwG5G-fSg and maTuEDSLQw, respectively).
TABLE_TYPE sent |
Gen NX body | Civil NX body |
|---|---|---|
BEAMFORCESTP |
{"error":{"message":"[empty] Cannot generate table data as there is no analysis result."}} |
{"error":{"message":"[empty] Cannot generate table data as there is no analysis result."}} |
BEAMFORCESIP |
{"error":{"message":"MIDAS GEN NX there was an error creating utbl. (ex PostMode ...)"}} |
{"error":{"message":"MIDAS CIVIL NX there was an error creating utbl. (ex PostMode ...)"}} |
REACTIONSURFACESPRING |
{"error":{"message":"MIDAS GEN NX there was an error creating utbl. (ex PostMode ...)"}} |
{"error":{"message":"MIDAS CIVIL NX there was an error creating utbl. (ex PostMode ...)"}} |
REACTIONLSURFACESPRING |
{"error":{"message":"[empty] Cannot generate table data as there is no analysis result."}} |
{"error":{"message":"[empty] Cannot generate table data as there is no analysis result."}} |
The distinction is stable across products: Cannot generate ... no analysis
result means the product recognised the table type but the scratch document
could not provide its data; there was an error creating utbl is the response
for the unrecognised spelling. This independently repeats the older Gen-only
BEAMFORCESTP finding and settles the direction of both contradictions as
measurements: BEAMFORCESTP and REACTIONLSURFACESPRING are recognised.
Per the handoff boundary, the contracts and their resolved flags were not
changed here.
2026-09-04 (last) — the 18 existing unconfirmed CRUD cases re-run; /db/STRPSSM closed¶
Both open documents were confirmed empty before the first destructive call:
GET /db/NODE and GET /db/ELEM each returned {"message": ""} on Gen and
Civil. The runs then used scripts/live_crud_check.py in batches of at most
eight, with its own seeded throwaway model and save-before-/doc/NEW
checkpoint under C:/temp. Every payload came from the harness's contract-led
case definitions; none was composed at the prompt. The harness saved each
resulting scratch model and restored an empty document after every batch.
The products were the continuously running sessions already tied to their
About dialogs: Gen NX 2026 v2.1 and Civil NX 2026 v2.2, both build 09/02/2026
(connectionID tZwG5G-fSg and maTuEDSLQw).
| Endpoint | Gen NX | Civil NX | Classification |
|---|---|---|---|
/db/ACTL |
create refused | update completed, updated value did not read back | remains unconfirmed |
/db/CGLP |
blocked by prerequisite seed | blocked by prerequisite seed | remains unconfirmed |
/db/DOEL |
create response accepted, record absent on GET | create response accepted, record absent on GET | remains unconfirmed |
/db/EPSE |
create refused | product-specific case not selected | remains unconfirmed |
/db/EPST |
create refused | prerequisite seed refused | remains unconfirmed |
/db/FBLA |
create refused | create refused | remains unconfirmed |
/db/HPCE |
create refused | create refused | remains unconfirmed |
/db/MADO |
create response accepted, record absent on GET | create response accepted, record absent on GET | remains unconfirmed |
/db/MVCT |
create refused | create refused | remains unconfirmed |
/db/NLLP |
Unknown Error |
Unknown Error |
remains unconfirmed |
/db/NLNK |
blocked by NLLP seed | blocked by NLLP seed | remains unconfirmed |
/db/NLNK-M1 |
product-specific case not selected | blocked by NLLP seed | remains unconfirmed |
/db/RPSC |
Wrong Field |
Wrong Field |
remains unconfirmed |
/db/SBDO |
create response accepted, record absent on GET | create response accepted, record absent on GET | remains unconfirmed |
/db/STCT |
create response accepted, record absent on GET | create refused against the auto-populated stage-control record | remains unconfirmed |
/db/STRPSSM |
not served for Gen | full CRUD round trip passed | promoted to write-confirmed |
/db/TDMF |
create refused | create refused | remains unconfirmed |
/db/WVLD |
product-specific case not selected | create refused | remains unconfirmed |
Two fixtures were stale against the live-corrected contracts and were repaired
before the final isolated run. /db/RPSC now sends longitudinal reinforcement
at MBARS[].MBAR_ITEMS[] while leaving SBAR_ITEMS at the root (MD-40); it
still returned Wrong Field on both products, so no conclusion beyond the
observed failure is claimed. /db/STRPSSM now sends {Y, Z} points rather
than the manual's erroneous {PY, PZ} spelling (MD-38). On Civil it then
passed POST, GET, PUT, GET, per-id DELETE, and deletion verification using
section id 1. This isolates the former failure to the stale point-key shape.
Result-state changes: schema/live-cases.json remains 167 cases and moves from
143 to 144 confirmed; repository coverage moves from 172 write / 227 read
to 173 write / 226 read. No other endpoint was promoted, and no failed
unconfirmed case is labelled an SDK or product defect.
2026-09-05 — npm public-API CRUD evidence extended from 23 to 32 DB endpoints¶
Ran the built npm 2.7.7 package through
packages/typescript/scripts/live-crud.mjs, not raw HTTP and not Python. Each
run supplied --save-dir C:/temp; the harness checkpointed the open document,
called /doc/NEW, verified NODE/ELEM were empty, used only cases emitted in
schema/live-cases.json, deleted each test record through the public
resource's per-id delete() method, saved the throwaway model separately, and
restored an empty document. Batches never exceeded eight endpoints.
The same nine previously unrecorded resources completed create, read-back, update, updated read-back, individual delete, and deletion verification on both MIDAS Gen NX 2026 v2.1 and MIDAS Civil NX 2026 v2.2, build 09/02/2026:
| Public npm resource endpoint | Gen | Civil |
|---|---|---|
/db/MVCD |
pass | pass |
/db/TDGR |
pass | pass |
/db/NPLN |
pass | pass |
/db/ETFC |
pass | pass |
/db/CCFC |
pass | pass |
/db/HSFC |
pass | pass |
/db/MLFC |
pass | pass |
/db/CUTL |
pass | pass |
/db/CLWP |
pass | pass |
This is evidence for the installed-user path that generated metadata alone
cannot provide: resource discovery through resources.db, request wrapping,
response unwrapping, stored-value checks, PUT handling, and per-id deletion all
ran through the built package. The npm inventory therefore moves from 23 to
32 distinct /db endpoints, plus the existing four result-table
operations (36 public-API operations total). docs/coverage.json stays
unchanged because its current rows record product endpoint evidence rather
than which language client supplied it; adding a language-evidence dimension
would be a schema decision, not a live-run side effect.
The wider selection also exposed a harness boundary that must not be called an
SDK regression. Python's live checker constructs a common base model before
its cases; schema/live-cases.json currently emits explicit per-case setup but
not that common model, while the npm checker begins from a genuinely empty
document. Consequently CNLD, BMLD, CONS, ESSF, SECF, TSGR and TDMT could not
resolve their node/element/material/section preconditions; GSTP, TDME, IFGS,
THGC, THFC and SPFC likewise did not persist without the base model; and the
LCOM-GEN/LCOM-CONC fixtures referenced load case DL, which did not exist.
The npm script prints REGRESS because these cases are confirmed in the
Python-driven fixture, but this run does not establish a package regression:
the two harnesses did not create equivalent starting models. /db/GRUP was
also rejected locally before its write because it has no DELETE operation and
the npm harness deliberately refuses cases it cannot clean up. None of these
attempts is included in the 32-endpoint count. Final direct GETs returned
{"message": ""} for NODE and ELEM on both products, independently confirming
that both sessions were left on empty documents.
2026-09-05 (later) — every historical non-TEMP crash path re-checked; zero crashes¶
The author clarified the scope as endpoints that have not been moved under
/TEMP. Accordingly /TEMP/DESIGN/SRC/AIK-SRC2K/OCHECK was deliberately not
called and its standing risk was not changed. Everything else with a recorded
product-crash history was re-run against the same continuously-running Gen NX
2026 v2.1 and Civil NX 2026 v2.2 sessions, both build 09/02/2026. Every risky
call was followed by a real GET /db/NODE; verify_connection() alone was not
used as proof of liveness.
| Historical crash path | Gen NX | Civil NX |
|---|---|---|
/post/TABLE, all eight Design Forces TABLE_TYPEs |
all returned {"message": ""}; alive after each |
all returned the normal there was an error creating utbl no-result error; alive after each |
/DESIGN/RC/KDS-41-20-2022/TABLE, Column/Brace/Beam |
all returned empty dictionaries; alive after each | all returned the normal there was an error creating utbl no-result error; alive after each |
/ope/EDMP |
returned clean Unknown Error; alive |
returned clean Unknown Error; alive |
/ope/USLC |
command complete; alive |
command complete; alive |
PUT /db/THNL |
full create/read/update/read/delete/read round trip passed | full create/read/update/read/delete/read round trip passed |
raw POST /db/NMAS with rmX/rmY/rmZ omitted |
returned, GET stored all three as 0; alive |
returned, GET stored all three as 0; alive |
The eight /post/TABLE values were BEAMDESIGNFORCES,
COLUMNDESIGNFORCES, BRACEDESIGNFORCES, WALLDESIGNFORCES,
STEELMEMBERDESIGNFORCES, SRCBEAMDESIGNFORCES,
SRCCOLUMNDESIGNFORCES, and COLDFORMEDSTEELMEMBERDESIGNFORCES. This is the
independent later-build re-test their docstrings had asked for after the single
clean 2026-08-11 pass. It establishes that none reproduces its old blank-model
crash on the current build. It does not claim that a populated, analysed and
designed production model exercises the same product path.
EDMP and USLC used the exact prior crash-reproduction setup recorded on
2026-08-07: the repository's common disposable model seed plus a real concrete
load combination. THNL used its confirmed schema/live-cases.json case through
scripts/live_crud_check.py. NMAS bypassed the SDK normalizer intentionally:
its body was derived from the shared confirmed case with only the three
rotational-mass fields removed. The old NMAS mitigation therefore remains in
both SDKs despite another clean raw call.
All modified models were checkpointed under C:/temp with their product-native
extensions before cleanup. Final direct NODE/ELEM reads on both products were
empty. The many /doc/NEW calls involved in the isolated harnesses also
returned cleanly, but this was not a large-real-model reproduction of that
endpoint's old crash and is not claimed as one.
2026-09-05 — Task 1 shared-model harness disagreement rechecked¶
Both products answered direct GET /db/NODE and GET /db/ELEM with empty
documents before this run. Gen's built npm 2.7.8 harness then replayed the
version-4 shared fixture, printing BUILT base model (9 steps), for the
two cases that had disagreed in the earlier session:
| Endpoint | npm on Gen | Python on Gen, same selection |
|---|---|---|
/db/TDMT |
id 3 missing after POST |
full create/read/update/read/delete/read PASS |
/db/GSTP |
id 3 missing after POST |
full create/read/update/read/delete/read PASS |
npm exited 1; Python exited 0. Both harnesses saved their throwaway models
under C:/temp and restored an empty document. Civil received no mutations
in this recheck. Product builds were not queried again in this run; no new
build-specific claim is made.
An offline comparison identifies the setup difference: Python's main loop
runs every seed in each selected tier, regardless of the selected cases'
needs. npm's runCase replays only the case's emitted setup. Both of
these cases had empty needs and setup in schema/live-cases.json, so
Python's props tier created TDMT records 1 and 2 before testing record 3 and
npm did not. Sharing baseModel closed the common prefix and nothing else;
it never established that the harnesses begin each case in the same state.
The handoff's explicit stop-on-disagreement condition was reached. This recheck adds no npm PASS evidence and does not classify either failure as a package defect.
Offline follow-up, 2026-09-05, fixture version 5. The emitter now exports
every tier seed the npm harness can replay -- a sequence of {"Assign": ...}
POSTs captured from the seed step's own calls -- rather than a hand-picked
three tiers. 34 of the 37 tier seeds export; the three that do not
(pjcf_unlock, solid11_seed, stage11_seed) read state back or delete a
record, are named in unsupportedSeeds with the reason, and the four cases
needing them carry blockedSeeds so npm refuses them instead of running them
half-seeded. Cases carrying setup went 21 to 66. A failure before the endpoint
under test is touched is now classified BLOCK and exits 3, the same split
the Python runner has always made, so id 3 missing after POST would not have
been printed as REGRESS under this build. None of this is a live result.
Whether TDMT and GSTP now agree across the two harnesses is exactly what the
next live session has to answer, and the products' builds were not queried
again here.
2026-09-05 — Task 1 closed live: the two harnesses now agree, and one Python-side collision surfaced¶
Fixture version 5, npm built from 2.7.8 sources. Both products answered
GET /db/NODE and GET /db/ELEM with empty documents before the session,
checked with each product's own MAPI key -- an earlier check in this session
read one key for both products and proved nothing, which is worth writing down
because verify_connection() answered connected either way.
The fifteen, both harnesses, both products¶
/db/TDMT, /db/GSTP, /db/CNLD, /db/BMLD, /db/CONS, /db/ESSF,
/db/SECF, /db/TSGR, /db/TDME, /db/IFGS, /db/THGC, /db/THFC,
/db/SPLC, /db/LCOM-GEN, /db/LCOM-CONC.
| harness | Gen | Civil |
|---|---|---|
npm live:crud |
15 PASS | 15 PASS |
live_crud_check.py |
15 PASS | 14 PASS, 1 blocked (below) |
BUILT base model (9 steps) printed on every npm run. The two cases that
disagreed on 2026-09-04 -- /db/TDMT and /db/GSTP -- now pass on both
harnesses. They failed id 3 missing after POST because npm replayed no tier
seed, so the records the case counts on were never created; version 5 emits
them and the symptom is gone. The remaining eleven of the original thirteen,
plus /db/LCOM-GEN and /db/LCOM-CONC, pass as well.
/db/SPLC on Civil: a fixture collision, not a regression¶
Selecting extras4 and extras5 together on Civil answers POST /db/SPLC -> 201
with an error body: Key Already Exist. Alone, the same case passes on the
same product in the same session.
The cause is a cross-tier id collision that predates this work and had simply
never been selected together. _extras4_seeds' lcom_seismic_splc is
Civil-only and creates /db/SPLC id 1; extras5's Civil /db/SPLC case owns id
1 too. The Python runner executes every seed step of a selected tier
regardless of any case's needs, so choosing both tiers hands the case's id to
a seed. Gen never sees it because that seed does not run there.
Requesting a different id is not a fix: this load-case family renumbers a
requested Assign key to the next free slot (confirmed live 2026-08-16, see
_extras5_seeds()), so a case asking for id 2 would land at 1 when extras4 was
not selected and fail its own read-back.
What changed is the classification. _run_case now checks whether the
case's id is already present before creating it, and reports BLOCK (exit 3,
"fixture problem") rather than REGRESS (exit 1, "treat as an SDK defect").
Verified live in both directions on Civil: the two-tier selection prints
BLOCK /db/SPLC and exits 3, the single-case selection still prints PASS and
exits 0. The npm harness has refused a setup collision since it was written;
this is the same refusal on the side that had been calling it a regression.
The underlying collision is still there and still needs a decision. Nothing about the endpoint is in doubt -- the shape passes on both products whenever either tier runs alone.
2026-09-05 — Task 4: the seventeen re-probed on build 09/02/2026, and what the fixtures themselves say¶
Every recorded reason in this file is a lead rather than a conclusion, so the
seventeen /db endpoints that have a live case and have never passed were run
again against the current builds. All of them still fail, and two were
probed field by field rather than only re-run.
| endpoint | Gen, build 09/02/2026 |
|---|---|
/db/ACTL |
Wrong Field |
/db/EPSE, /db/EPST, /db/RPSC, /db/TDMF |
Wrong Field |
/db/HPCE |
Wrong Key |
/db/FBLA, /db/MVCT, /db/NLLP |
Unknown Error |
/db/MADO, /db/DOEL, /db/SBDO |
POST accepted, record absent on read-back |
/db/CGLP, /db/NLNK |
blocked; their nllp_seed/glink_seed fail first |
/db/ACTL: both halves of the old finding reproduce¶
The 2026-08-16 entry recorded Gen refusing every POST and Civil never
persisting TOL. Both hold on build 09/02/2026, and the Gen half was narrowed:
three payloads were sent, each derived from committed sources rather than
written by hand — the fixture as committed, the fixture filtered to the fields
the contract tags for Gen, and the two fields the contract marks required.
All three answer Wrong Field. Civil accepts all three and reads back
correctly, then fails read_updated: updated to 0.0005, read back 0.001.
So the fixture is not the explanation on either product. /db/ACTL is a
product-behaviour item, not a coverage one.
/db/FBLA: the obvious suspect is not the cause¶
Its payload carries LOAD_ANGLE, which no contract records. Sending the
contract's seven keys without it answers the same Unknown Error on both
products, so the extra key is a real fixture defect and not why the call
fails.
The check that should have existed: fixtures against contracts¶
Chasing those two made the gap obvious. This repository compares contracts
against both SDKs, against /info, and against the manual, and had nothing
comparing them against the fixtures — the fourth artefact claiming to know an
endpoint's shape, and the one deciding what a live run actually sends.
scripts/check_fixture_contract.py does. Its first three counts were all
wrong, each for its own reason, and the sequence is the finding worth keeping.
| reported | when | what was wrong with it |
|---|---|---|
| 64 contract gaps | 2026-09-05 | counted safeToOmit: true fields, which are already the record of an accepted call that omitted them |
| 81 total, 54 + 27 | 2026-09-05 | the checker read only document["fields"] and ignored appliesWhen |
| 41 + 2 | 2026-09-06 | current |
The second correction removed 38 findings and is the instructive one, because every one of them read as a hard defect and none was:
- A name declared in a
variantcounted as recorded nowhere./db/EIGV'sFRMIN,FRMAX,iFREQ,bMINMAXandbSTRUM,/db/THIS'sDALL,/db/NBOF'sKEY_NODE_ITEMS,/db/PNLD'sAREALOAD,/db/NLCT's three and/db/FBLA'sLOAD_ANGLEare all declared in a variant of their own contract. The list that was written up as "21 wire names an accepted round trip sent that no contract records" was, almost entirely, a checker that had not looked in the right place. - A
requiredfield carrying anappliesWhencounted as missing from every payload, rather than from the branch that selects it./db/NLNK's four and/db/HSFC's two already carried their condition.
/db/MVCT's DIST has no appliesWhen and is still reported, which is what
separates this from silencing the check.
What survives is 41 fixture leads across 5 endpoints — /db/ACTL,
/db/GRDP, /db/MVCT, /db/NLNK-M1, /db/TDMF — and 2 contract gaps on
one confirmed endpoint, /db/SDIS's LRB and NRB.
The generalization. A checker that compares two artefacts is a third claim about the shape, and it is wrong until something disagrees with it. This one was believed for a day, written into a release note, and handed to another agent as a task list, on nothing but its own output. A new checker's first findings are a hypothesis; confirm a sample of them against the artefacts by hand before reporting a count as a fact.
Both lists are held as a baseline in CI, in both directions: a new finding fails, and so does one that disappears without being recorded. Nothing was merged from them — a fixture is never a source for a contract.
2026-09-06 — chapter 08 moving-load and lane family, both products¶
Thirteen /db endpoints from chapter 08 gained a live case, replaying the
manual's own JSON examples from scripts/fixtures/*.json with only the model
references remapped to the seeded base model. Both documents were confirmed
empty first, with each product's own MAPI key.
| endpoint | Gen | Civil |
|---|---|---|
/db/LLANtr, /db/MVHLtr |
PASS | PASS |
/db/MLSP, /db/MLSR, /db/MVLDtr |
PASS | PASS |
/db/SLAN |
PASS (under BS) |
PASS (under KSCE-LSD15) |
/db/LLANch, /db/SLANch |
code unavailable | PASS |
/db/LLANid |
code unavailable | PASS |
/db/IMPF |
code unavailable | PASS |
/db/LLANop, /db/SLANop |
refused under BS |
PASS |
/db/SINF |
POST accepted, record absent | POST accepted, record absent |
Which moving-load code a product offers decides most of this table.
POST /db/MVCD answers [Error] ... (Item:Unavailable moving load code) on Gen
for CHINA, INDIA and KOREA, so the lanes those codes exist for cannot be
written there at all. That is a product capability, not a payload defect, and
the cases are split per product rather than carrying a payload that fails on
one of them. BS is the code chapter 08 lists for the general/optimization
family on Gen, and under it /db/SLAN passes while /db/LLANop and
/db/SLANop are still refused.
The tiers could not be run together, and that was the finding¶
Every lane tier seeds the same single-row /db/MVCD selector with its own
CODE, by POST. The first tier in a selection wins and every later one answers
Key Already Exist, taking its whole tier down with it: selecting four lane
tiers on Gen left one running and blocked five cases that pass individually.
/db/MLSP, /db/MLSR and /db/MVLDtr looked like failures for that reason
alone.
The seed now POSTs and falls back to PUT on the refusal — /db/MVCD declares
PUT, and the record is a selector rather than a table, so changing it is what a
second tier means. Four lane tiers selected together on Gen then pass all five
cases where one had passed before.
It POSTs first deliberately rather than reading the record and branching.
Reading state back would have made the seed one the npm harness cannot replay
from an emitted payload, which is how pjcf_unlock, solid11_seed and
stage11_seed came to be excluded — so branching would have taken all thirteen
of these cases away from npm to fix a Python-only collision. The first attempt
did exactly that and the emitter caught it.
This is the same collision class as /db/SPLC's, and the second one found in
two days: a seed that owns a fixed id is a shared resource whether or not it
was written as one.
What is not claimed¶
/db/SINF accepts its POST on both products and the record is absent on read
back, so it stays read-level and unconfirmed. /db/MVLDbs, /db/MVLDch,
/db/MVLDeu and /db/MVLDid have no live case; an earlier draft of this
work recorded them as write citing live_crud_check.py, and that citation had
no case behind it, so they are back at read.
2026-09-06 — moving-load controls pass; country load cases remain unresolved¶
The Gen NX 2026 v2.1 and Civil NX 2026 v2.2 sessions - both Build 09/02/2026,
author-confirmed 2026-09-06; the entry first recorded 08/26 and 08/27, which
nothing could have measured - were checkpointed under C:/temp, replaced with a
throwaway base model, and restored to an empty scratch document after each
Python and npm run. The fixtures replay the first JSON Request Body from the
vendored manual commit 7920759; the two SDKs consumed the same emitted case
data.
/db/MVCTbs and /db/MVCTtr completed create/read/update/read/delete on both
products. /db/MVCTid completed the same round trip on Civil; Gen does not
offer the INDIA moving-load code. Their manual iIGP and
INFL_GEN_POINT branches are now represented as appliesWhen, so the fixture
checker no longer asks a Number/Line payload to invent the mutually exclusive
Distance value. Write coverage moved from 185 to 188 endpoints, and npm DB
evidence from 55 to 58.
The adjacent country/code-specific load cases did not earn write evidence:
| endpoint | Gen | Civil |
|---|---|---|
/db/MVLDbs |
not run | not run |
/db/MVLDch |
code unavailable | Non-existent Vehicle ... in Sub-Load Case |
/db/MVLDid |
code unavailable | Number of Sub-Load Cases |
/db/MVLDeu |
Unknown Error |
Unknown Error |
/db/MVLDpl |
POLAND code unavailable |
POST accepted, id 1 absent on read-back |
/db/MVLDbs stopped at the required offline gate: its contract currently
marks the mutually exclusive LCDATA_* objects required at the record root,
so the manual's own LOADMODEL="STANDER" example appears to omit five required
sibling branches. Expressing the two-value ALL_MODE branch with the present
condition model needs a contract-shape decision; the live case was therefore
not run and the gate was not waived.
For the four attempted endpoints, the lane records were mechanical clones of
the manual's own lane Request Body with only record ids and the lane names
referenced by the target Request Body remapped. No vehicle definition was
invented. The China result confirms that its documented vehicle label is a
model reference, not a self-contained definition. India and Eurocode still
need a manual- or /info-backed prerequisite before their failures can be
classified further. Poland's Civil no-persistence response is retained as an
unconfirmed product observation. Python and npm returned the same outcomes.
2026-09-06 — Hyper-S controls: PUT-only write verification on Civil¶
Civil NX 2026 v2.2, Build 09/02/2026 (author-confirmed; recorded as 08/27 at
the time, which nothing could have measured) was checkpointed under C:/temp, replaced
with a disposable base model, and restored to an empty scratch document after
each run. The complete /db/THGC-M1 and /db/THOO-M1 Request Bodies were
copied from chapter 09 at the vendored manual commit 7920759; they were not
inferred from either SDK.
Both endpoints completed PUT/read/per-id DELETE/read through Python and the published npm surface. They deliberately have no POST step because their declared operations are GET, PUT, and DELETE. This moves both endpoints from read to write evidence on Civil.
The first npm attempt exposed two harness defects rather than product defects:
the harness unconditionally called POST, and its nested-object expectation used
JavaScript reference identity. The harness now selects POST and/or PUT from the
emitted case methods and compares expected arrays/objects structurally. Unit
tests cover the nested OUT_OPT shape that found the latter defect. The rerun
passed both endpoints and restored the empty document.
2026-09-06 (later) - /ope/MEMB settled by measurement, on both products¶
The sibling manual repo asked for a re-check of the ELEM_LIST vs AELEM
question and was right that the 2026-08-27 record was thinner than it read.
Rather than reconstruct the missing answers, the whole thing was measured
again on Gen NX and Civil NX. Both sessions were confirmed empty first with
each product's own key (verify_connection() reporting program: "gen"
and program: "civil" respectively), and every probe got its own
/doc/NEW plus a verified-empty check before the throwaway model was
rebuilt, so no probe could see another's members. The model is
schema/live-cases.json's base model; elements 2 and 3 are its two collinear
horizontal beams. Probe bodies are the article's own Request Example with the
element ids remapped.
Identical on both products:
| # | sent | POST | body | GET /db/MEMB after |
|---|---|---|---|---|
| A | ELEM_LIST: [2,3], SELECTION |
200 | {"MEMB": {"1": {"AELEM": [2,3], "bREVERSE": false}}} |
member created |
| B | AELEM: [2,3], SELECTION |
200 | {"error": {"message": "There is no valid element information."}} |
{"message": ""} - nothing created |
| C | ELEM_LIST: [2] and AELEM: [3] |
200 | {"MEMB": {"1": {"AELEM": [2], ...}}} |
member is [2] |
| D | AELEM: [2,3], AUTO/ALL |
200 | {"1": {"AELEM": [1]}, "2": {"AELEM": [2,3]}} |
whole model auto-assigned |
| E | no element list, SELECTION |
200 | {"error": {"message": "There is no valid element information."}} |
{"message": ""} |
B and E are identical, down to the status code and message string. Sending
AELEM is indistinguishable from sending no element list at all, which is the
signature of a key the request schema does not have - not of a bad value. That
is the cleanest form this question could have been settled in, and it took a
negative control (E) that the 2026-08-27 pass never ran.
The other three answers:
SELECTION_TYPEis not the confound it looked like.ALLdoes ignore the element list (D), but it ignoresELEM_LISTjust as thoroughly. It is not a condition under whichAELEMstarts working.- Both keys at once:
ELEM_LISTwins andAELEMis ignored outright (C), with no conflict and no warning. - The rejection is HTTP 200, not a 4xx. One more instance of the rule, now with the status code written down.
Two things fell out that nobody was looking for:
bREVERSEdisagrees between the POST echo and the stored record. All three successful probes, both products: POST answers"bREVERSE": falseand an immediateGET /db/MEMBreturnstruefor that same member. The POST response body is not the stored record, so do not assert against it.POST /doc/NEWwith no request body is HTTP 500 -{"error": {"message": "Cannot read properties of null (reading 'Argument')"}}from the relay - and the document is not reset. It needs{"Argument": {}}, which answers200 "... command complete"and does clear. The first run of this probe ignored that status and every probe after it ran on an accumulated model; the results were discarded and the run above replaced them. The failure is loud, and it was still missed by not reading it - which is the argument for asserting the reset rather than assuming it.
/ope/MEMB moves to write level on both products on this run: it created
design members and the members were read back. Both sessions were left on an
empty document, confirmed on /db/NODE, /db/ELEM and /db/MEMB.
Product build strings are not recorded: the API exposes no endpoint that reports them, so that one field of the sibling repo's request cannot be answered from a script.
Full reply in docs/ope_memb_elem_list_response.md (removed 2026-09-17; git
history at fa1332b).
Follow-up the same day: the documentation half was a locale difference, and
this repository got it wrong. The sibling repo quoted the article's request
example as "AELEM": [1, 2]; the reply above re-fetched the article, found
"ELEM_LIST": [640, 692], and reported their citation as mistaken. Both
readings were real. Article 49514964272665, updated_at
2026-07-30T05:16:25Z in both cases, and the ko and en-us locales carry
different Input JSON examples - ko sends AELEM, en-us sends
ELEM_LIST, while both Specifications tables say ELEM_LIST. Recorded as
MD-52.
The live run is what settles it, and it still points the same way: ELEM_LIST
assigns the member, AELEM is not read. The ko example is the wrong one, and
the sibling repo has already reverted its own chapter back to ELEM_LIST
(0270fad).
The lesson is not about this endpoint. A vendored citation records a URL but not a locale, so two people can transcribe the same article id faithfully and end up with different field names - and every manual-versus-article comparison here that fetched a single locale has the same blind spot. "I re-fetched it and you are wrong" was reported in good faith with the raw body in hand; the step missing from it was asking why a careful person would be reading something else.
2026-09-12 - seven pending write cases completed in both SDKs¶
Gen NX 2026 v2.1 and Civil NX 2026 v2.2, both Build 09/02/2026
(author-confirmed), were connected with their own keys and confirmed empty on
/db/NODE and /db/ELEM before the batch. Each harness checkpointed under
C:/temp, built its disposable dependencies, and restored an empty scratch
document after the run.
Python and the built npm package independently completed the emitted cases for
/db/IEPI, /db/EXLD, /db/PRST, /db/POLC, /db/MATD, and /db/IEHC on
both products. Civil additionally completed /db/POLC-M1; that endpoint is
Civil-only. The ordinary cases completed create/read/update/read/delete/read.
/db/MATD declares only GET and PUT, so it completed read/PUT/read and relied
on the harness's final whole-document reset for cleanup. /db/POLC-M1 included
POST because the earlier live observation proves that the route accepts it,
despite the chapter's normalized method list.
The fixtures came from the contracts and the Request Bodies at vendored manual
commit 7920759; neither SDK was used as a source for the other. /db/IEHC
uses separate Gen and Civil cases so the Gen-only wall members never leak into
the Civil payload. /db/POLC-M1 uses the dependency-free ACC branch already
represented by its contract.
/db/MATD: the documented material lookup is not sufficient on this build¶
Two manual-derived attempts were rejected identically on Gen and Civil:
CODENAME="EN04(RC)",CODEMATLNAME="ClassB"returnedRebar grade lookup failed.- Omitting the strength values returned
MAINREBAR_B_FY must be > 0.
A GET of the disposable model's material 1 returned concrete C24 with
CODENAME="KS01(RC)", CODEMATLNAME="C24", and blank rebar-code/name fields.
Using that observed lookup identity together with the manual Request Body's
positive MAINREBAR_B_FY=500000 and SUBREBAR_B_FY=600000 passed on both
products and both SDKs. This is recorded as product evidence, not generalized
into a contract claim: the manual's implication that these strengths are
ignored does not match the live requirement, and its EN04(RC) / ClassB
example is not usable on these builds.
The first npm run also exposed a harness safety gap: it refused every endpoint
without DELETE, even when the selected case was last and a final document reset
was requested. The harness now permits that narrow document-reset cleanup
mode only for the final selected case with final reset enabled; unit tests cover
both the allowed and rejected orderings. The rerun passed all seven distinct
endpoints and left both products empty.
2026-09-14 - GRDP completed; three B-2 failures narrowed offline¶
The same continuously running Gen NX 2026 v2.1 and Civil NX 2026 v2.2 Build
09/02/2026 sessions were confirmed empty, checkpointed under C:/temp, and
restored to empty scratch documents after every Python and npm run.
The fixture/contract comparison fell from 41 findings over five endpoints to
one finding on /db/ACTL. /db/GRDP now sends every member of the vendored
manual's complete Request Body. /db/MVCT, /db/TDMF, and /db/NLNK-M1 now
carry the branch conditions that their manual rows state explicitly (iIGP,
FTYPE, and REF_SYSTEM/INPUT_METHOD, respectively), rather than treating
all mutually exclusive branch members as simultaneously required.
/db/GRDP completed create/read/update/read/delete/read through both Python
and the built npm package on both products. The first complete-payload run
showed why the older probe was misleading: the POST echo retained
STRAIN_GROUP_ITEMS.DAMPING_RATIO=0.05, but immediate GET stored that value and
the nested group coefficients as 0 on the disposable model. The case now
probes FREQ_MODE_1_DEFAULT, which does persist. An attempted update from 0.1
to 0.2 was correctly rejected because it equalled FREQ_MODE_2_DEFAULT; using
the manual's separately stated 0.5 completed the round trip.
/db/MVCT initially repeated the old Unknown Error on both products. An
isolated prerequisite probe then showed that selecting the manual's AASHTO
LRFD moving-load code was sufficient; no lane, vehicle, or moving-load case
was needed. The normal Python harness and built npm public API subsequently
completed create/read/update/read/delete/read on Gen and Civil, checkpointing
under C:/temp and restoring both products to empty scratch documents.
The other two did not earn write evidence. /db/TDMF still returns Wrong
Field on both products even with the chapter's CREEP/CTYPE Request Body;
/info's extra ELAST has no documented value or request semantics, so none
was invented. Civil /db/NLNK-M1 remains blocked before its
own call because the manual NLLP seed still returns Unknown Error. These are
now live/product prerequisites or documentation gaps, not offline
fixture-versus-contract mismatches.
2026-09-14 - EPMT is write-confirmed on Gen, rejected on Civil¶
The fixed manual's /db/EPMT Von-Mises Request Body was added as a new Task A
case. The update uses the second material name printed by that same section;
no payload value was inferred. Python and the built npm public API each
completed create/read/update/read/delete/read on Gen NX 2026 v2.1 Build
09/02/2026.
Civil NX 2026 v2.2 Build 09/02/2026 returned Wrong Field for the identical
POST through both SDKs. Fresh GET /info/db/EPMT responses from Gen and Civil
declared the same field shape, including the VM branch members, so /info
does not supply a product-specific payload correction. The Civil case remains
unconfirmed and its earlier read-only evidence remains intact. Every run was
checkpointed under C:/temp and restored to an empty scratch document.
2026-09-14 - FIMP's printed Kent & Park request is internally invalid¶
The fixed manual's complete /db/FIMP Request Body was added without changing
its values. Python and the built npm public API sent it to Gen NX 2026 v2.1
and Civil NX 2026 v2.2 Build 09/02/2026. All four POSTs returned the same
specific product error:
Epsilon_cu > 0.8 / Z + Epsilon_co
The request prints ECU=0.003, Z=100, and EC0=0.002, so it does not meet
that stated relationship. The chapter's second example repeats the same three
values and supplies no compliant alternative. No replacement was invented;
the case remains unconfirmed and /db/FIMP remains read-only in the coverage
ledger. Every run was checkpointed under C:/temp and restored to an empty
scratch document.
2026-09-15 - Task F npm replay, extras14 first pass¶
The existing confirmed fixtures for /db/ACTL-M1, /db/BCGD-M1, /db/CJFG,
/db/CRGR, /db/DYLA, /db/EIGV-M1, /db/HHCT-M1, /db/NLCT-M1, and
/db/STCT-M1 completed through the built npm package on Civil NX 2026 v2.2
Build 09/02/2026. The same selections were re-run through Python on the same
session. All models were checkpointed under C:/temp and reset to empty.
The first npm pass exposed two fixture-replay defects rather than endpoint
regressions. A setup resource without DELETE was rejected even for the final
case before a guaranteed document reset; the harness now permits exactly that
cleanup mode and a unit test guards the boundary. dl14_seed is also marked as
the live-observed renumbering seed it is. /db/BCGA-M1 subsequently reached
its endpoint, but its Python probe sorts server-reordered BC_SELECT while the
language-neutral fixture cannot yet express that comparator. /db/DYFG and
/db/DYNF require the intentionally interleaved /db/MVCD switch to EUROCODE;
an endpoint-only selection omits that switch. These three remain out of npm
evidence until their comparison/order semantics are represented explicitly.
2026-09-16 - Task F npm replay, extras1 complete¶
All ten extras1 endpoints completed through the built npm package and were
then re-run through Python in the same product sessions on Build 09/02/2026.
/db/CLDR, /db/CO_F, /db/CO_M, /db/CO_S, /db/CO_T, /db/PRLS,
/db/PZEF, and /db/STYP passed on Gen and Civil. /db/SPAN and
/db/STYP-M1 are Civil-only and passed there. Every run was checkpointed
under C:/temp and restored to an empty document.
The first npm /db/CO_F attempt was BLOCKED before the target call because
the emitted fixture's global seed map silently let the extras7 seed named
fbld_seed replace the different extras1 seed with the same name. Python
selects seeds inside each tier and was unaffected. The extras7 seed is now
named fbld7_seed, preserving both measured payloads independently; the npm
rerun then passed on both products. This was fixture identity loss, not a
product or SDK regression.
2026-09-16 - Task F npm replay, extras2 complete¶
All ten extras2 endpoints completed through npm and Python on Build
09/02/2026. /db/BTMP, /db/EFCT, /db/GTMP, /db/IELC, /db/INMF,
/db/LDSQ, /db/SMLC, /db/SMPT, and /db/STMP passed on Gen and Civil;
Civil-only /db/PLCB passed on Civil. Each run was checkpointed under
C:/temp and restored to an empty document.
The first npm pass reached neither /db/SMLC nor the /db/SMPT target because
their shared smpt_seed asks for id 90 and the product stores it at the next
free id. This renumbering was already documented by the Python fixture from
the 2026-08-16 live run, but the emitted fixture had not preserved that fact.
Marking smpt_seed as renumbering made the npm replay verify the stored seed
by its name; both targets then passed on both products.
2026-09-16 - Task F npm replay, extras3 complete¶
All six extras3 endpoints completed through npm and Python on Build
09/02/2026. /db/EDMP, /db/PSSF, /db/VBEM, and /db/VSEC passed on Gen
and Civil; Civil-only /db/EWSF and /db/STRPSSM passed on Civil. Every run
was checkpointed under C:/temp and restored to an empty document. No fixture,
SDK, or product disagreement surfaced in this tier.
2026-09-16 - Task F npm replay, boundary complete¶
All eight boundary endpoints (/db/ELNK, /db/FRLS, /db/GSPR,
/db/MCON, /db/NSPR, /db/OFFS, /db/RIGD, and /db/SSPS) completed
through npm and Python on both Gen and Civil, Build 09/02/2026. Every run was
checkpointed under C:/temp and restored to an empty document. No fixture,
SDK, or product disagreement surfaced in this tier.
2026-09-16 - Build 09/15/2026 on both products, and the published 2.8.2 checked from both registries¶
Gen NX and Civil NX both moved to Build 09/15/2026 (MIDAS Gen NX 2026 v2.1,
MIDAS Civil NX 2026 v2.2), each read from its own About dialog. This is the
first time in this file's history that the two products carry the same build
date; they have been patched on separate schedules all year, so this is a
coincidence to check rather than a rule to rely on. Everything below was run
GET only, against the documents the author had open - no /doc/NEW, no write
of any kind.
What was tested is the published package, not this working tree. Both
surfaces were installed fresh from their registries into a scratch directory
(pip install midas-nx==2.8.2, npm i midas-nx@2.8.2) and the read-only
sweeps were pointed at those installs, so a result here is what a user who
installs 2.8.2 today gets. PyPI published 2026-09-15T17:13Z, npm
2026-09-15T17:08Z.
| product | surface | swept | answered | failed |
|---|---|---|---|---|
| Gen | PyPI midas-nx 2.8.2 |
268 GET-capable resources | 268 | 0 |
| Gen | npm midas-nx 2.8.2 |
268 of 305 declared serve GET | 268 | 0 |
| Civil | PyPI midas-nx 2.8.2 |
283 GET-capable resources | 283 | 0 |
| Civil | npm midas-nx 2.8.2 |
283 of 305 declared serve GET | 283 | 0 |
The two SDKs agree exactly on both products, as they did on 2026-09-03 at 267
and 282; the extra one on each side is DESIGN/STEEL/DSTL, added in 2.8.2. npm
additionally reported 6 endpoints carrying data on Gen and 7 on Civil, which is
a property of the open documents, not of the build.
DESIGN/STEEL/DSTL answered on both products - the ledger's last unverified endpoint¶
It returned {"message": ""}, the documented zero-row shape, on Gen and on
Civil, through both published SDKs. Its declared products: [gen, civil] is
therefore confirmed rather than assumed, and docs/coverage.json now records
it at level: "read", taking live coverage to 400/400 (200 write / 200
read). What this does not do is send it a payload: the endpoint selects a
project's steel design code, and nothing has yet put a value into it.
The patch changed one schema, identically on both products: /db/SECT gains USE_HAMBLY_EQ¶
scripts/info_baseline.py --capture per product, then --diff against
schema/info-baseline.json (captured 2026-09-03 on Build 09/02/2026), reports
exactly one difference on each side and it is the same one - 189 pairs compared
on Gen, 210 on Civil:
CHANGED /db/SECT (gen) CHANGED /db/SECT (civil)
+ SECT_AFTER.USE_HAMBLY_EQ (bool) + SECT_AFTER.USE_HAMBLY_EQ (bool)
+ SECT_BEFORE.USE_HAMBLY_EQ (bool) + SECT_BEFORE.USE_HAMBLY_EQ (bool)
Nothing else changed, gained or disappeared, on either product. Because both products declare it, this is not one of the ten schema divergences and needs no per-product tag.
The new property appears nowhere in the manual repository - Hambly does
not occur in docs/manual/*.md at all - and therefore in no contract and
neither SDK. That is a documentation lag one day after a patch, not a defect,
so it is deliberately not filed in docs/manual_defects_register.md.
Four things say "the article has not been revised yet" rather than "this is an internal or beta flag", and they are worth writing down because whoever decides what to do with the property should not have to guess again:
- It carries a description.
/infogives it as{"description": " Use Hambly Eq. for Ixx", "type": "boolean"}. Ixx is the torsional constant. The placeholders this API really does carry -/db/DRLS'sDUMMY, whichinfoOnlyexists for - have no description at all. - Its position is the tell. Within
SECT_BEFORE/SECT_AFTER's 57 properties it sits at... USE_SHEAR_DEFORM, USE_WARPING_EFFECT, USE_HAMBLY_EQ, SHAPE ..., and the first two are rows (11) Consider Shear Deformation and (12) Consider Warping Effect of the chapter's 공통 Specifications table - both Boolean, both defaultfalse, both Optional. The table stops at (12). This is the third checkbox of that same group sitting in row (13)'s empty seat, not a flag hidden somewhere unrelated. - Both products declare it identically. A beta would more plausibly reach one product first; this reached Gen and Civil in the same patch.
- The timing needs no explanation. The manual repo's 2026-09-15 정기 점검
sync (
a6947a7) and the products' Build 09/15/2026 are the same day, so the article simply had not been revised when the build shipped.
None of that is proof, and nothing has sent the property to the server. It argues for holding, which is what a beta flag would argue for too - the two hypotheses differ in what the next sync will show, not in what to do now.
schema/info-baseline.json was deliberately left at its 2026-09-03 capture.
Both products have now been captured on the new build and the pair would make a
valid replacement, but re-baselining is not a bookkeeping step here: CI runs
info_baseline.py --against-contracts --check, which fails when the set of
declared-but-uncontracted properties grows, and USE_HAMBLY_EQ is exactly such
a property. Committing a new baseline therefore means first deciding what
contracts/endpoints/db-sect.yaml says about it - /info is a permitted
source for a /db/* contract, so requirement: unstated is available - or
waiting for the next MIDASIT manual sync to document it. That decision is the
author's; until it is made, the 2026-09-03 baseline is still the right thing to
diff against, and this section is the record of the one property that differs.
Two things these runs do not prove, both worth restating because a clean sweep invites the opposite reading: they prove 268 and 283 routes exist, answer and parse on the new builds, and they prove nothing whatsoever about request shapes, because the server never saw a payload.
A wrinkle in the diff tool, not in the product¶
--diff --product <p> filters the fresh capture by product but not the
baseline, so a single-product capture reads as a wall of GONE ... (other
product) lines - 210 of them sweeping Gen, 189 sweeping Civil - that mean only
"this capture had no such-and-such in it". They are noise, not a finding.
Reading that output requires filtering the other product out by hand. The
per-product capture is not avoidable: the MAPI keys are per product.
2026-09-16 (later) - every historical crash path re-run on Gen NX Build 09/15/2026: one crashed¶
The author asked for the crash paths to be re-tested on the new build, then
chose the full scope including the deliberately destructive ones, on a document
they confirmed disposable. Work went least-destructive first, and every risky
call was followed by a real GET /db/NODE - verify_connection() alone was
never used as proof of liveness, because it answers connected through the
relay while the product is gone.
| Historical crash path | Ticket | Result on Build 09/15/2026 |
|---|---|---|
/post/TABLE, all eight Design Forces TABLE_TYPEs |
- | all {"message": ""} in <0.5s; alive after each |
/DESIGN/RC/KDS-41-20-2022/TABLE, Column/Brace/Beam |
MAPI-2431 | all {}; alive after each |
PUT /db/THNL |
MAPI-2468 | full create/read/update/read/delete/read round trip PASS |
/ope/EDMP |
MAPI-2425 | clean Unknown Error; alive |
/ope/USLC |
MAPI-2426 | command complete; alive |
/db/NMAS through the SDK (normalizer on) |
MAPI-2378 | full round trip PASS |
raw POST /db/NMAS with rmX/rmY/rmZ omitted |
MAPI-2378 | did not reproduce - 201 in 0.38s, GET stored all three as 0; alive |
/TEMP/DESIGN/SRC/AIK-SRC2K/OCHECK |
MAPI-2429 | 🛑 crashed |
Nothing was hand-written. The four /db/* round trips ran through
scripts/live_crud_check.py's own confirmed cases; /ope/EDMP and /ope/USLC
used the 2026-07-30 crash-reproduction shapes on the repository's
BASE_MODEL_STEPS seed plus extras4's own /db/LCOM-CONC record; the raw NMAS
call ran through docs/vendor_repro_nmas.py, which is the vendor-facing
reproduction and bypasses the SDK entirely.
OCHECK crashed, and that is the expected result rather than a new finding.
Same conservative argument as every prior repro, on the repository's seed rather
than a hand-built dummy this time: the call hung 24.06s and returned 404
Client Disconnected, the follow-up GET /db/NODE answered 404 client does
not exist, and verify_connection() flipped to disconnected. It is worth
being precise about what is new here, because it is easy to overstate: Gen was
already confirmed crashing on the /TEMP/ path on 2026-08-07. What 2026-09-16
adds is the current build, and the first Gen reproduction in over a month -
MAPI-2429 is now reproduced across four builds and both products, still
matching MIDASIT's own "not a defect, no fix timeline" closure. No Jira action
follows; the ticket is already closed on exactly this finding.
The ordering is what makes the rest of the table mean something: the product had just answered eleven historically-crashing calls and four full write round trips without a stumble, so it was demonstrably healthy right up to the OCHECK call.
Two things this does not establish. The /post/TABLE and RC-TABLE families
were exercised against a document with no nodes, which is the same blank-model
shape as every clean re-test since 2026-08-11 - a populated, analysed and
designed model has still never been re-tested against them. And the raw NMAS
call not reproducing is now its third consecutive clean result, but the
normalizer stays in both SDKs: a server defect that stops reproducing is not the
same as one whose fix has been stated, and the cost of keeping the mitigation is
three fields nobody has to think about.
Civil NX, same build, same paths - all clean, OCHECK deliberately skipped¶
The author extended the re-test to Civil NX (v2.2, Build 09/15/2026, document
confirmed disposable) and excluded OCHECK: it had just been reproduced on Gen,
it is already confirmed on Civil across three builds, and crashing a second
product proves nothing the ticket does not already say.
| Historical crash path | Result on Civil, Build 09/15/2026 |
|---|---|
/post/TABLE, all eight Design Forces TABLE_TYPEs |
all returned the established there was an error creating utbl (ex PostMode ...) no-result error; alive after each |
/DESIGN/RC/KDS-41-20-2022/TABLE, Column/Brace/Beam |
same no-result error; alive after each |
PUT /db/THNL |
full round trip PASS |
/ope/EDMP |
clean Unknown Error; alive |
/ope/USLC |
command complete; alive |
/db/NMAS through the SDK |
full round trip PASS |
raw POST /db/NMAS with the three rotational fields omitted |
did not reproduce, twice in the same session - 201 in ~0.4s; alive |
Every modified document was checkpointed under C:/temp with the product's own
.mcbz extension and then reset with /doc/NEW; both products were left on
empty documents.
A defect in the vendor-facing reproduction script, found by running it¶
docs/vendor_repro_nmas.py built every URL as {host}/{product}{endpoint},
including its own /mapikey/verify health check. That endpoint is served from
the host root with no product segment - client.py's verify_connection()
strips the segment for exactly this reason - so the script's opening "연결 확인"
line and its post-call relay probe had both been answering
404 Not Found, Please check your request url. on both products.
Its verdict was never wrong: the pass/fail decision reads the /db/* calls, not
this one. But this is the file MIDASIT is pointed at to reproduce A-1, and it
opened with a 404. Fixed by giving call() a root=True option for that one
endpoint; re-run on Civil, the check now answers 200 with the normal
connected body. Nothing else in the script changed, and it ships in neither
package.
2026-09-16 — Task I boundary: DESIGN/STEEL/DSTL¶
On a disposable empty document, GET /DESIGN/STEEL/DSTL answered 200 with
{"message": ""} on both Gen NX 2026 v2.1 and Civil NX 2026 v2.2, Build
09/15/2026. The manual's documented design-code selection was absent from that
response, so there was no observed original value to restore. No PUT and no
DELETE were sent: a write followed by a guessed revert would not be a safe
round trip. This remains a read-level confirmation and a documented live block,
not a rejection of the manual payload.
2026-09-16 — npm/Python replay: static fixture batch¶
On fresh disposable documents checkpointed below C:/temp, the npm package and
the Python SDK each replayed the same emitted confirmed fixtures for
/db/ETMP, /db/FBLD, /db/LTOM, /db/NBOF, /db/NTMP, /db/PRES,
/db/PSLT, and /db/SDSP. Every endpoint completed its full
create → get → update → get → delete round trip on both Gen NX 2026 v2.1 and
Civil NX 2026 v2.2, Build 09/15/2026. Each harness reset the document with
/doc/NEW; final GET /db/NODE and GET /db/ELEM checks were empty on both
products.
2026-09-16 — npm/Python replay: dynamic-load batch¶
On fresh disposable documents checkpointed below C:/temp, both SDKs completed
the same emitted fixture round trips for /db/SPFC, /db/THGA, /db/THIS,
/db/THMS, /db/THNL, and /db/THSL on Gen NX 2026 v2.1 and Civil NX 2026
v2.2, Build 09/15/2026. Every npm run and every Python run completed
create → get → update → get → delete for all six resources. Both products were
reset through /doc/NEW after the batch.
2026-09-16 — Civil-only extras14 replay result¶
/db/BCGA-M1, /db/DYFG, and /db/DYNF are Civil-only cases, so Gen was not
called. The npm harness safely blocked BCGA-M1 because its emitted setup
names /db/BNGR as individually non-cleanable; Python completed that existing
case. Both SDKs received the same current-server rejections for the other two:
DYFG requires the moving-load code to be Eurocode and DYNF is applicable
only to Moving Code EUROCODE. This is not counted as npm replay completion.
The Python harness independently reports both as current regressions; no SDK
behaviour claim is made because the two clients exposed the same server result.
The Civil document was reset to empty after each attempt.
2026-09-16 — npm/Python replay: analysis-control subset¶
/db/BUCK and /db/PDEL completed their emitted fixture round trips through
both packages on Gen NX and Civil NX, Build 09/15/2026. /db/BCCT also passed
on both products once it was intentionally run as a one-case npm batch: its
/db/BNGR prerequisite has no DELETE operation, so the final /doc/NEW reset
owned its cleanup. Python completed the same three endpoints on both products.
/db/HHCT and /db/NLCT passed on Gen through both SDKs but failed on Civil
through both SDKs. HHCT's POST succeeds but the expected value does not read
back; NLCT returns that LINE_SEARCH_OPTION is required when
OPT_ENABLE_LINE_SEARCH is true. Neither is counted as an npm replay success;
the identical outcomes are retained as product/fixture evidence rather than
claimed as an SDK divergence. Every run was checkpointed under C:/temp and
finished with a fresh document.
2026-09-16 — npm/Python replay: bridge batch¶
/db/ULFC completed its emitted fixture on both SDKs and both products.
Civil-only /db/CAMB, /db/GCMB, and /db/GSBG likewise passed through npm
and Python. Each bridge group case ran as a one-case npm batch because its
/db/GRUP setup cannot be individually deleted; the terminal /doc/NEW
reset therefore owned cleanup. Checkpoints remained under C:/temp, and each
product returned to an empty document.
2026-09-16 — npm/Python replay: static-load subset¶
/db/FMLD, /db/PNLA, and /db/POSL passed their shared fixtures through
both SDKs on Gen NX and Civil NX; Gen-only /db/POSP passed through both SDKs
on Gen. The first npm PNLA pass exposed a fixture omission rather than an API
failure: /db/PNLD is known to renumber requested key 90 to key 1. Adding its
already documented allowRenumbering marker to the emitted fixture made the
subsequent npm Gen and Civil replays pass. All runs used the disposable
checkpoint/reset protocol under C:/temp.
2026-09-16 — npm/Python replay: moving-load subset¶
/db/LLAN, /db/MVHC, and /db/MVLD completed their emitted AASHTO LRFD
fixtures through npm and Python on both products, Build 09/15/2026. /db/MVHL
also completed through Python on both products, but npm POSTs are stored under a
server-renumbered target ID rather than fixture ID 2. The npm harness can
verify known seed renumbering by stable name but has no equivalent target
case representation, so MVHL remains outside the npm-success count pending a
separate, tested harness design. Each product was checkpointed under C:/temp
and reset to an empty document.
2026-09-16 — npm/Python replay: construction-stage batch¶
/db/STAG, /db/TMLD, and /db/CRPC completed their emitted fixtures through
npm and Python on Gen NX and Civil NX; Civil-only /db/CMCS completed through
both SDKs on Civil. npm ran each as an isolated case because the shared group
setup includes resources without per-ID DELETE; the terminal /doc/NEW reset
owns that cleanup. Every call used the C:/temp checkpoint protocol and left
an empty document.
2026-09-16 — npm/Python replay: heat-of-hydration subset¶
/db/HAHS and /db/STBK completed their fixtures through npm and Python on
both products, Build 09/15/2026. HAHS used its confirmed disposable eight-node
solid model; both runs checkpointed below C:/temp and ended with /doc/NEW.
/db/HSTG then completed through npm and Python on both products as a separate
one-case group-seed batch under the same checkpoint/reset protocol.
2026-09-16 — npm/Python replay: load-combination batch¶
/db/LCOM-SRC, /db/LCOM-STEEL, and /db/LCOM-STLCOMP each completed the
same emitted fixture through npm and Python on Gen NX and Civil NX, Build
09/15/2026. All product documents were checkpointed under C:/temp and reset
to empty after the batch.
2026-09-16 — npm/Python replay: lane-optimization batch¶
Civil ran /db/LLANop, /db/SLAN, and /db/SLANop together through the npm
harness; all three completed their emitted create → get → update → get → delete
round trips. Gen then ran /db/SLAN as a one-case npm batch and passed. Python
replayed the same three selections on Civil and the same SLAN selection on Gen;
all passed. The runs used Build 09/15/2026, checkpointed under C:/temp, and
restored empty scratch documents with /doc/NEW.
2026-09-16 — npm/Python replay: boundary-group core case¶
/db/BNGR ran as a one-case batch on Gen and independently on Civil because
the resource has no per-ID DELETE operation. npm completed create → get →
update → get on both products, after which the harness checkpointed the
throwaway model and used /doc/NEW for cleanup. Python replayed the same
one-case selection on each product and passed. Both products were Build
09/15/2026 and were left on empty documents.
2026-09-17 - closing the npm/Python evidence asymmetry, and what is left of it¶
Both products were open on Build 09/15/2026 with empty documents, confirmed by
a read of /db/NODE and /db/ELEM on each before anything ran. Every batch
below went through the built npm package first and the Python harness second on
the same selection in the same session, checkpointed under C:/temp, and ended
with /doc/NEW.
| endpoint | npm | Python | what it closed |
|---|---|---|---|
/db/GRUP |
Gen, Civil | Gen, Civil | the last plain replay in the gap |
/db/LLANtr |
Gen | Gen | Civil-only since 2026-09-06 |
/db/MLSP |
Gen | Gen | same |
/db/MLSR |
Gen | Gen | same |
/db/MVHLtr |
Gen | Gen | same |
/db/MVLDtr |
Gen | Gen | same |
/db/TMAT |
Gen, Civil | Gen, Civil | never attempted through npm |
/db/IMPF |
Civil | Civil | same; Civil-only, needs the KOREA lane code |
All eight passed create → get → update → get → delete on every product listed.
The five lane and moving cases ran as one npm batch on Gen, so the /db/MVCD
selector seed that used to take a whole tier down with Key Already Exist
handled five tiers in one selection without incident.
The asymmetry was partly a measurement artefact¶
scripts/report_npm_replay_coverage.py counted endpoints, and an endpoint
is not the unit the fixture works in. It now counts confirmed cases and
compares each case's declared products against the products the evidence
inventory records, which changed what the number means:
by confirmed case (177 cases over 166 endpoints)
npm ran every declared product: 170
npm ran only some : 0
npm ran none : 7
Two things only that unit can see. Five cases were counted as done while npm had run one product of two - the five lane and moving rows above, Civil-only since 2026-09-06 while Python had both. They are the asymmetry this session was asked to close, and endpoint-level counting had hidden them behind a tick.
And /db/HHCT and /db/NLCT were counted as undone while npm had already
replayed them. Each carries a confirmed Gen case and an unconfirmed Civil one;
npm completed the Gen case on 2026-09-16 and the Civil case failed, which for an
unconfirmed case means triage the fixture rather than a regression. Endpoint
counting cannot record one product's result without implying the other's, so the
run went unrecorded. Their Gen evidence is now in the ledger and the inventory,
and nothing is claimed about Civil.
A first draft of the per-product comparison also reported eleven endpoints whose
inventory row named a product their confirmed case does not declare. All eleven
were the /db/HHCT shape - npm running an unconfirmed case of the same
endpoint, which is a real run and not a wrong label - and they disappeared when
the comparison was widened to every case for the endpoint. That rule is pinned
by a test.
The seven that are left, and why none is a replay¶
| endpoint | why |
|---|---|
/db/PJCF |
pjcf_unlock reads state back and branches, so it cannot be emitted as a payload |
/db/HECB |
same, stage11_seed + solid11_seed |
/db/HSPT |
same, stage11_seed |
/db/MVHL |
the server renumbers the target id; npm can verify a renumbered seed by name and has no equivalent for a target |
/db/BCGA-M1 |
its setup names /db/BNGR, which has no per-id DELETE, so npm blocks the case rather than leave the model dirty |
/db/DYFG |
the server refused both SDKs on 2026-09-16: the moving-load code must be Eurocode, and the case seeds KSCE |
/db/DYNF |
same refusal, same day |
Four of the seven are harness and fixture design, which is offline work.
/db/DYFG and /db/DYNF are the two worth looking at first and not because of
npm: they are confirmed cases that Python also failed, and a confirmed case
failing is this repository's definition of a regression. Whether the seed
drifted or the product changed is not yet established, and re-running the
harness will not answer it.
2026-09-17 (later) — the npm seed gap closed, and Task I and Task J run¶
Both products assumed on Build 09/15/2026, as read from their About dialogs on
2026-09-16; not re-read this time. Every write ran on
a scratch document, checkpointed under C:/temp first and reset with
/doc/NEW afterwards.
A /doc/NEW with no project open blocked Gen NX¶
The first call of the session was a Python /doc/NEW against Gen NX with no
project open (GET /db/NODE had answered The project is not opened). It
did not answer within 60 s. Afterwards /mapikey/verify still said
connected while GET /db/NODE timed out - the blocked-session signature.
Civil was not called. The author then brought both products back up with an
empty document open, and everything below ran on those. What the product
showed is not recorded, so this is a symptom, not a cause: open a document
before the first /doc/NEW, rather than relying on /doc/NEW to create one.
npm replayed the five confirmed cases it could not express¶
Fixture version 6 closes what was recorded as harness design:
- A seed step may be a per-id DELETE (
{"endpoint": ..., "delete": [ids]}), which is whatDbResource.deletesends. That exportspjcf_unlockandsolid11_seed. stage11_seedreads/db/STAGonly so a full Python run does not create stage 1 twice. It is listed inFRESH_DOCUMENT_SEEDS, and its create branch is exported; the npm harness's collision check refuses loudly if stage 1 ever exists. Any other seed that reads stays unexportable.expected.unorderedtells npm to compare a list as a multiset, which/db/BCGA-M1's probe already did by sorting./db/MVHLneeded no harness change. Its case targets id 2, the table renumbers to the next free id, and the case never declared thevehicleseed that holds id 1. Python always ran that seed with the tier; npm seeds only what a case declares, so its POST landed at id 1.- The emitted setup follows
needs, and HECB's listed the stage before the groups the stage names./db/STCTalso lackedhecb_seed.
| Endpoint | npm Gen | npm Civil | Python Gen | Python Civil |
|---|---|---|---|---|
/db/PJCF |
PASS | PASS | PASS | PASS |
/db/MVHL |
PASS | PASS | PASS | PASS |
/db/HECB |
PASS | PASS | PASS | PASS |
/db/HSPT |
PASS | PASS | PASS | PASS |
/db/BCGA-M1 |
- | PASS | - | PASS |
HECB, HSPT and BCGA-M1 each ran as their own npm invocation, because their
setup touches /db/GRUP or /db/BNGR, which have no per-id DELETE and so may
only be cleaned up by the final document reset. The Python runs printed three
seed failures that no selected case needed: nllp_seed and glink_seed
answered Unknown Error on both products, as recorded before, and on Civil
mvcd_ksce_seed answered Key Already Exist because the moving tier had
created /db/MVCD id 1 earlier in the same run. That one looked like the lead
for /db/DYFG and /db/DYNF and was not; see the next section.
/db/DYFG and /db/DYNF were never a regression¶
They need the moving-load code to be EUROCODE, and extras14 gets there with a
case, not a seed: mvcd_ksce_seed creates /db/MVCD as KSCE-LSD15 for
/db/DYLA, then the tier's own /db/MVCD case PUTs EUROCODE, and only then do
DYFG and DYNF run. The 2026-09-16 runs selected --endpoints /db/DYFG,/db/DYNF,
which filters that switch case out, so the code stayed KSCE-LSD15 and both
SDKs were refused - correctly. Selecting the switch with them
(--tier extras14 --endpoints /db/DYLA,/db/MVCD,/db/DYFG,/db/DYNF) passed all
four on Civil NX, Build 09/15/2026.
npm cannot interleave a case between two others' setups, so the fixture now
declares what those two actually need: a mvcd_eurocode seed, the switch
case's own confirmed update payload, which the two cases name in setup while
setup_replaces keeps mvcd_ksce_seed from being prepended in front of it.
Python still gates them on mvcd_ksce_seed. npm then passed both on Civil.
report_npm_replay_coverage.py reports all 177 confirmed cases replayed by npm
on every product they declare.
The rule this adds: an endpoint selection can drop a case another case depends
on, and the Python harness does not warn. In extras14 that case is /db/MVCD.
Task I: DESIGN/STEEL/DSTL takes a write on Gen, and Civil refuses it¶
On a fresh document GET answered {"message": ""} on both products.
PUT {"Assign": {"1": {"DGNCODE": "KDS 41 30 : 2022"}}} then:
- Gen NX accepted it, answered
{"DSTL": {"1": {"DGNCODE": "KDS 41 30 : 2022"}}}, and a followingGETreturned the same record. - Civil NX answered
[Error] Errors detected in Steel Design Control Data.(Item:)and a followingGETwas still{"message": ""}.
The manual's request shape is therefore right, on Gen. There was no original
value to put back, so the revert was the document itself: the scratch model
was saved under C:/temp and replaced with /doc/NEW, after which GET
answered {"message": ""} again. No DELETE was sent. The enum has one
documented value, so nothing was varied on Civil; the wording matches the
refusal /db/DSTL gave for most code names in batch 13 (2026-08-17), but what
Civil needs is not established. docs/coverage.json records the endpoint
at level: "write" for Gen alone, as the ledger does for every write verified
on one product; the Civil read of 2026-09-16 is still in its method.
Task J: USE_HAMBLY_EQ is absent from a DB/User solid section's record¶
The scratch model's one section was the base model's emitted DBUSER solid
rectangle. GET /db/SECT returned no SECT_AFTER block at all and a
SECT_BEFORE without USE_HAMBLY_EQ, on both products. That is one section
type, created without the field, so it says only that the product does not add
the property to a record of that type. A section type that carries
SECT_AFTER - a composite section - is where the property would be expected,
and no confirmed fixture builds one; the probe stopped rather than write one
from memory.
2026-09-18 - Task G assertions made meaningful and re-confirmed¶
Both products were open on Build 09/15/2026. Their own MAPI keys returned empty
/db/NODE and /db/ELEM tables before the first mutation. The built npm
package ran first and the Python harness ran second, using the same emitted
fixture. Every run checkpointed under C:/temp, created a disposable base
model, and restored an empty scratch document afterwards.
| Endpoint | Products | Assertion that passed in both SDKs |
|---|---|---|
/db/MATD |
Gen, Civil | MAINREBAR_B_FY was absent on the base material and read back as 500000 after PUT |
/db/IEHC |
Gen, Civil | BEAM_LOC read back as 1 after POST and 2 after PUT |
/db/POLC-M1 |
Civil | NLTYPE read back as PDELTA after POST and NONE after PUT |
The prior checks could pass without proving their update: MATD asserted the pre-existing material name, while IEHC and POLC-M1 sent identical create and update payloads. These corrected payloads were marked unconfirmed before the run and restored to confirmed only after all product/SDK combinations above passed.
Re-deriving the standing safeToOmit survey changes no candidate: MATD has no
create call, while IEHC and POLC-M1 are not among its 57 candidate fields. The
result remains 21 grounded claims and 36 honestly unverified candidates.
Task K: current-build core batch¶
The first eight-endpoint Task K batch replayed /db/LDGR, /db/NODE,
/db/SKEW, /db/STLD, /db/CNLD, /db/BMLD, /db/CONS, and /db/MVCD
through npm and Python on both Gen and Civil. All 32 endpoint/SDK/product
combinations completed the emitted create/read/update/read/delete sequence on
Build 09/15/2026.
The first npm attempt exposed a fixture-only block: the shared base model
already contains node 2 and static load cases 1 and 2, while the SKEW and STLD
cases redundantly replayed the same named seeds. npm correctly refused the two
collisions. Removing those redundant case-level setup declarations made the
fixture agree with the base model; both cases then passed through both SDKs on
both products. Every attempt checkpointed under C:/temp and restored an empty
scratch document.
Task K: current-build properties batch¶
/db/THIK, /db/ESSF, /db/SECF, /db/TSGR, /db/TDMT, and /db/TDME
then replayed cleanly through npm and Python on both Gen and Civil, Build
09/15/2026. All 24 endpoint/SDK/product combinations passed, with checkpoints
under C:/temp and an empty scratch document restored after every run.
Task K: current-build boundary batches¶
The boundary tier was split at the eight-endpoint limit. /db/NSPR,
/db/GSTP, /db/GSPR, /db/ELNK, /db/RIGD, /db/MCON, /db/FRLS, and
/db/OFFS passed first; /db/SSPS passed separately. npm and Python both
completed every case on Gen and Civil, Build 09/15/2026: 36
endpoint/SDK/product combinations in total. Each run checkpointed under
C:/temp and restored an empty scratch document.
Task K: current-build properties extras3 batch¶
Gen replayed /db/GRDP, /db/EDMP, /db/PSSF, /db/VSEC, and /db/VBEM;
Civil replayed those five plus its declared /db/STRPSSM and /db/EWSF
cases. Both npm and Python passed every selection on Build 09/15/2026, for 24
endpoint/SDK/product combinations. The unsupported Gen cases were excluded
before product calls rather than misreported as failures. Every live run used
C:/temp checkpoints and restored an empty document.
Task K: current-build extras2 batches¶
The eleven remaining extras2 cases were split into selections of eight and
three. Gen ran every case except the Civil-only /db/PLCB; Civil ran all
eleven. /db/SMPT, /db/SMLC, /db/PLCB, /db/LDSQ, /db/IELC,
/db/IFGS, /db/EFCT, /db/INMF, /db/GTMP, /db/STMP, and /db/BTMP
all passed through npm and Python on every declared product, Build 09/15/2026.
The 42 endpoint/SDK/product combinations used C:/temp checkpoints and ended
on empty scratch documents.
Task K: current-build extras13 design batch¶
/db/DCON, /db/LENG, /db/MEMB, /db/DCTL, /db/LTSR, /db/MBTP, and
/db/WMAK passed through npm and Python on Gen and Civil, Build 09/15/2026.
The first npm attempt blocked five cases because their explicit design-model
setup overlapped the shared base model. The fixture now marks those known
material, section, node, element, and plate replacements explicitly instead
of weakening collision checks. The corrected fixture then passed all 28
endpoint/SDK/product combinations. Each attempt restored an empty document.
Task K: current-build extras4 load-combination batch¶
/db/LCOM-GEN, /db/LCOM-CONC, /db/CUTL, and /db/CLWP passed through
both SDKs on Gen and Civil; the confirmed Gen /db/LCOM-SEISMIC case passed
through both SDKs on Gen. Its old case-level static-load seed was removed
because both harnesses already build the same DL record in the shared base
model. All 18 endpoint/SDK/product combinations passed on Build 09/15/2026,
with C:/temp checkpoints and empty documents restored afterwards.
Task K: current-build extras10 hydration batch¶
/db/ETFC, /db/CCFC, and /db/HSFC passed through npm and Python on Gen
and Civil, Build 09/15/2026. All 12 endpoint/SDK/product combinations passed;
each run checkpointed under C:/temp and restored an empty document.
Task K: current-build extras15 assignment batch¶
/db/IEPI, /db/EXLD, /db/PRST, and /db/POLC passed through npm and
Python on Gen and Civil, Build 09/15/2026. All 16 endpoint/SDK/product
combinations passed; each run checkpointed under C:/temp and restored an
empty document.
Task K: current-build dynamic Hyper-S controls batch¶
The Civil-only /db/THGC-M1 and /db/THOO-M1 cases passed through npm and
Python on Civil NX 2026 v2.2, Build 09/15/2026. Both SDKs completed each
PUT/read/update/read/per-id DELETE sequence, for four endpoint/SDK/product
combinations. Both runs checkpointed under C:/temp and restored an empty
scratch document.
Task K: current-build extras6 seismic-device batch¶
/db/SDVI, /db/SDVE, and /db/SDST passed through npm and Python on Gen
and Civil; the Gen-only /db/SDHY and /db/SDIS cases passed through both
SDKs on Gen. All 16 endpoint/SDK/product combinations passed on Build
09/15/2026. Every run checkpointed under C:/temp and restored an empty
scratch document.
Task K: current-build extras8 analysis-control batch¶
/db/EIGV, /db/MVCT, and /db/SMCT passed through npm and Python on Gen
and Civil NX, Build 09/15/2026. All 12 endpoint/SDK/product combinations
passed; each run checkpointed under C:/temp and restored an empty scratch
document.
Task K: current-build extras7 nodal-load batch¶
/db/PNLD passed through npm and Python on Gen and Civil NX, Build
09/15/2026. All four endpoint/SDK/product combinations passed, checkpointed
under C:/temp, and restored empty scratch documents. The Civil Python tier
also printed unrelated best-effort seed warnings for posp_seed and
posl_seed; neither is a PNLD prerequisite, and the selected PNLD case
still completed its full create/read/update/read/delete/read round trip.
Task K: current-build extras16 material batch¶
The confirmed Gen-only /db/EPMT case passed through npm and Python on Gen NX
2026 v2.1, Build 09/15/2026. Both SDKs completed the full
create/read/update/read/delete/read round trip, checkpointed under C:/temp,
and restored an empty scratch document.
Task K: current-build extras5 dynamic-load batch¶
/db/SPLC, /db/THGC, and /db/THFC passed through npm and Python on Gen
and Civil NX, Build 09/15/2026. All 12 endpoint/SDK/product combinations
completed full round trips. Keeping this selection inside extras5 avoided
the documented cross-tier SPLC seed collision; all runs checkpointed under
C:/temp and restored empty scratch documents.
Task K: current-build China and India lane batches¶
The Civil-only /db/LLANch, /db/SLANch, and /db/LLANid confirmed cases
passed through npm and Python on Civil NX 2026 v2.2, Build 09/15/2026. The
China and India code selections were kept in separate tier runs. All six
endpoint/SDK/product combinations passed, with C:/temp checkpoints and empty
scratch documents restored afterwards.
Task K: current-build moving-control batches¶
/db/MVCTbs and /db/MVCTtr passed through npm and Python on Gen and Civil;
the Civil-only /db/MVCTid case also passed through both SDKs on Civil NX,
Build 09/15/2026. Each case selected its own moving-load code (BS, INDIA,
or TRANS) in a separate setup/cleanup sequence. All 10
endpoint/SDK/product combinations completed full round trips, checkpointed
under C:/temp, and restored empty scratch documents.
Task K: current-build /db/NMAS replay¶
/db/NMAS passed create/read/update/read/delete/read through npm and Python on
Gen NX and Civil NX, Build 09/15/2026. The case uses NODE 3 from the shared
base model; its obsolete duplicate setup was removed because npm correctly
refuses overwriting a base-model record. Both products checkpointed under
C:/temp and restored an empty scratch document after the run.
Task K: current-build extras1 completion batches¶
/db/TDGR, /db/NPLN, /db/PRLS, /db/MLFC, /db/CO_M, /db/CO_S,
/db/CO_T, /db/STYP, and /db/CLDR passed through npm and Python on Gen NX
and Civil NX, Build 09/15/2026. Civil-only /db/STYP-M1 passed through both
SDKs on Civil NX. The four PUT-only color/type cases ran as isolated npm invocations so
the document reset, rather than a nonexistent DELETE operation, was their
cleanup. Every run checkpointed under C:/temp and restored an empty scratch
document. Python's extras1 diagnostic still reports the independently known
nllp_seed/glink_seed failures, but each selected case completed its own
round trip.
MIDAS-API manual-error probes requested 2026-09-18¶
Targeted probes from
MIDAS-API/docs/error_reports/live_verification_requests_20260918.md ran on
Gen NX 2026 v2.1 and Civil NX 2026 v2.2, Build 09/15/2026. Each probe saved
the disposable document under C:/temp, rebuilt its documented preconditions,
and used a GET after the write rather than treating a 2xx status as success.
/ope/MEMB: the documentedSELECTION_TYPEand table typoSELETION_TYPEboth selected and persisted elements 2 and 3 on Gen and Civil. The typo behaves as an accepted alias on this build./db/SSEIS: Gen acceptedKDS(41-17-00: 2019)and normalized it toKDS(41-17-00:2019). The two example typosIINHERENT_TORSIONandNHERENT_TORSIONreturned HTTP 201 but disappeared from the response; GET kept the realINHERENT_TORSIONfield atfalseinstead of the requestedtrue./db/TDNA: both products accepted and persisted the official 2D and 3D Round/Element examples' numericRADIUSvalues. Both products returned an HTTP 201 body containingWrong FieldforPROFY.RADIUS=falseand forPROF.RADIUS=[0,20]; GET then returnedNot Found Key. The two conflicting specification rows must be Number, not Boolean or Array./db/MATD: Gen persistedbSERVCHECK=true,dSHORTTERM=1.25, anddLONGTERM=1.5, both separately and together. Civil echoed each field in its HTTP 200 PUT response but omitted all three from the following GET, so they are accepted-but-ignored on Civil in this build./db/SPLC: on Gen, POST persistedaACCECC_ECCEN_LIST[0].ALONG=2.5. A following PUT echoed the requested value3.5, but GET retained2.5; updating ALONG is silently ignored on this build even though creation works.
The Jira-ready Korean response is in the manual repository at
docs/error_reports/live_verification_feedback_20260918.md. Raw response
captures remain only in C:/temp/manual-feedback-*.json; model response
bodies are deliberately not committed here.
Task K: current-build final extras1 batch¶
/db/PZEF passed through npm and Python on Gen NX and Civil NX, while the
Civil-only /db/SPAN case passed through both SDKs on Civil NX, Build
09/15/2026. The npm runner required the no-DELETE /db/PZEF case to run last;
after correcting that ordering, all six endpoint/SDK/product combinations
completed their full case. Python's extras1 diagnostic printed the already
known, unrelated nllp_seed and glink_seed warnings, but both selected
cases passed. Each run checkpointed under C:/temp and restored an empty
scratch document.
Task K: current-build final extras14 batches¶
The Civil-only /db/CRGR, /db/CJFG, /db/DYLA, /db/ACTL-M1,
/db/EIGV-M1, /db/HHCT-M1, /db/NLCT-M1, /db/STCT-M1, and
/db/BCGD-M1 confirmed cases passed through npm and Python on Civil NX 2026
v2.2, Build 09/15/2026. npm ran /db/CRGR, /db/CJFG, and /db/DYLA
individually because their /db/GRUP setup has no per-ID cleanup and therefore
must be last; the earlier runner guard was a batch-order block, not an endpoint
failure. All 18 successful endpoint/SDK combinations completed their full
round trips, checkpointed under C:/temp, and restored empty scratch
documents.
2026-09-19 — Task A batches 17 and 18, first live run¶
Both products on Build 09/15/2026 (Gen NX 2026 v2.1, Civil NX 2026 v2.2). The
first read-only check found no project open on either product —
GET /db/NODE answered The project is not opened with each product's own key
while /mapikey/verify still said connected — so nothing was run until the
author opened a New Project in both. The re-check then read 0 NODE and 0
ELEM records on each, and was repeated before every run. The built npm
package ran first and the Python harness second, on Gen then Civil, same
session, same emitted fixture. Every run checkpointed under C:/temp and
restored an empty scratch document.
npm and Python agreed on every endpoint and product:
| Endpoint | Gen | Civil |
|---|---|---|
/db/TDNT |
pass | pass |
/db/POGD |
Wrong Field |
pass |
/db/POGD-M1 |
— (Civil only) | pass |
/db/PHGE |
Unknown Error |
Unknown Error |
/db/TDNA |
see below | see below |
/db/TDPL |
blocked by the TDNA seed | blocked by the TDNA seed |
/db/TDNT, /db/POGD (Civil) and /db/POGD-M1 are write-level from this run;
the ledger is 204 write.
/db/TDNTpassed with the ch07 section 6 KSCE LSD15 example as written. That example sends none ofFT,FPKorTDMFNAME, which the chapter's Specifications table marks Required without a condition. The pass is live evidence for theappliesWhenonRMthose three fields now carry: the product does not require them under RM 6./db/POGDis product-asymmetric: the identical payload passes on Civil and answersWrong Fieldon Gen, through both SDKs. It is now one case per product, the pattern/db/EPMTalready uses.Wrong Fieldusually names a bad value rather than a bad field name, so the enums in ch14's common control fields are where to look first./db/PHGEansweredUnknown Erroron both products, with ch14's own two-element hinge-assignment example on the base model's elements 1 and 2./db/TDNAfailed in two stages, and the first one was a fixture defect. The ch07 section 7 example sendsTDN_GRUP: 1and assumes tendon group 1 exists; without it both SDKs got[Error] Tendon Group 1 does not exist.— a domain error, so the shape was accepted and the target was missing. A/db/TDGRseed built from extras1's confirmed case fixed that, and the retry answered, on both products and through both SDKs:
[Error] Errors detected in Tendon Profile Data.(Item:IS_DB_TDNA_NOTENSIONCALC : Not Registered String)
The item named is an internal resource-string id the product could not look
up (Not Registered String), so the message itself is broken as well as the
request refused. "No tension calc" reads as a model-state precondition — the
base model's beams carry a DB/User solid section, not a PSC one — but that
is a reading, not a finding. It was not chased by permuting fields; the
case stays unconfirmed, and /db/TDPL stays blocked behind it.
2026-09-19 (later) — Task B on Build 09/15/2026: nothing moved¶
Same session as batches 17 and 18, both products still on Build 09/15/2026,
the read-only 0-record check repeated before every run. Of Task B's 22
endpoints, the 15 that were neither settled product behaviour (/db/ACTL,
/db/FIMP, /db/STCT) nor blocked behind nllp_seed (/db/NLLP,
/db/NLNK, /db/NLNK-M1, /db/CGLP) were run, because none of the 15 had
been run on this build — the last recorded attempts are 2026-09-04 to
2026-09-14. npm then Python, Gen then Civil. The four lane_code_* seeds all
POST /db/MVCD id 1, so each moving-load code had an invocation of its own.
Every endpoint answered what it answered on the earlier build, word for word, and npm and Python agreed on every one:
| Endpoint | Gen | Civil |
|---|---|---|
/db/EPSE, /db/EPST |
Wrong Field |
— (Gen only) |
/db/RPSC, /db/TDMF |
Wrong Field |
Wrong Field |
/db/WVLD |
— (Civil only) | Wrong Field |
/db/HPCE |
Wrong Key |
Wrong Key |
/db/FBLA |
Unknown Error |
Unknown Error |
/db/MVLDeu |
Unknown Error |
Unknown Error |
/db/MADO, /db/SBDO, /db/DOEL |
POST accepted, record absent on read-back | same |
/db/SINF |
POST accepted, id 1 absent on read-back | same |
/db/MVLDpl |
— (Civil only) | POST accepted, id 1 absent on read-back |
/db/MVLDch |
— (Civil only) | [Error] Moving Load Case Data (Name:MV_Case1) contains errors.(Item:Non-existent Vehicle has been defined in Sub-Load Case.) |
/db/MVLDid |
— (Civil only) | [Error] Moving Load Case Data (Name:MV_India_1) contains errors.(Item:Number of Sub-Load Cases) |
That is a result, not an absence of one: a new build changed none of these, so none of them is build-transient. Do not re-run any of the 15 against this build with an unchanged fixture — it has now been asked.
fbld7_seed was missing from RENUMBERING_SEEDS, so npm never tested /db/FBLA¶
npm's first pass reported /db/FBLA as BLOCK — /db/FBLD: id 90 missing after
setup POST on both products, while Python reached FBLA and got Unknown
Error. The two SDKs were not disagreeing about the product; they were testing
different things. /db/FBLD renumbers to the next free id (confirmed live
2026-08-16), and extras7's own seed docstring says so — "pnld_seed/fbld7_seed
both land at id 1, not the requested 90" — but only pnld_seed had been
registered. npm, which verifies every seed record by id, stopped at the seed;
Python, which does not, carried on to FBLA, whose payload names the load type
rather than its id. fbld7_seed is now registered, and npm reaches FBLA and
answers Unknown Error exactly as Python does.
Leads, not findings¶
/db/MVLDchneeds a vehicle. Its sub-load case names the China classCH(CJJ11)_C-CD(A/B), and itsneedsbuild the lane code and the lanes but no vehicle; the message says as much. No confirmed case builds a China vehicle — the fixture's vehicle cases are AASHTO/db/MVHLand/db/MVHLtr— so a seed needs a China vehicle payload from ch08, not one written here./db/MVLDid'sNumber of Sub-Load Casesis a domain message about a count, the same class as/db/SPAN's item-count-vs-list-length rule.- Of the five "accepted, then absent" endpoints, three ask for id 1 in an
empty table (
/db/SBDO,/db/SINF,/db/MVLDpl), so renumbering cannot explain them the way it explained FBLD: the next free id is the one requested, and they drop the write./db/MADO(id 92, beside its seeds' 90 and 91) and/db/DOEL(id 4) do not rule renumbering out on this evidence alone; extras9 records MADO dropping writes on both products.
Task B, same session: /db/MVLDch and /db/MVLDid pass once they have a vehicle¶
Both leads from the run above were offline questions first, and both had the
same answer. A ch08 country load case's sub-load names a vehicle — despite the
key, VEHICLE_CLASS with VEHICLE_TYPE: "VL" names a /db/MVHL record, not
a /db/MVHC class — and neither case's needs built one.
- India is paired by the manual itself. Section 14's General Load Python
example names
IN(IRC6)_ClassA, which is section 10's India example (MVLD code 7,STANDARD_CODE: "IRC:6-2000", standard Class A). The fixture had used section 14's Request Body instead, whose railway vehicleIN(IRC)_(25t1)_BroadGauge-1676mmno section documents creating. The case now names Class A and a seed creates it. - China is not paired. Both of section 13's examples name the standard
class
CH(CJJ11)_C-CD(A/B), which no section documents creating, and the only China vehicle section 10 documents is the user-definedCN_UD_Lane1(MVLD code 3,VEH_CNTruck/Lane, noSTANDARD_CODE). The case names that one: a model reference remapped, as element and lane references already are, not a value invented.
With the vehicles seeded, both passed a full round trip on Civil NX through
both SDKs — create, read, update, read, per-id DELETE, read. The India
result also answers the lead the run above recorded: Number of Sub-Load
Cases was the missing vehicle too, not a count rule — NUM_LOADED_LANES was
left at the example's 2, beside one sub-load item. A sub-load whose vehicle
does not exist is evidently discarded, and the case is then refused for
having none.
Two more things this run established:
- The country cases' update now proves a PUT. It had equalled the create,
so it could not fail (the Task G class). It changes
DESCalone — the probe/db/STLD's confirmed case uses — and both cases read backcrud updated./db/MVLDeuand/db/MVLDplshare the helper and get the same update; both still fail before it, as recorded above. /db/MVHLaccepted and stored both country shapes, since npm verifies every seed record by id: a user-defined China vehicle withVEH_CNand noSTANDARD_CODE, and a standard India vehicle withSTANDARD_CODEand noVEH_*object. That matches what the SDK's own class docstring recorded from a real Eurocode model on 2026-07-30 — country vehicles carry theirVEH_*object instead ofVEH_DEFAULT, and not necessarily aSTANDARD_CODE— and it is the first time either of these two shapes has been written./db/MVHLwas already write-level, so no count changes.
/db/MVLDch and /db/MVLDid are write-level on Civil, and the ledger is 206
write. Gen has neither code, so Gen's evidence for both stays the read.
Task B, same session: the five Wrong Field cases are not bad values¶
The standing advice is that Wrong Field usually names a bad value, so vary
a documented enum value before any field name. None of the five contracts
declares an enum on a field these payloads send; the value sets live in
field descriptions. Measured against those, and against the history:
/db/EPST— every documented value set is now exhausted. 2026-08-16 had variedSEL_TYPEandEP_TYPE; this session varied the remaining two, one at a time, through the Python harness on Gen with a temporary edit that was reverted afterwards:ELEM_TYPE: "PLANAR"on the base model's plate element 4, andDIR: "NORMAL". Both answeredWrong Field. EPST's failure is not a value its descriptions offer./db/EPSEshares every one of those fields and fails identically; it was not probed separately./db/WVLD— value-independent. A bare{"NAME": ...}answeredWrong Fieldon 2026-08-16, so no value in the payload is the cause; varyingTHEORY,CHAR_TYPEorVERT_COORDcannot answer anything./db/RPSC— the manual's own example with its documented values fails. Comparing the payload withGET /info/db/RPSCturned up one member the fixture never sends,MBARS[].MBAR_ITEMS[].PART. The contract and ch04 both record it, as an Integer with no default, no requiredness and no value in any example, so sending it means inventing one. Stopped there./db/TDMF— no field it sends states a value set; the CREEP/CTYPEbody was the chapter's own, and was tried on 2026-09-14.
One false lead, recorded so the next session does not follow it: every one of
the 399 /info schemas in schema/info-baseline.json roots its record at
Argument, /db/NODE included, so RPSC's Argument root says nothing about
its request wrapper.
2026-09-20 — Task P /db/PTNS¶
The final mechanically buildable /db case passed through the built npm
package and Python SDK on Gen NX 2026 v2.1 and Civil NX 2026 v2.2, Build
09/15/2026. Each product started from an empty document verified with its own
key. The fixture used the manual's TRUSS shape on element 5 and base-model
nodes 21-22, created the existing PS15_SEED prestress load case, registered
it through /db/EXLD, then completed PTNS create/read/update/read/delete/read.
The update changed TENSION from 130 to 260 and both SDKs read back the change.
Every run checkpointed under C:/temp and restored an empty scratch document.
2026-09-20 (later) - Task P's fixture stops sharing extras15's seeds¶
The PTNS case above borrowed extras15's prestress_load_cases seed by
splicing that tier's seed list into extras19's, and put its truss on the base
model's node pair 21-22. Both were wrong for the same reason: a tier's seeds
are not per-case. The runner executes every seed of a selected tier before
that tier's cases, so a selection holding extras15 and extras19 - which is
what a full re-verification is - POSTed the same /db/STLD records twice, and
/db/STLD renumbers, so the second POST would have left two load cases
answering to the name the fixture looks up. Nodes 21-22 are the pair the base
model keeps unattached so ELNK, RIGD and MCON cannot collide with a real
element; the truss attached one to them.
The fixture now builds its own nodes 51-52, its own PS19_SEED load case and
registers that name through /db/EXLD. Re-run on Build 09/15/2026 through
both SDKs: PTNS passed on Gen and Civil, and /db/EXLD, /db/PRST and
/db/PTNS passed together in one Gen selection, which is the combination the
old arrangement would have broken. /db/EXLD id 1 is still shared with
extras15's own case, which deletes it before extras19's seed re-creates it -
TIERS is ordered, so that sequence is fixed.
2026-09-20 (later) - review fixes, re-run on Build 09/15/2026¶
A code review of the untagged batch found four defects in the harnesses. Two were only reachable live, so extras13's five design cases - the only ones whose setup replaces a shared base-model record - were re-run on Gen and Civil through both SDKs. All five passed on both products with no cleanup errors.
The npm harness detects what a setup step created by diffing against a
snapshot taken before the step, so an id a replaceExisting seed overwrote
never looked new and cleanup left it in place. The fixture's steel S450 stayed
at material 1, its H300x150 at section 1, and nodes 1-4, element 2-3 and
thickness 1 likewise, for every later case in the same invocation. Nothing has
misreported because of it - the batches this is run in are small and the
design tier sits late - but a confirmed case running against a base model
nobody rebuilt is how a healthy SDK prints REGRESS. Cleanup now restores the
base-model record.
The Python harness's read-back probe subscripts the record it is handed
(p["ITEMS"][0]["END"]), and only MidasAPIError was caught, so a record the
product returns in another shape raised KeyError out of the tier loop: no
report, no end-of-run checkpoint, and the product left holding the fixture's
model. An unreadable record is now a failure of that case and nothing else.
2026-09-21 - /db/REBW was already write level, and the ledger had lost it¶
Nothing new was run. Consolidating the ledger put the two records for
/db/REBW side by side, and they disagreed: db-rebw-live-shape-2026-07-29
in contracts/verification/gen-nx.yaml describes a PUT round trip against a
real production Gen NX model - wall 101's record backed up, VER_BAR.DIST
changed from 0.2 to 0.99, the change confirmed on a fresh read, then reverted -
while docs/coverage.json had the endpoint at read level.
The ledger's own definition settles it: write means a live call actually
mutated model data, and that PUT did. What happened is a property of the old
shape rather than of the evidence. An endpoint had one prose method field,
and on 2026-08-27 a read-sweep narrative about /info/db/REBW field names was
written into it, overwriting the write evidence that had been there since
2026-07-29. The session record kept it; the per-endpoint field could not.
/db/REBW is now write level on Gen, dated 2026-07-29 on build 07/28/2026,
which is the session that earned it. Published coverage moves from 207 write /
193 read to 208 / 192, and ROADMAP's version matrix gains the 2026-07-29 Gen
row that endpoint had been the only citer of.
This is also why the new ledger appends rather than edits: a record is what one session saw, and a later session writing over it loses evidence nobody notices is gone.
2026-09-21 - the vendor report re-measured on both products, and two of its claims sharpened¶
The author had both products open and asked for the report's items to be
checked as of today. Scope chosen by the author: the fixture replay, not
A-2 (its reproduction empties a table) and not A-7 (it needs a document
opened from Program Files and, if it reproduces, a human to dismiss a modal).
Both documents were empty before anything ran (GET /db/NODE and /db/ELEM
answered 0 records under each product's own key), every destructive run
checkpointed under C:/temp, and both products were left on empty documents.
No build string was read this session. The API reports none, so every one
in this file is a human reading the About dialog; the /info comparison below
says the surface matches Build 09/15/2026's and nothing stronger than that.
The API surface has not moved. A fresh GET-only /info capture of both
products diffed against schema/info-baseline.json shows exactly one change,
/db/SECT gaining SECT_AFTER.USE_HAMBLY_EQ and SECT_BEFORE.USE_HAMBLY_EQ
on both - which is the already-recorded Build 09/15/2026 delta against a
baseline captured 2026-09-03. Nothing else. That is not proof the build is
unchanged and it was not treated as one: /db/NMAS is the standing proof that
behaviour can change while /info does not, which is why the writes were run
anyway.
Reproduced, unchanged¶
| item | endpoint | what happened today |
|---|---|---|
| A-3 | /db/CONS |
sent an 8-character CONSTRAINT, stored 7, both products |
| A-3 | /db/MVHL |
VEHICLE_TYPE_NAME: "NOT-A-VEHICLE" stored verbatim, both |
| A-3 | /db/SECF |
key naming no section: POST ok, table empty, both |
| A-3 | /db/STCT |
Gen: wrote 30, read back None - iITER dropped |
| A-3 | /db/SBDO, /db/SINF |
id 1 missing after wrote, both |
| A-3 | /db/MVLDpl |
id 1 missing after wrote, Civil |
| - | /db/MADO, /db/DOEL |
id 92 / id 4 missing, both - populated tables, so still not separable from a renumber |
| A-4 | seventeen calls | every refusal in the A-10 batch arrived as HTTP 201 with an error body |
| A-6 | /db/TDMT |
an unrecognised CODE answers Wrong Field |
| A-8 | /DESIGN/*, IEHG trio |
404 on both products; /db/* answers |
| A-9 | /db/POSL |
Civil /info declares CODE in 8 properties; sending CODE: "" answers Wrong Field; the same payload without it is accepted |
| A-10 | all nine + /db/RPSC |
each answered its exact recorded message on both products |
A-10 in full, from the harness rather than by hand: Wrong Field for
/db/TDMF, /db/RPSC, /db/EPST, /db/EPSE and /db/WVLD; Wrong Key for
/db/HPCE; Unknown Error for /db/FBLA, /db/PHGE, /db/MVLDeu and
/db/NLLP. /db/WVLD is the Civil case and /db/EPST//db/EPSE the Gen
ones, so "both products" means each on the product that declares it.
Two claims that got sharper, one that got weaker¶
/db/SECF is an echo, not just a silent success. The report recorded a 200
with no error. What the product actually returns is the whole record echoed
back - {"SECF": {"4": {"ITEMS": [{"ID": 1, "AREA_SF": 1.2, ...}]}}} - while
GET /db/SECF answers {"message": ""}. That is the same signature as
/db/CONS and /db/MATD, not a weaker cousin of them, and the report's
wording is now that.
/db/STBK's LCNAME is weaker evidence than it was being used as. The
claim that /info is not a superset of what the server accepts rested partly
on LCNAME being absent from /info while a confirmed round trip sends it.
The call does succeed on both products. But the record read back afterwards is
{"NODE1": 1, "NODE2": 2, "DX": 0, "DY": 0.005, "DZ": 0, "GROUP_NAME": ""} -
no LCNAME. So what is established is that the field is tolerated, not
that it is stored, and whether it had any effect is unmeasured. /db/POSL is
doing all the work in that direction and it is doing it well; /db/STBK is now
stated as the weaker observation it is, in the report and in CLAUDE.md.
A first probe that answered nothing, and why it is recorded¶
/db/MVHL's first run reported the bogus vehicle name as not stored, which
would have contradicted the report. It was wrong: the probe called
_seed_model only, and /db/MVHL's case declares needs: [mvcd, vehicle] -
without the /db/MVCD selector carrying CODE: "AASHTO LRFD", the POST is a
no-op for an unrelated reason. Re-run with the seed taken from the fixture, the
name stores verbatim on both products.
This is the fifth time a missing tier seed has read as a product finding. The
rule it keeps proving: a probe that skips the fixture's own needs is not
measuring the endpoint.
Not measured today¶
A-2 and A-7 by the author's choice, above. A-5 needs the product to be killed.
/db/STCT on Civil reported BLOCKED rather than a result - see the
correction in the next section, because the reason recorded here first was
wrong. /db/MATD and /db/SSEIS came from
scripts/live_manual_feedback.py's probes rather than the CRUD fixture and
were not re-run in the batch above. /db/SPLC's round trip passes; the
ALONG-ignored-on-update half is not what that case measures.
2026-09-21 (later) - the rest of the report, on a dummy model built for it¶
The author asked for the remaining items to be measured with a dummy model
rather than left as debt. scripts/live_crud_check.py's _seed_model builds
it - 10 nodes, 4 elements, 2 static load cases - and every run checkpointed
under C:/temp and ended on an empty document. Both products were confirmed
empty before and after.
A-2 reproduces, and the contrast now sits in one session¶
Measured on both products, on a model built to be destroyed:
| call | before | after |
|---|---|---|
DELETE /db/NODE/6 (per-id, undocumented) |
NODE 10, ELEM 4 | NODE 9, ELEM 3 |
DELETE /db/STLD + {"Assign": {"1": {}}} |
STLD 2 | STLD 0 |
DELETE /db/NODE + {"Assign": {"3": {}}} |
NODE 9, ELEM 3 | NODE 0, ELEM 0 |
The per-id form does exactly what it should, including taking the one element
that depended on node 6. The documented body-with-ids form ignores the id and
empties the table, and on /db/NODE it takes every element with it - one call,
whole model. Identical on Gen and Civil.
That is the strongest form of this finding recorded so far, because the correct behaviour and the destructive one are two calls apart in the same session on the same model, rather than compared across sessions.
A-3's remaining three, through their own probes¶
scripts/live_manual_feedback.py --case b1 and --case b2, which is where
these were measured on 2026-09-18:
/db/MATD- Gen storesbSERVCHECK,dSHORTTERManddLONGTERMindividually and together; Civil's record carries none of the three in any of the five variants, baseline included, while the PUT answers 200./db/SPLC- POST storesALONG: 2.5; the PUT to3.5answers 200 and echoes 3.5; the following GET still reads2.5. Gen./db/SSEIS- the realINHERENT_TORSIONround-trips totrue. Both article typos,IINHERENT_TORSIONandNHERENT_TORSION, vanish from the 201 response body and leave the real fieldfalse.
Correction: /db/STCT's Civil block is a fixture seed, not the product¶
The batch earlier today recorded Civil's /db/STCT case as BLOCKED because
"Civil pre-populates the stage-control record". That attribution was wrong,
and the harness's own message said so: id 1 already exists before this case
ran; a seed in this selection owns it. A seed in extras11 creates it.
Measured directly on a freshly seeded model, GET /db/STCT answers
{"message": ""} on both products - neither pre-populates it - and the PUT
is refused because there is no record to update. The 2026-08 observation of a
pre-existing record on Civil was on a model with construction staging in use,
which is also where that table becomes POST/DELETE-locked.
So the Civil half of /db/STCT still has not been measured, and now the
precondition is known: it needs a model with construction stages, not a bare
seed. The Gen half stands on today's wrote 30, read back None.
This is the second wrong attribution in one day, after /db/MVHL's missing
seed. Both came from the same habit - reading a harness result without reading
what the harness said about it.
2026-09-21 (later still) - A-7 reproduced on Gen, and not on Civil, from one call¶
The author asked for A-7 to be measured directly: build a dummy model and save
it under Program Files. Both products were tried, at their request, on a
dummy _seed_model model with a real checkpoint written to C:/temp first.
Same relay, same call, same path shape, opposite results.
POST /doc/SAVEAS -> C:/Program Files/a7-probe-<product>-<stamp>.<ext> |
|
|---|---|
| Civil NX | {"message": "MIDAS CIVIL NX command complete"}, session responsive. ~~/doc/OPEN then succeeded~~ -- wrong, see the correction below: the probe read the absence of an exception, not the answer |
| Gen NX | the HTTP call never answered (read timeout at 60s), and the session was blocked |
The Gen dialog, photographed by the author:
C:/Program Files/a7-probe-gen-20260921T072357Z.mgbx 액세스가 거부되었습니다.
That is A-7's exact signature, on the exact path, and it blocked every /db/*
call until the author dismissed it. Gen was responsive again immediately after.
Two things this session establishes on its own¶
verify_connection() answered connected throughout the block. Every
/db/NODE call timed out while /mapikey/verify answered connected in well
under a second, twice, minutes apart. That is A-5's mechanism, observed
incidentally and more cleanly than the original crash-window measurement: the
relay serves the health check, so it cannot see a product held by a modal.
/doc/SAVEAS did not answer "command complete" here. The standing rule in
CLAUDE.md is that a save which never happened still answers like a success. For
this failure mode it did not answer at all - the call hung until the dialog
was dismissed, and the client gave up first. Both behaviours are real, but
the split drawn here - "a path NX dislikes answers like success, an
access-denied write hangs" - is wrong: Civil answered the identical
access-denied write with command complete. The split is by product. See the
last section of this date.
The GET /db/CAMB re-check was not one¶
GET /db/CAMB on Civil then answered {"message": ""} without blocking, and
this was read as the 2026-07-29 "a plain GET pops the dialog" case failing to
reproduce. It was not a test of that case: it assumed a document opened from
Program Files, and the /doc/OPEN meant to provide one had failed (see the
next section). The 2026-07-29 observation, made with the product's own tutorial
file genuinely located under Program Files, remains the only measurement.
2026-09-21 (last) - A-7 settled, and the probe that got it wrong¶
The author checked the NX host: the Civil file was in neither
C:\Program Files\ nor %LOCALAPPDATA%\VirtualStore\. Then they tried a Save
As from the Civil NX GUI to that folder and Windows itself refused it -
"이 위치에 저장할 권한이 없습니다. 권한은 관리자에게 문의하십시오.", offering
the Documents folder instead. So the account cannot write there through any
path, and no file was ever created by either product.
Both hypotheses above are dead. It is not elevation and it is not UAC virtualization. Civil simply reported a success for a write that did not happen, which is the failure shape CLAUDE.md has recorded since 2026-07-26 - the one this session's Gen result was used to argue it was not.
The probe was the defect, not the API¶
/doc/OPEN knows perfectly well. Measured on both products, on an empty
document (0 nodes, checked immediately before, so a node count can distinguish
"it opened" from "it did nothing"), against a file that certainly does not
exist:
[civil] OPEN C:/Program Files/a7-missing-....mcbz -> {"message": "MIDAS CIVIL NX path is wrong (the file can't open)"} nodes after: 0
[civil] OPEN C:/temp/a7-missing-....mcbz -> {"message": "MIDAS CIVIL NX path is wrong (the file can't open)"} nodes after: 0
[gen] OPEN C:/Program Files/a7-missing-....mgbx -> {"message": "MIDAS GEN NX path is wrong (the file can't open)"} nodes after: 0
[gen] OPEN C:/temp/a7-missing-....mgbx -> {"message": "MIDAS GEN NX path is wrong (the file can't open)"} nodes after: 0
Same message in a writable directory and an unwritable one, so it is about the missing file and not about the permission.
The earlier probe called /doc/OPEN, caught no exception, and printed its
own sentence - "/doc/OPEN on the Program Files path SUCCEEDED - the file
exists" - without ever printing the answer body. The product had answered
path is wrong (the file can't open). HTTP 200, no error key, so
MidasResultError does not fire and nothing raises. A probe that prints a
conclusion instead of the response can only report what it already assumed.
The full chain, every answer read¶
Civil, one session, document empty beforehand, seeded to 10 nodes:
SAVEAS C:/temp/a7-chain-civil-<stamp>.mcbz -> {"message": "MIDAS CIVIL NX command complete"}
SAVEAS C:/Program Files/a7-chain-civil-<stamp>.mcbz -> {"message": "MIDAS CIVIL NX command complete"} <- byte-identical
OPEN C:/Program Files/a7-chain-civil-<stamp>.mcbz -> {"message": "MIDAS CIVIL NX path is wrong (the file can't open)"}
OPEN C:/temp/a7-chain-civil-<stamp>.mcbz -> {"message": "MIDAS CIVIL NX command complete"} nodes: 10
The session stayed alive after each call. So on Civil the information that the
write failed exists in the product and is absent from the SAVEAS response;
the very next call reports it.
What this changes¶
/doc/SAVEAShas two failure shapes and they are per-product, not per-path. Identical call, identical path: Civil answerscommand completeand writes nothing, Gen raises a modal and never answers. The 2026-07-26 "answers like success" and the 2026-09-21 "hangs the call" observations are both real and are not two kinds of path.- "Verify a write with
/doc/OPEN" still holds, and needs one more clause: read the message./doc/OPENreports a missing file honestly, but as a 200 body with noerrorkey, so absence of an exception proves nothing. - Nothing was left behind on the NX host by the Program Files attempts. The
earlier note claiming a stray
a7-probe-civil-*.mcbzis withdrawn. The files underC:/tempare real and are the author's to clear.
Both products were left connected, responsive, and with the dummy model open on
Civil (saved at C:/temp); Gen's document was left empty.
2026-09-22 - /db/SPLC's supplementary rows, one at a time¶
scripts/live_manual_feedback.py --case c1, both products, each document
confirmed empty by GET with that product's own key first, each probe on a fresh
document seeded by _seed_model plus the SPFC_B2 spectrum function, and a
checkpoint under C:/temp before the first /doc/NEW and after each probe. The
build was not re-read this session; the last one recorded is 09/15/2026 on both.
Every probe starts from section 2's no-damping Request Body with aFUNCNAME
pointed at SPFC_B2, and changes what its label says.
| probe | product | POST | read back |
|---|---|---|---|
| the example as printed | both | 201 | as sent; Gen adds bACCECC: false, bAUTO; Civil adds CQCRATIO, iANGLETYPE |
bACCECC: true, rows 25-29 omitted |
Gen | 201 | bACCECC: true, with bACCECC_AUTO: false, bACCECC_CONSIDER_GL and bACCECC_MINIMUM_TORSION supplied |
bNDP: true, NDP omitted |
Gen | 201 | neither bNDP nor NDP |
bNDP: true, NDP: 1.0 |
Gen | 201 | neither bNDP nor NDP |
Modal damping example (iMDTYPE: 1) |
both | 201 | DALL, aDAMPING as sent |
Mass & Stiffness, direct (iMDTYPE: 2, iCOEF: 1) |
both | 201 | MASSC, STIFFC as sent |
Mass & Stiffness, from modal damping (iCOEF: 2) |
both | 201 | iCALC, FP1, FP2, DR1, DR2 as sent |
What it settles:
- Rows 25-29 are not required, even with the switch on. The table marks
them Required directly under row 24's
bACCECCand states no condition, and a confirmed round trip already omitted them withbACCECCat its default; the other half is now measured as well. MD-57. NDPis not required either, and what the server does withbNDPandNDPis open: both are accepted and neither is read back, on this document. That may depend on a design setting the scratch model does not have; nothing here says which.- The damping tables' gates are the manual's own, and the three examples that state them round-trip unchanged on both products.
The contract now carries all four supplementary tables, and ResponseSpectrumLoadCasePayload
is generated from it. Both documents were left empty. Response bodies stay in
the run's JSON outside the repository.
2026-09-22 (later) - /db/ELEM's per-type rows, one at a time¶
scripts/live_manual_feedback.py --case c2, same conditions as the SPLC run
above: empty documents confirmed first, one fresh seeded document per probe,
checkpoints under C:/temp. Each probe is one of section 2's Request Bodies on
the seed's nodes, as printed or with one row the per-type table marks Required
left out. Plane Stress has no printed example, so it is the PLATE one with
TYPE: "PLSTRS". A wall has to stand vertically; the first run put it on the
seed's flat plate corners and Gen answered The geometry of the element no. 10
is incorrect, so the WALL probes were re-run on Gen on the seed's frame nodes
plus one node below node 3.
| probe | Gen NX | Civil NX |
|---|---|---|
TENSTR Cable, as printed (no NON_LEN) |
accepted | accepted |
TENSTR Cable without STYPE |
Errors detected in the Element input data |
same |
TENSTR Cable without CABLE |
accepted; reads back CABLE: 3, NON_LEN: 3.2, no TENS |
same |
| COMPTR Truss, as printed | accepted | accepted |
COMPTR Truss without STYPE |
refused, as above | same |
PLATE without STYPE |
accepted; reads back STYPE: 1 |
same |
PLSTRS with and without STYPE |
accepted; STYPE: 1 when omitted |
same |
| WALL, as printed | accepted; W_CON not in the response or the GET |
The element type no. 5 for the element no. 10 is not supported |
WALL without STYPE |
refused, as above | not supported |
WALL without WALL |
The wall ID no. 0 ... exceeded the possible range ... no. 1 to no. 9999 |
not supported |
WALL without W_CON |
accepted, identical record | not supported |
What it settles, all of it MD-59:
STYPEselects the branch and is required where a table's element has more than one subtype - TENSTR, COMPTR, WALL - and defaults to 1 for PLATE and PLSTRS, where the tables also mark it Required.- Cable's
CABLEandNON_LENare not required. The section's own Cable example omitsNON_LEN; omittingCABLEgets Lu with a server-chosen length. - WALL is a Gen NX element. Civil refuses the type outright, the chapter's own example included, and says nothing about it.
W_CONis accepted and never returned, sent or not, and/infodeclares it on neither product.
ElementPayload is now generated from the contract as a union over
(TYPE, STYPE). Both documents were left empty.
2026-09-22 (later still) - /db/SPFC's design codes, and a save dialog CALC_OPT leaves behind¶
The run that blocked both products¶
scripts/live_manual_feedback.py --case c3 first sent each of section 1's
design-code Request Bodies with CALC_OPT: true added where the body lacks it
(MD-15: without it or an aFUNC the server refuses a design spectrum), one
fresh document per example. On both products the first example
(KDS(41-17-00:2019)) was accepted and saved to C:/temp, and the /doc/NEW
before the second never answered; every later call timed out. The author
confirmed a save-changes dialog on both hosts and restarted both products.
So a CALC_OPT: true record leaves the document modified again after a
/doc/SAVEAS - the server-built curve evidently lands later - and the next
/doc/NEW raises the save dialog, which blocks the whole API session. None of
the SPLC or ELEM probes earlier the same day, which save and /doc/NEW in the
same pattern, did this. A harness must not /doc/NEW after a CALC_OPT:
true write without saving again first, or at all.
What the examples store¶
Re-run without CALC_OPT: each example carries the section's User Type
aFUNC curve instead, all eight in one document, and the table is read back
(this endpoint renumbers a POSTed record). Both products, identical results:
| example | result |
|---|---|
| KDS(41-17-00:2019), IBC2012, CH2010, JPN2000, TAIWAN(2022), IS1893(2016), NBC95 | accepted; STR, OPT and VAL stored where the tables put them. The server pads aSRA to four entries, and adds aMSRACC and TL to IBC2012's VAL |
| EURO2004, as printed | Unknown Error |
--case c4 then varied the EURO2004 body on Gen one change at a time: VAL.AG
for VAL.ag (the /info spelling), OPT removed, and both. All four answer
Unknown Error. /info declares SPECTYPE, GROUTYPE and NATIONALANNEX in
STR, as strings, where the table puts them in OPT; no working EURO2004
request was found, and none was guessed. MD-60.
Both documents were left empty.
2026-09-22 (last) - /db/THIS's four printed Request Bodies¶
scripts/live_manual_feedback.py --case c5: section 6's four bodies, as
printed, into one fresh seeded document per product, read back by name (the
endpoint renumbers). Empty documents confirmed first, both left empty after.
| body | Gen NX | Civil NX |
|---|---|---|
| Linear + Modal + Transient | stored as sent, plus bSUBSEQ: false, iGEOM: 0 |
same |
| Nonlinear + Direct Integration | Unknown Error |
Wrong Field |
| Nonlinear + Static, Load Control | Wrong Field |
accepted; stored without ENDTIME, with bCUMULATE: false for the sent true, iMSTEP: 16 for 10, and iTHTYPE: 1 added |
| Nonlinear + Static, Displacement Control | Wrong Field |
accepted; iMSTEP: 16 for 10, ULSM dropped, iTHTYPE: 1 added |
The seed model has no nonlinear properties, and a nonlinear time history on
it may simply be unanalysable; these results say the printed nonlinear bodies
do not run on a bare model, not which row is wrong, so no contract row is
corrected from them. What they do show: Civil NX takes a Static record without
iTHTYPE (COMMON marks it Required) and rewrites several values it was sent.
Both belong to a session with a nonlinear model before they are claimed.
2026-09-22 (after) - /db/MVHL: MVLD_CODE picks the country object¶
scripts/live_manual_feedback.py --case c6 and --case c7, Civil NX, both
documents confirmed empty first and left empty after. Each country got its
own document with its /db/MVCD CODE from section 1's value table
selected, then section 10's printed body, read back by VEHICLE_LOAD_NAME
(the endpoint renumbers).
| body | MVLD_CODE |
STANDARD_CODE sent |
result |
|---|---|---|---|
| KSCE-LSD15 standard | 13 | "KSCE-LSD15" |
stored as sent |
| KSCE-LSD15 user-defined Truck/Lane | 13 | none | stored as sent, VEH_KSCE_LSD15 included |
| Canada | 8 | "CANADA" |
stored; VEH_CA read back with CENT_F added |
| Australia | 14 | "ROAD TRAFFIC" |
stored; VEH_AU read back with four more members |
| Australia, heading value | 14 | "AUSTRALIA" |
Wrong Field |
| China user-defined Truck/Lane | 3 | none | stored as sent, VEH_CN included |
| China, under the Australia code | 3 | none | {"message": ""}, nothing stored |
| South Africa | 16 | "NA" |
Wrong Field |
South Africa without STANDARD_CODE (c7) |
16 | none | stored, but without VEH_ZA |
| Poland | 15 | "PN-85/S-10030 - RoadBridge" |
{"message": ""}, nothing stored |
Poland, MVLD_CODE 1 to 20 (c7) |
1-20 | same | {"message": ""} each, nothing stored |
What this settles: the VEH_* object follows the record's MVLD_CODE, not
the STANDARD_CODE each table's heading names. Two user-defined bodies send
no STANDARD_CODE and were stored with their objects; Australia's heading
value is refused where its body's "ROAD TRAFFIC", the name of that table's
first group, is stored. So STANDARD_CODE picks a standard within a
country, and the chapter's footnote list of country names is not its value
set. A record whose MVLD_CODE is not the model's own code answers exactly
like a success and stores nothing - the same shape as the empty
VEH_DEFAULT case.
What it does not settle: why Poland's body stores nothing under any code,
and what STANDARD_CODE South Africa's VEH_ZA needs. Neither was chased by
varying values the manual does not give. /db/MVHL's contract gates its six
country objects on the MVLD_CODE each printed body sends, with Poland's 15
marked unconfirmed (MD-61).
2026-09-22 (after) - /ope/DIVIDEELEM: the Equal row's axes hold for every method¶
scripts/live_manual_feedback.py --case c8, Civil NX and Gen NX, each body in
its own seeded document (element 1 a 3.2 m beam, element 4 a 4 m square
plate), /db/ELEM counted before and after. Empty documents confirmed first
with each product's own key, left empty after.
| body | both products |
|---|---|
Frame Equal, printed (NUM_X: 10) |
4 -> 13 elements |
Frame Unequal, DIST_X: "2@1.0" only |
4 -> 6 |
Frame ParametricUnequal, RATIO_X: "3@0.3" only |
4 -> 7 |
Planar ParametricUnequal, RATIO_X and RATIO_Y |
4 -> 23 |
Planar ParametricUnequal, RATIO_X only |
Unknown Error, nothing divided |
Planar Unequal, printed (2@2.5, 2@3.0 on a 4 m plate) |
... second query is wrong |
The Unequal and ParametricUnequal rows mark X, Y and Z Required with no condition; the Equal row beside them says which axes each element type uses, and that rule is what the product applies. The printed Planar Unequal body failed on its distances, which overrun this plate, not on its shape. Wall and Solid were not measured and follow the Equal row. MD-62.
2026-09-27 - both products at v2.2 Build 09/24/2026, and Gen crosses a version line¶
Not a live measurement. Both About dialogs were read by the author on 2026-09-27 and nothing was called against either product beyond a connection probe. The API reports no build anywhere, so an About dialog is the only measurement of one there is.
| Product | Read 2026-09-27 | Previously recorded |
|---|---|---|
| MIDAS CIVIL NX 2026 | v2.2, Build 09/24/2026 | v2.2, Build 09/15/2026 |
| MIDAS GEN NX 2026 | v2.2, Build 09/24/2026 | v2.1, Build 09/15/2026 |
Gen moving v2.1 -> v2.2 is the part worth noticing. Every ledger record in this repository says Gen NX 2026 (v2.1); this is the first v2.2 Gen on this machine, and Civil has carried v2.2 since 2026-07-26. Civil's version does not move at all here - only its build does.
Neither product was connected. verify_connection() answered
{'keyVerified': True, 'status': 'disconnected'} for both, each with its own
key, and a following GET /db/NODE raised MidasNotFoundError: 404: client
does not exist on both. So the API connection is off inside both products;
no GET reached a model and nothing below was run. Worth recording on its own:
this is the shape a genuinely disconnected product answers with, against
CLAUDE.md's warning that verify_connection() cannot see a blocked
session - a modal dialog keeps answering "connected", this answers
"disconnected".
What the new build opens, none of it run:
/infodiff.scripts/info_baseline.py --capturethen--diffis the mode that exists for exactly this question, and GET-only. Build 09/15/2026 added/db/SECT'sUSE_HAMBLY_EQon both products, so a build changing the declared surface is not hypothetical here.- Hyper-S on Gen.
db/base.pygates the-M1family withHYPER_S_ONLYrather thanCIVIL_ONLYprecisely because Hyper-S is expected to reach Gen NX eventually, and that constant is the one place to widen. Gen arriving at v2.2 - the version Civil has carried Hyper-S under - is the first event that could change it. A GET per endpoint settles it. /db/ACTL'sACWC(MD-46). Gen's/infodeclares it and Civil's does not, and a live Gen send answered"Wrong Key"while a bare{ITER, TOL}answered"Wrong Field". A new Gen major version is a reason to re-read both, and the manual repo's 2026-09-24 sync asks the same question from the documentation side (ja-locale-only row; en-us/ko kept at 9 rows).- Re-verification. The playbook's scope command, run with
BUILD = "09/24/2026"on 2026-09-27, names the whole confirmed set: not one of them has a ledger record citing this build. That is the recurring task, it is destructive (/doc/NEW), and it has not started.
No ledger record was added. A build string is not evidence about an endpoint, and re-verifying is what would produce one.
2026-09-27 (later) - the new build measured: Hyper-S did not move, and Civil declares one new property¶
Both products connected on fresh keys, each document open and empty
(GET /db/NODE and GET /db/ELEM both {'message': ''} on both, with that
product's own key). GET only throughout - nothing was written and no
/doc/NEW was sent. This answers items 1 to 3 of the section above.
/info on Build 09/24/2026: three changed pairs out of 399¶
info_baseline.py --capture per product, merged, then --diff against the
committed 2026-09-03 baseline. 305 endpoints swept on each product, 399 pairs
with a schema - the same 399 the baseline holds, so no endpoint started or
stopped answering /info.
CHANGED /db/RPSC (civil)
+ CONTRIBUTION_FACTOR (number)
CHANGED /db/SECT (civil)
+ SECT_AFTER.USE_HAMBLY_EQ (boolean)
+ SECT_BEFORE.USE_HAMBLY_EQ (boolean)
CHANGED /db/SECT (gen)
+ SECT_AFTER.USE_HAMBLY_EQ (boolean)
+ SECT_BEFORE.USE_HAMBLY_EQ (boolean)
/db/SECT's pair is the known 2026-09-15 arrival, already recorded above.
/db/RPSC's CONTRIBUTION_FACTOR is new to this repository. The baseline
is from Build 09/02/2026 and no capture was taken on 09/15/2026, so the window
is 09/02 to 09/24 and which of the two builds introduced it cannot be
narrowed from what is recorded - saying "09/24 added it" would be a guess.
/db/RPSC's CONTRIBUTION_FACTOR, measured against the same three tests¶
The property is documented nowhere: CONTRIBUTION_FACTOR and "Contribution
Factor" both return zero hits across every chapter of the manual repo, and
nothing in contracts/, src/, the npm types or schema/ names it.
- It carries a description, an unusually specific one.
/infogives it as{"description": " Concrete Contribution Factor (Steel Composite Type2 only, applied when OPT_CRACKED is true, otherwise reset to 1)", "type": "number"}. That names its own gate and its own reset value. A placeholder like/db/DRLS'sDUMMYcarries no description at all. - Its position is the tell. Civil declares
OPT_MBAR_J, OPT_SBAR_J, OPT_CRACKED, CONTRIBUTION_FACTOR, SBAR_ITEMS, MBARS- it sits directly afterOPT_CRACKED, the flag its own description names as its condition. Gen declares the same list without it. - The products differ, and here that argues the opposite way.
USE_HAMBLY_EQreached both products in one patch, which was read above as evidence against a beta flag. This one is Civil only - but "Steel Composite Type2" is a Civil-side section concept, so a product-scoped field is what it should be rather than a half-shipped one. Neither reading is proof.
Nothing was sent to the server, so this says what the product declares, not
what it accepts - the /db/POSL CODE case is the standing reminder that the
two differ.
It also makes /db/RPSC an eleventh both-product endpoint whose two
schemas are not the same record, against the ten MD-46 lists. MD-46's point
holds unchanged: products: [civil, gen] says the route answers on both, never
that the record is the same.
schema/info-baseline.json is again deliberately left at its 2026-09-03
capture, for the reason the USE_HAMBLY_EQ section already sets out: CI runs
info_baseline.py --against-contracts --check and --divergence --check, both
of which fail when their set grows, and CONTRIBUTION_FACTOR would grow both.
Re-baselining means first deciding what contracts/endpoints/db-rpsc.yaml says
about the property - /info is a permitted source for a /db/* contract - and
that is the author's call. Until then the 2026-09-03 baseline stays the right
thing to diff against. The fresh captures were written to a scratch directory
and are not in the repository.
Hyper-S did not reach Gen NX at v2.2¶
All 21 -M1 endpoints were sent a plain GET on Gen NX 2026 (v2.2), Build
09/24/2026: 21 of 21 answered 404, none answered, none failed any other
way. So the version jump that made Gen's major version match Civil's did not
bring Civil's solver with it. HYPER_S_ONLY in db/base.py stays exactly as
it is, and it is still the right constant - this measured a negative, not a
reason to change the gate.
/db/ACTL's ACWC is unchanged by the new Gen build¶
From the same capture: Gen declares
ACWC, ANRC, ARDC, BMSTRESS, CRBAR, CSECF, ITER, TOL, TRS and Civil declares
the same list with CLATS in place of ACWC. Identical to the 2026-09-03
baseline on both products. A new Gen major version changed neither side of
MD-46, and the manual repo's 2026-09-24 question - whether the ja-locale-only
ACWC row means the en-us/ko tables are missing a row - is not settled by a
schema read either way. Sending the field is a write and was not attempted.
2026-09-27 (later still) - the GET breadth sweep on both products, and what a read sweep structurally cannot reach¶
The /info work above is not a full read check, and this section exists
because that was asked directly. /info is served for /db/* only, so of the
610 pairs that capture swept, the 160 /DESIGN pairs answering 404 were never
a check - they are the API fact that those endpoints have no /info route.
scripts/live_readonly_sweep.py is the tool that issues a plain GET, and it
was run on both products on Build 09/24/2026, GET only, against the same open
and empty documents.
| Product | GET-capable resources swept | Result | Skipped, and why |
|---|---|---|---|
| Gen NX (v2.2) | 268 | 268 ok, 0 failures | 36 not on this product, 1 declares no GET |
| Civil NX (v2.2) | 283 | 283 ok, 0 failures | 21 not on this product, 1 declares no GET |
Both counts are one higher than the 2026-09-03 sweep's 267 and 282. That is
the inventory growing, not the server: DESIGN/STEEL/DSTL joined both SDKs
in 2.8.2, after that sweep. No endpoint changed its answer.
Hyper-S, measured with its control in the same session¶
The 21 -M1 endpoints were sent a plain GET on both products:
| Product | Result |
|---|---|
| Gen NX 2026 (v2.2), Build 09/24/2026 | 21 of 21 answered 404 |
| Civil NX 2026 (v2.2), Build 09/24/2026 | 21 of 21 answered ok |
The Civil half is the control, and it is what makes the Gen half mean
something: 404 there is the route not being served on Gen, not a broken sweep
or a bad endpoint string. HYPER_S_ONLY is unchanged and still correct.
What no read sweep reaches, and it is not an omission to close¶
Of the 397 endpoints in the inventory, 305 are DbResource-shaped and 92 are
not. The 92 are command-shaped, so there is no GET to issue:
| Family | Count | Why a read sweep cannot reach it |
|---|---|---|
/DESIGN/* |
41 | the *-ANAL / *-TABLE / *-REPORT trios; *-ANAL runs a design check and has hung Gen NX before |
/ope/* |
19 | operations that mutate the model (/ope/DIVIDEELEM, /ope/AUTOMESH) |
/post/* |
13 | POST-shaped reads; non-destructive, but they need an analysed model to answer with anything |
/doc/* |
11 | /doc/NEW discards unsaved work, /doc/SAVEAS writes on the NX host |
/view/* |
7 | change the view; /view/CAPTURE writes a file on the NX host |
/TEMP/... |
1 | OCHECK, which crashes the session - never call it |
Only the 13 /post/* could be probed safely as they stand, and on an empty
document they would answer "perform analysis" rather than anything about their
request shape. The other 79 are reached by the write harness or not at all,
which is the 183-confirmed-case re-verification that has not started on this
build. So: every resource-shaped endpoint that declares a GET has been read
on Build 09/24/2026 on every product that serves it, and no command-shaped
endpoint has been touched. The one resource-shaped exception is
/DESIGN/SRC/AIK-SRC2K/DSRC, which declares only PUT and DELETE, so there is
no read of it to take.
2026-09-27 (last) - a dummy model on both products: the design-force gap closed, and /view/CAPTURE writes nothing¶
The author asked for whatever of the 92 command-shaped endpoints a dummy model
could reach, and authorised C:/temp for the calls that write on the NX host.
Both products were on empty documents; both now hold the model described here.
The products are on a different PC (author-confirmed at the end of the
session). Every path below therefore resolves on that machine, and nothing in
this checkout's own C:/temp is evidence about any of them. That is not a
detail: a claim built on listing the local directory was written during this
session and is retracted below.
The model, and the mistake that cost a session first¶
schema/live-cases.json's own baseModel (9 steps, nothing hand-written) plus
supports. It is 10 nodes, 3 BEAM elements in a chain and 1 PLATE, one dead-load
case with self weight.
The first attempt blocked Civil NX and needed a human to clear it. The base
model fixes node 1 only, so the plate floats; the supports were widened with
PUT /db/CONS sending five ITEMS under record key "1", the PUT answered
200 and echoed all five, and /doc/ANAL was sent on the strength of that
echo. The analysis raised a dialog on the Civil machine, and from then on
verify_connection() kept answering connected through the relay while every
GET timed out - the exact shape CLAUDE.md describes.
GET /db/CONS had been printed in the same output and showed one record.
Reading it would have stopped the analysis. The lesson is not new, it is the
repository's own rule applied to the wrong half of the output: an echo is the
request coming back, not the record being stored.
The cause is in db/boundary.py:31: /db/CONS is keyed by node id, and
ITEMS[].ID is a serial number within that node's list. Five items under key
"1" is five constraints on node 1, and the server keeps one. Re-sent as
{"1": {...}, "5": {...}, ...} across nodes 1, 5, 6, 7, 8, 21 and 22, all
seven stored, GET confirmed it, and only then was the model analysed. The
fixture's own /db/CONS case uses a single node, so this multi-record shape had
never been exercised.
/doc/ANAL completes on Gen without answering¶
| Product | /doc/ANAL |
Results afterwards |
|---|---|---|
| Civil NX | {'message': 'MIDAS CIVIL NX command complete'} in 1.78 s |
full |
| Gen NX | no response; read timeout at 60 s | full, and identical |
On Gen the HTTP call never returned, yet the analysis had run: the first result
table took 10.09 s and then every table answered normally, with exactly the
row counts Civil produced - reactions 14, displacements 20, beam forces 30,
plate stresses 10. The session stayed alive throughout (GET /db/NODE answered
10 nodes straight after the timeout). This is the *-ANAL advice in
CLAUDE.md holding for /doc/ANAL itself on Build 09/24/2026: use a short
timeout and read the tables back regardless of whether the call returned.
Treating the timeout as a failed solve would have been wrong.
Pre-process and result tables against a populated, analysed model¶
Civil, 10 pre-process tables: material 1 row, section 1, supports 7 (the
seven constraints, read back), element weight 4, load summary 2, mass summary 1;
nodal body force {"message": ""}; the three story tables answer
there was an error creating utbl because the model has no stories. Result
tables carried real numbers on both products. Every table arrived under the
top-level key "empty" - the confirmation, live again, that "empty" is the
default key for a blank TABLE_NAME and can carry a full table.
The design-force family, on a populated and analysed model for the first time¶
The 2026-09-16 re-test recorded its own gap in as many words: "a populated,
analysed and designed model has still never been re-tested against them." All
ten were run on both products, each followed by a real GET /db/NODE:
| Gen NX | Civil NX | |
|---|---|---|
| 8 Design Forces tables | all {"message": ""} |
all there was an error creating utbl |
/post/PM |
Please Check RC Design Code |
Please Check RC Design Code |
/post/STEELCODECHECK |
{"message": ""} |
{"message": ""} |
| crashes | none | none |
| alive after every call | yes | yes |
Each product answered exactly as it did on a blank document. No crash path
reopened, and /post/PM's answer is a domain error naming a missing design
code rather than a shape refusal, so the request shape is one the server takes.
What is still untested is a designed model; this closes the populated and
analysed half.
/view/CAPTURE: what was measured, and a claim retracted¶
/view/SELECT, /view/ANGLE and /view/ACTIVE all answered cleanly on both
products. /view/CAPTURE was probed four ways on Civil:
| Argument | Answer |
|---|---|
EXPORT_PATH only |
command complete |
+ WIDTH/HEIGHT/SET_HIDDEN/PERSPECTIVE/ZOOM_LEVEL |
command complete |
same, .bmp instead of .png |
command complete |
+ FIGURE_NAME (Smart Report) |
MidasResultError: It's not found Figure Name |
The one real result is the last row: Smart Report mode validates its input and names what is missing, and the SDK raises it properly rather than passing a 200 through as success.
Retracted: "and writes no file" - and then settled by measurement. This
section first reported the three command complete rows as a second instance
of the /doc/SAVEAS defect, a success-shaped message for a write that never
happened, on the evidence that no file appeared in C:/temp. That was this
machine's C:/temp while the products were on another PC, so the listing was
never evidence about anything.
The author then moved both products onto this machine, which makes a local
listing mean something, and the same probes were re-run against empty
documents with /doc/SAVEAS as the control:
| Call | Answer | File on disk |
|---|---|---|
/doc/SAVEAS (control) |
command complete |
61,440 bytes |
/view/CAPTURE, EXPORT_PATH only |
command complete |
4,385 bytes |
/view/CAPTURE, + WIDTH/HEIGHT/SET_HIDDEN/PERSPECTIVE/ZOOM_LEVEL |
command complete |
4,217 bytes |
/view/CAPTURE, .bmp |
command complete |
1,440,054 bytes |
/view/CAPTURE, + FIGURE_NAME |
It's not found Figure Name |
none, correctly |
/view/CAPTURE is not defective, and neither was /doc/SAVEAS here. Every
command complete was truthful; the files were being written on PC B all
along. EXPORT_PATH alone is enough - no FIGURE_NAME is required unless
Smart Report mode is wanted - and the only failure is the one that reports
itself. Nothing is filed, and nothing should have been.
The premise that caused it was an inference: the local C:/temp holds
checkpoints earlier sessions wrote, so NX must run here. It was never
measured, CLAUDE.md's first rule about paths says the opposite is the normal
case, and the question "which machine is the product on?" was never asked
even while a file-writing endpoint was being called. One question would have
cost nothing. A file the caller cannot see is verified with /doc/OPEN,
never with a local path check, and where the product is decides which of
those two a directory listing even is.
The .env in this checkout made the same distinction in its own header - Gen
NX runs on two separate PCs (A and B) with independent MAPI keys/sessions -
and that file was overwritten during this session on the assumption that a new
pair of keys refreshed the same session rather than naming a different
machine. It is now split per machine so the next reader cannot miss it.
Files this session left on PC B's C:/temp: five image probes
(nxprobe_a/c/d, midas_nx_probe_civil/gen) and three dummy-model
checkpoints, all of which did get written.
State left behind¶
The dummy models and their results are on PC B, which the author
disconnected at the end of the session, so no /doc/NEW was ever sent and
none is needed from here - those documents are not reachable through the API
any more, and they are 10-node scratch models. The products now answering are
on PC A with empty documents. The three /doc/SAVEAS checkpoints on PC B did
write, by the same argument as the table above.
2026-09-27 (closing) - both undocumented properties contracted, and the baseline moved¶
The two sections above left schema/info-baseline.json at its 2026-09-03
capture on purpose, because /db/SECT's USE_HAMBLY_EQ and /db/RPSC's
CONTRIBUTION_FACTOR were declared by /info and recorded by no contract, and
--against-contracts holds that gap as a ceiling. At the author's direction
both are now contracted from /info (provenance: info_schema,
requirement: unstated, each with its /info description verbatim and the
evidence in provenanceNote), and the baseline is the Build 09/24/2026 capture
taken earlier today on PC B, whose build strings are the ones the author read
from the About dialogs. A PC A capture the same day was byte-identical across
all 399 pairs.
What changed the call on USE_HAMBLY_EQ, held since 2026-09-16: the reason for
holding was to wait for the next manual sync, and that sync (MIDAS-API
685be56, 2026-09-24) came without it, while a second build kept it on both
products. Only SECT_BEFORE's copy is recorded - the contract does not model
SECT_AFTER - and --against-contracts stays within its /db/SECT ceiling
without being raised. --divergence's ceiling did move, 10 -> 11, because
/db/RPSC is now a record the two products declare differently; the field is
tagged products: [civil], so tagging stays complete.
The npm surface gains two optional members and nothing else. Neither property has been sent to a product.
2026-09-27 (re-verification) - every confirmed case on Build 09/24/2026: nothing regressed¶
Live, destructive, run with the author's go-ahead, on the machine holding
this checkout (both products v2.2, Build 09/24/2026, author-confirmed from the
About dialogs on both machines). Both documents were confirmed open and empty
with each product's own key before the first /doc/NEW. Every harness
invocation checkpointed to C:/temp - local here, so each checkpoint was
checked on disk - sent /doc/NEW, built the base model, ran its cases and
restored an empty document; a real GET /db/NODE followed every invocation,
and both products answered after all of them.
The confirmed cases were planned into 46 selections by tier, at most eight endpoints each, and each selection went through npm then Python, Gen then Civil - 101 npm and 79 Python invocations, about 60 minutes of harness time.
| Result | |
|---|---|
| confirmed endpoint-product pairs | 302 of 302 passed through both SDKs |
| confirmed endpoints | 172 of 172 (130 on both products, 35 Civil only, 7 Gen only) |
| regressions (exit 1) | 0 |
| harness exits | 176 clean, 4 exit 3 |
The four exit-3 invocations are two selections on Civil, one per harness, and they are the three cases the playbook already lists as never having passed on Civil. Both SDKs got the same server text as on Build 09/15/2026:
| Case (Civil, unconfirmed) | Answer, both SDKs |
|---|---|
/db/LCOM-SEISMIC |
The Load Combination Type is not supported. |
/db/HHCT |
POST accepted; wrote 1, read back 0 |
/db/NLCT |
LINE_SEARCH_OPTION is required when OPT_ENABLE_LINE_SEARCH is true. |
The build moved nothing that the fixture measures, in either direction.
One stop along the way, a harness refusal rather than a product event. The
first pass halted at extras1 on Gen: the npm harness refused /db/STYP with
a no-DELETE case must run last and be followed by a document reset and exited
2 before sending it, after /db/PJCF had passed. The selection planner had
applied the playbook's trap bullet as written, which named only /db/GRUP and
/db/BNGR; the harness's own rule is wider - any case whose endpoint, or
anything its setup writes, has no DELETE - and eleven confirmed cases fall
under it. The planner was widened to that rule, the aborted invocation set
aside, and the run resumed from that selection; the playbook bullet now states
the rule the harness applies. Both products were alive throughout, and the
next invocation's checkpoint-then-/doc/NEW cleared the model the refusal had
left behind.
Recorded as ledger-write-2026-09-27-1 (both products), -2 (Civil) and -3
(Gen), and as a session section in docs/npm_live_evidence_scratch.md. The
playbook's scope command with BUILD = "09/24/2026" now prints 0. No fixture
change: nothing newly confirmed, and a failing unconfirmed case is not flipped.
2026-09-27 (after the re-verification) - the unconfirmed cases on Build 09/24/2026: nothing newly resolved¶
The re-verification above detects regressions: it replays what already worked.
A fix would show up in the other set, so the author asked for it too. Every
unconfirmed case in the fixture was re-run on Build 09/24/2026, through both
harnesses, on each product the case names - 34 cases over 32 endpoints (the
three Civil cases the re-verification had already exercised were not repeated).
Same machine, same procedure: checkpoint to C:/temp, /doc/NEW, base model,
cases, empty document restored, a real GET after every invocation. Both products
answered throughout, and no case is quarantined for crashing.
Nothing that failed on Build 09/15/2026 passes on 09/24/2026. npm and Python agreed on every case, and every answer matched the reason the playbook already records:
| Endpoint | Product | Answer on 09/24/2026, both SDKs |
|---|---|---|
/db/EPST, /db/EPSE |
Gen | Wrong Field |
/db/WVLD |
Civil | Wrong Field |
/db/TDMF, /db/RPSC |
both | Wrong Field |
/db/EPMT |
Civil | Wrong Field (Gen passes, as before) |
/db/POGD |
Gen | Wrong Field (Civil passes, as before) |
/db/HPCE |
both | Wrong Key |
/db/FBLA, /db/MVLDeu, /db/PHGE, /db/NLLP |
both | Unknown Error |
/db/NLNK, /db/NLNK-M1, /db/CGLP |
both / Civil | blocked: their nllp_seed answers Unknown Error |
/db/MADO, /db/SBDO, /db/DOEL |
both | POST accepted, id 90 missing after setup POST |
/db/SINF |
both | POST accepted, id 1 missing after POST |
/db/MVLDpl |
Civil | POST accepted, id 1 missing after POST |
/db/ACTL |
Gen / Civil | Wrong Field / PUT accepted, TOL not kept (expected 0.0005) |
/db/FIMP |
both | contains errors.(Item:Epsilon_cu > 0.8 / Z + Epsilon_co) (MD-54) |
/db/TDNA |
both | (Item:IS_DB_TDNA_NOTENSIONCALC : Not Registered String) |
/db/TDPL |
both | blocked by the TDNA seed |
/db/LLANch, /db/SLANch, /db/LLANid, /db/IMPF |
Gen | blocked: /db/MVCD answers Unavailable moving load code |
/db/LLANop, /db/SLANop |
Gen | contains errors.(Item:Wheel Spacing) under BS |
/db/DSTL |
Gen | Errors detected in Steel Design Control Data.(Item:) (Civil passes, as before) |
/db/STCT |
Gen | wrote 30, read back None - iITER dropped |
Three passes appeared in the run, and none of them is new. /db/EPMT on Gen and
/db/POGD on Civil are the confirmed halves of their endpoints, run because the
selection covered both products. /db/DSTL on Civil passed on 2026-09-01 as
well; the case stays unconfirmed because confirmed covers both products it
names and Gen still refuses.
Two rows gained detail, and neither is a change. /db/LLANop and
/db/SLANop on Gen were recorded as "refused under BS" with no item; the
product names Wheel Spacing, which was simply never written down. And
/db/STCT on Civil now has a mechanism. It was BLOCKED on 2026-09-21 with the
same harness message - id 1 already exists before this case ran; a seed in this
selection owns it - and that session could only say the precondition was "a
model with construction stages". Built up one call at a time on an empty Civil
document: the base model's nine steps leave /db/STCT empty, and so do the
case's BNGR, GRUP, CCFC and ETFC seed steps; the first
POST /db/STAG creates /db/STCT id 1 with the product's defaults
(bLAST_FINAL: true, CPFC: "INTERNAL", iNLA_TYPE: 1, ...). On Gen the
case's own POST of id 1 is accepted after the same setup, so Gen does not do
this. The Civil half therefore still has never been measured, and the reason is
the case's shape, not the product: a Civil case has to PUT the record the stage
created rather than POST one. That is a fixture change and is not made here.
I first reported this as a change in Build 09/24/2026. It is not: the 2026-09-21 block on Build 09/15/2026 is the same event, read then without knowing which call caused it.
No ledger record is added - nothing was newly achieved - and no fixture flag moved. The Civil document used to pin the STCT mechanism was reset through the npm harness afterwards; both products are on empty documents.
2026-09-27 (manual repo request) - four documentation findings re-measured on Build 09/24/2026: all unchanged¶
MIDAS-API/docs/error_reports/live_verification_requests_20260927.md asked
whether four findings from the 2026-09-18 request still hold before they are
quoted in a Jira comment. The build had moved, so they were re-run with the same
harness and payloads - scripts/live_manual_feedback.py --case b1 (Gen),
--case a1 and --case a3 (both products) - on empty documents, a real GET
after each invocation, both documents reset through the npm harness afterwards.
| Request item | 2026-09-18 item | Endpoint | Result on 09/24/2026 |
|---|---|---|---|
| A-8 | B-1 | /db/SSEIS |
IINHERENT_TORSION and NHERENT_TORSION answer 201, vanish from the response, and GET keeps INHERENT_TORSION = false; the correct key stores true |
| A-7 | A-1 | /ope/MEMB |
SELETION_TYPE behaves exactly like SELECTION_TYPE on both products (AELEM = [2,3]) - an alias |
| B-2 (2D) | A-3 (b) | /db/TDNA |
PROFY[1].RADIUS = false answers 201 with Wrong Field, GET Not Found Key, both products |
| B-2 (3D) | A-3 (c) | /db/TDNA |
PROF[1].RADIUS = [0, 20] answers the same, both products |
The numeric baselines round-tripped as numbers ([0, 20, 0] in PROFY, PROFZ
and PROF) on both products, so the refusals are about the type. Every row is
the 2026-09-18 result. The reply is
MIDAS-API/docs/error_reports/live_verification_feedback_20260927.md, left
uncommitted there beside the request, which is uncommitted too.
Outside what was asked: /ope/MEMB's POST response says bREVERSE: false and
the GET after it says true, identically for both keys. The 2026-09-18 reply
recorded only AELEM, so whether that was already so cannot be told from the
record.
2026-09-27 (manual repo request, rebar) - REBB/REBC/REBW: which key generation the product takes¶
MIDAS-API/docs/error_reports/live_verification_requests_20260927_reb.md
asked which of two key generations in MIDASIT's own articles the product
actually speaks. The ko pages (edited 2025) carry the short keys (ID,
vMAIN_BAR, D0, VER_BAR, bUSE_MODEL_THICK ...); the en-us JSON Schemas
(edited 2026-06-25) carry long ones (CREATE_SUB_SECTION, MAIN_BAR, DO,
VERTICAL_REBAR, USE_MODEL_THICKNESS ...). REBC's and REBW's en-us examples
follow the en-us schema; REBB's does not - it is the ko shape. The three
articles (49513985245849, 49513980544793, 49514033006745) were fetched
fresh from the Help Center API in both locales, and every payload below is the
article's example copied byte for byte, with only the record key moved onto the
scratch model.
Gen NX 2026 v2.2, Build 09/24/2026. Each variant ran on its own /doc/NEW
scratch document built for it: UNIT m/kN, a C24 material, an SB 0.6x0.6
section 1 used by two columns, an SB 0.7x0.4 section 2 used by a beam, a
two-storey wall id 1 (two WALL elements, THIK 0.2), stories 1F/2F/Roof and
DCON KCI-USD12. All three tables read {"message": ""} before each write.
Checkpoints are under C:/temp/reb-*.mgbx on the NX host.
Reads¶
| Civil NX | Gen NX /info item keys |
|
|---|---|---|
/db/REBB |
GET and /info both 404 |
ID, BAR_SECTOR_I/M/J, MAIN_BAR_DC_TOP/BOT, bSAME_SIZE_TOP_BOT/IMJ/LAYER |
/db/REBC |
GET and /info both 404 |
ID, vMAIN_BAR, SHEAR_BAR_END/CEN, HOOP_TYPE, HOOK_TYPE, bSAME_SPACE_END_CEN, NUM_BAR_BC_JOINT |
/db/REBW |
GET and /info both 404 |
ID, bUSE_MODEL_THICK, THICK, DW, DE, VER_BAR, HOR_BAR, END_BAR, NUM_END_BAR, BE_HOR_BAR, BE_LENGTH, vSTORY_NAME |
Not one long-generation key is in the server's schema. Civil has none of the
three routes, as GEN_ONLY already records.
Writes¶
| Endpoint | Variant | HTTP | Body | GET after |
|---|---|---|---|---|
| REBB | (a) ko example | 201 | Unknown Error |
empty |
| REBB | (b) en-us example (ko shape) | 201 | Unknown Error |
empty |
| REBB | (c) en-us schema, required fields + CREATE_SUB_SECTION: false |
201 | Wrong Field |
empty |
| REBB | (c) same with CREATE_SUB_SECTION: true, ELEMS.KEYS: [3] |
201 | Wrong Field |
empty |
| REBB | control: {"ITEMS": [{}]} |
201 | Wrong Field |
empty |
| REBC | (a) ko example | 201 | Unknown Error |
empty |
| REBC | (b) en-us example | 201 | Wrong Field |
empty |
| REBW | (a) ko example | 201 | Unknown Error |
empty |
| REBW | (b) en-us example | 201 | Wrong Field |
empty |
Nothing was stored, so no GET could show key names from a write. The split in the error is the result: every short-generation body gets past field validation, and every long-generation body is refused at it. Three follow-ups in one document pin that down:
- Short keys are parsed and checked against the model. The ko REBB body
keyed to a section that does not exist (3) answers
[Error] Beam Rebars has been entered in the section no. 3, which has not been specified.- a domain error that could only come after the body was read. IDis required. The ko body withIDremoved answersWrong Fieldon all three; withID: 1instead of0it answersUnknown Erroras before. That is also why the empty-item control answersWrong Field.Unknown Errorsurvives everything tried: PUT instead of POST (200, same body), another existing section key,vSTORY_NAME: ["1F"]on REBW,HOOK_TYPEon REBC, a completed/doc/ANAL(supports, a dead load, self weight), and switchingDCONtoKDS 41 20 : 2022(accepted). Where it comes from is still unknown.
Where the long generation comes from¶
It is the ch26 endpoints' schema. contracts/endpoints/design-rc-kds-41-20-2022-reb{b,c,w}.yaml
record CREATE_SUB_SECTION/ELEMS/MAIN_BAR/USE_CORNER/DO/HOOK_TYPE for
/DESIGN/RC/KDS-41-20-2022/REBC and the whole long REBW set -
VERTICAL_REBAR, CONCRETE_FACE_TO_CENTER_OF_REBAR, STORY {FROM, TO} ... -
for its REBW, and on 2026-07-29 one production model answered for the same 102
walls with the short keys on /db/REBW and the long ones on the ch26 route
(entry of that date above). The en-us ch24 articles carry the ch26 schema. For
REBB the match is partial: ch26's REBB has CREATE_SUB_SECTION/ELEMS but keeps
the vMAIN_BAR_TOP arrays, while the en-us ch24 schema's LAYER1/LAYER2,
DT/DB match neither route. Posting the en-us examples to the ch26 routes
themselves was tried too and answered Wrong Field there (so did the ko
bodies), so that route has its own unmet precondition and this proves nothing
about ch26.
What this changes here¶
db-rebb-write-path-refuses-every-payload rested on the empty item: "an empty
object cannot contain a wrong field". It can - it lacks ID. The finding that
no write to /db/REBB has ever been seen to succeed stands, and now covers REBC
and REBW on a scratch model as well; the reasoning that the body was ruled out
does not. The risk, the contract's rule and the TypedDict docstring are
corrected to say so. The 2026-08-27 and 2026-09-03 verification records are
left as written - records are not edited.
No ledger record: nothing was newly achieved. The document was reset with
/doc/NEW after the last checkpoint.
Correction to the entry above: the reply to the four-finding request was
committed in the manual repo (60e7ca3), not left uncommitted.
2026-09-28 - the /db endpoints with no live case: RCHK and DRLS written, five others pinned to a cause¶
Sixteen write-capable /db endpoints had no case in scripts/live_crud_check.py.
Four were set aside before starting: /db/IEHG-GL-M1, /db/IEHG-PSS-M1 and
/db/IEHG-TRUSS-M1 have no permitted source, and /db/REBB was measured the
day before. Of the rest, those with a manual Request example and light
prerequisites were probed first, each (endpoint, product) on its own /doc/NEW
document with the harness base model, POST -> GET -> PUT -> GET -> per-id DELETE
-> GET. Both products v2.2, Build 09/24/2026; checkpoints C:/temp/nocase*.
| Endpoint | Product | Result |
|---|---|---|
/db/DRLS |
Gen | full round trip on the manual example (empty records on nodes 1, 2, 5); per-id DELETE removed node 1 alone |
/db/RCHK |
Civil | full round trip once section 2 existed - the key is a section number |
/db/REBR |
Gen | manual example (long keys) Wrong Field; the same record in /info's short keys with ID Unknown Error - the REBB/REBC/REBW pattern |
/db/CSCS |
both | contains errors.(Item:Section Type) on an SB or VALUE section; the manual's PSC and COMPOSITE section examples are themselves refused (Section Dimensions ... incorrectly entered), so no composite target could be built |
/db/MVLDbs |
both | blocked at the lanes: under BS, /db/LLAN and /db/LLANop both refuse the manual lanes on wheel spacing, the 2026-09-27 finding; lanes created under EUROCODE are deleted when the code is switched to BS. The case body answers Wrong Field without lanes |
/db/RCHK. The manual example's second record is a BEAM keyed 2; against
the base model (one section) the POST answers [Error] Rebar for
Beam/Column/Brace Checking has been entered in the section no. 2, which has not
been specified. and stores neither record. With an SB section 2 added, both
records were created, read, updated and deleted. The new extras13 case keeps
the first record (COLUMN, section 1) byte for byte and changes only
SUB_BAR.SUBBAR_NAME to "#5", a value the same example uses, so the PUT is
checked by a value found nowhere else in the record. It passed through both
live_crud_check.py and live-crud.mjs on Civil and is confirmed=True.
/db/DRLS stays without a harness case for the reason its tier docstring
gives: an empty record has no value that tells a create from an update. The
write is recorded from the probe.
Ledger: ledger-write-2026-09-28-1 (RCHK, Civil) and -2 (DRLS, Gen). Both
contracts were re-promoted to cite the new write sessions
(db-rchk-crud-2026-09-28, db-drls-crud-2026-09-28), which keeps
check_verification_lag.py at its ceiling of 40.
Not attempted yet, each for a stated reason: /db/IMFM, /db/FIBR and
/db/IEHG form a chain on /db/FIMP records whose own case is still
unconfirmed; /db/TDCS needs /db/TDNA (unconfirmed) and /db/CSCS (above);
/db/EPMT-M1, /db/IEHG-BEAM-M1 and /db/IMFM-M1 have no manual example, so
/info is their only source.
2026-09-28 (later) - the fiber chain: FIMP's example was the manual repo's, and IMFM and FIBR follow¶
/db/FIMP had one case, unconfirmed since 2026-09-14 because the vendored
chapter's Kent & Park body is refused with Epsilon_cu > 0.8 / Z + Epsilon_co
(MD-54), and /db/IMFM, /db/FIBR and /db/IEHG all name FIMP records. The
MIDASIT article itself (35944335180569, en-us, edited 2024-08-05) was fetched
through the Help Center API: it carries 19 Request examples, 13 concrete and 6
steel models.
Every one of the 19 is accepted by POST on both products (Build 09/24/2026).
The article's Kent & Park example is not the chapter's: EC1_METHOD: 0,
EC1: 0.0025, STRENGTH_AFTER: 1 and no Z, where the chapter prints
EC1_METHOD: 1, EC1: 0.0035, Z: 100, STRENGTH_AFTER: 0. MD-54 blamed the
article's example; it is the manual repo's transcription, and the register,
docs/vendor_report_triage.md (where it was held as a B-item candidate until
the article was read) and the playbook's failure table are corrected. The
examples are kept verbatim in scripts/fixtures/fimp_article_examples.json.
/db/FIMP ignores a POST's key. {"3": ...} into an empty table answers
with the record under "3", and GET /db/FIMP then lists it as "1"; a second
POST under "17" is stored as "2". The same renumbering /db/STLD does, and
the echo hides it. The case is therefore keyed 1, and the seed sends ids 1-4 so
the npm harness cleans up the ids it sent.
/db/IMFM is keyed by material id. The manual example (material 1 concrete,
material 2 steel) round-tripped on both products with its FIMP names moved onto
article records; the case keeps material 1 and updates REBAR_NAME.
/db/FIBR round-tripped on both products with the manual example's
SECT_KEY moved to section 1 and its three FIMP names onto article records;
FIBR_BASE and everything else as printed. The case updates FIMP_NAME[0].
All three passed through both harnesses on both products and are
confirmed=True; ledger ledger-write-2026-09-28-3 (Gen) and -4 (Civil);
contracts re-promoted to fiber-chain-crud-2026-09-28.
/db/IEHG stops here. Its example assigns an inelastic hinge property
(PROP_NAME) and no documented endpoint defines one - the manual has the
assignment and the control (/db/IEHC), not the property. A POST naming a
property that does not exist answers Not Found Key on both products. It stays
at read level until a property can be created other than in the GUI.
The three Hyper-S -M1 endpoints with no manual example¶
/info is their only source, so each was tried with the nearest confirmed
record written in the names /info declares, on Civil:
| Endpoint | Sent | Result |
|---|---|---|
/db/IMFM-M1 |
the /db/IMFM record above, concrete references nested under CONCRETE as /info has them |
full round trip through both harnesses; confirmed=True, ledger ledger-write-2026-09-28-5 |
/db/EPMT-M1 |
/db/EPMT's Gen-confirmed Von Mises record - /info declares the identical VMISES keys on both |
Wrong Field, POST and PUT; the same Civil-only refusal /db/EPMT shows (MD-56) |
/db/IEHG-BEAM-M1 |
INEL_PROP_NAME naming a property that does not exist |
Inelastic Hinge Property not found: Fiber_Auto - the product states the blocker /db/IEHG has |
2026-09-28 (design) - the ch25-27 design-parameter tables: 35 confirmed, 43 written¶
/DESIGN/* held 124 inventory rows and 2 writes. Of them, 76 are DB-style
parameter tables (the rest are the ANAL/REPORT/TABLE function calls, the three
design-code selectors, the three LCTB tables with no example, and /TEMP/.../OCHECK,
which is never called). A pilot on Gen wrote every table's first manual Request
example with the matching design code selected: 44 were stored and read back.
Those became the new design_tables tier - 43 of them; /DESIGN/RC/.../DCREM
is held back because its GET keys the record by node id rather than the id it
was written under - with every create a manual example record as printed
(scripts/fixtures/design_manual_examples.json) and every update one key moved
to a value the manual gives: another record of the same example, a
Specifications enum value, or a stated default. Element-keyed tables take the
base model's beam element 2 (column element 1 for PMDM).
Result, Build 09/24/2026: 35 endpoints confirmed through both harnesses, 66
endpoint-product pairs (Gen 35, Civil 31). live-crud.mjs had to learn to look
under resources.design; it only searched resources.db.
What the tier found about the product:
- No design code is needed first for the element-keyed tables and most
singletons; a fresh document takes them on both products. (Not RC
LMRRandSRDFor steelSRDF, which need their chapter'sDCOwritten first - see 2026-09-29 below.) - Per-id DELETE works on
/DESIGNtables and removes one record. - On the singletons, DELETE means different things.
DCO(all three codes) is removed.DCTL(all three) and steelSRDFgo back to the Specifications defaults (DT: "3D",bAUTOKF: false;PHI_T1 0.9...).LLRFandMATDgo back to the model's values. RCSRDFdoes not change at all. RCLMRRcomes back withRHORandRHOWexchanged - writtenRHOW 0.04, RHOR 0.03, readRHOR 0.04, RHOW 0.03after the DELETE. (Retracted 2026-09-29: the DELETE writes fixed values; the example's numbers only made it look like an exchange. See below.) These eight took a PUT and read it back, so they are written, but this checker's delete step expects the record gone and they stay unconfirmed. - The three
LENGtables are one table. A record the RC case left behind made the steel and SRC cases refuse to start ("id 2 already exists"). The manual's firstLENGrecord also setsbNOTUSE: true, which the product stores withLB0; the case probesbNOTUSEinstead. - Civil refuses the RC and steel design-code selections:
/DESIGN/RC/DRCwithKDS 41 20 : 2022answersWrong Field,/DESIGN/STEEL/DSTLa Steel Design Control Data error; SRC'sDSRCis accepted. So on Civil the tables that need design control data - RCLMRRandSRDF, steelDCOandSRDF, RCDCO- are refused, and their Civil cases stay unconfirmed. On Gen, RCLMRR/SRDFtook their PUT only once RCDCOhad set a design code earlier in the same run. /DESIGN/RC/.../MATDand bothULCTtables are Gen-only in the SDK'sPRODUCTS, and Civil answered404forMATD.
Ledger ledger-write-2026-09-28-6 (Gen) and -7 (Civil); the 43 contracts
cite the new session design-tables-2026-09-28.
Still open in /DESIGN: the 13 tables the pilot refused for a visible reason
(beam-only element types hit by the pilot's key mapping, SRC section records,
a haunched beam), the 16 it refused for no visible reason (the four REB*
tables, DCRE, the four DCRM, MEMB in all three codes, steel and SRC LLRF,
BEMW, CRCM, SMODI, SRC MATD), DCREM, and the function calls.
2026-09-29 - the design singletons whose DELETE resets: 12 confirmed¶
The eight singletons left unconfirmed on 2026-09-28 were measured again on Build 09/24/2026, each with values chosen to be distinguishable from anything a reset could write, before a case was allowed to name an expected value. All of them are PUT-only (no POST); the harness writes with the PUT.
| Table | What a per-id DELETE leaves | Products |
|---|---|---|
DCTL (RC, steel, SRC) |
bAUTOKF: false, DT: "3D"; FRAMEX/FRAMEY as written |
Gen, Civil |
RC LLRF |
APPLIED_COMP: ["AXIAL"] (a fresh document has no LLRF record at all) |
Gen, Civil |
RC MATD |
the model's own material (the base model's C24, no rebar) | Gen |
RC LMRR |
always RHOR 0.04, RHOC 0.03, RHOW 0.03 - written 0.05/0.06/0.07, read those three |
Gen |
steel SRDF |
PHI_C, PHI_B, PHI_V to 0.9; PHI_T1 0.9, PHI_T2 0.75 read the same either way |
Gen |
RC SRDF |
nothing: the DELETE answers HTTP 200 {"message": "error status"} and the record stays as written |
Gen |
Four things this corrects or adds:
- The three
DCTLendpoints are one record, like the threeLENG: a PUT through RC's reads back through steel's and SRC's. - RC
LMRR's "exchange" on 2026-09-28 was an inference, and wrong. The DELETE writes the same three numbers whatever was stored; it only looked like an exchange because the manual example isRHOW 0.04, RHOR 0.03. WhetherRHOR 0.04is a product default or a misplaced one cannot be told from the API. - RC
LMRRandSRDFrefuse a PUT until RCDCOhas been written ("Errors detected in Concrete Design Control Data"), and steelSRDFuntil steelDCOhas ("... Steel Design Control Data"), on both products. The design code survives theDCOrecord's own DELETE - a steelDCOPUT-then-DELETE was enough for steelSRDFto take its PUT - so the tier's order (each chapter'sDCOcase runs before these) is what satisfies it. The npm harness gets the same order from the endpoint list. On Civil theDCOitself is refused, so these stay unconfirmed there. - RC
SRDF's refused DELETE does not raise.{"message": "error status"}carries noerrorkey, soMidasResultErrorstays silent anddelete()returns as if it had worked. Another member of the "a 200 does not mean success" family; nothing in the SDK detects it today.
The harness side: Case(expect_after_delete=...) in
scripts/live_crud_check.py, emitted as expected.afterDelete and read by
live-crud.mjs; without it a DELETE must still remove the record. A probe of
"*" compares the whole record, used where the reset touches keys other than
the one the update moves (DCTL, LMRR, steel SRDF). MATD now probes
CONCRETE.GRADE, because the reset removes the rebar grade key altogether.
Result: the whole design_tables tier through both harnesses, Gen 43/43 and
Civil 35/39 (the four design-control-data refusals). confirmed=True for the
8 on Gen and DCTL x3 and RC LLRF on Civil; ledger
ledger-write-2026-09-29-1 (Gen) and -2 (Civil), session
design-singletons-2026-09-29.
2026-09-29 (design, continued) - sixteen more tables, and what is still refused¶
Of the 29 tables the 2026-09-28 pilot refused, sixteen became cases today.
The pilot's own mapping caused most refusals: it spread each example's
records over base-model elements 1-4, and element 4 is the plate, element 1
the column. [Error] The element no. 4 is an element type in which ... cannot
be entered and ... can only be assigned to BEAM type elements were about
that, not about the tables.
| Table | What made it pass | Products |
|---|---|---|
RC CMFT, EQCT, MBTP, SUEQ, MCMB, MRFT, TRFT |
one example record on beam element 2 | Gen, Civil (TRFT Gen only; Civil answers 404) |
RC SCOL |
one example record on column element 1 | Gen, Civil |
MEMB (RC, steel, SRC) |
the example's AELEM (elements 885-891, which this model lacks) pointed at beams 2 and 3 |
Gen, Civil |
steel and SRC LLRF |
the example's LIVE_LOAD_CASES: ["LL2"] and REDUCTION_DATA on story B2 emptied - neither exists here |
Gen, Civil |
steel SMODI |
keyed by a steel material: Not Found Key on the base model's concrete material 1, accepted on a steel one at id 2 (new design_steel_material seed) |
Gen, Civil |
steel CRCM |
keyed by an element on a circular steel section: a user pipe (SHAPE: "P", D 0.3, t 0.01) on the steel material, as a column off to the side (section 902, element 901; new design_pipe_column seed). The pilot's refusal was Item:Material Type |
Gen, Civil |
RC BEMW |
the example's STOR_NAME: "B2" names a story; with the manual's /db/STOR record POSTed as 1F/2F (new design_stories seed) it takes 1F. With BBOT_STOR: false the product drops STOR_NAME from the record |
Gen (/db/STOR is Gen-only in the SDK, so Civil gets no story) |
Things the product does that these cases now pin:
MRFTstoresFACTORdifferently per product. The example's second record is0.01. Gen stores it as0.7- and 0.05, 0.1 and 0.2 as well - while 0.5 and 0.69 are stored as sent; Civil stores0.01. The manual states the range as>0, <=1. The case expects each product's value.- The three
LLRFendpoints are one record, likeDCTLandLENG. A fresh document has no LLRF record; DELETE leaves one readingAPPLIED_COMP: ["AXIAL"]. A PUT of["AXIAL", "SHEAR", "MOMENTS", "ALL"]is stored as["ALL"]. MEMB's per-id DELETE removes the member;SMODI's removes the modification.
Still refused, each with what was tried:
HCBM(RC and steel):Unknown Erroron three consecutive beams (seeded 91-93) with the example's other fields, with and withoutL1/L2, withPOS_TYPE1, withPART_Bas aTOrange, after RCDCO, and with parts A and C on a tapered section (whose own POST was refused -Section input data contain errors- so that last try proves nothing). A haunched beam most likely needs real tapered members; no confirmed tapered-section payload exists yet.- SRC
MCRD,MRBD: keyed by an SRC section, and the manual's/db/SECTSRC example (SHAPE: "RBO") answersUnknown Erroras printed, withDATATYPE: 1added, and with the concrete dimensions enlarged. Without an SRC section they answer... section no. N, which has not been specified. - SRC
MATD: a PUT keyed by material 1 or 2 answers{"message": ""}and stores nothing; the GET stays empty. DCRE(Wrong Field) andDCRM-BEAM/-COLUMN(Unknown Error), before and after RCDCO;DCRM-BEAMwithSPLICED_BARS: 1instead of"50%"answersWrong Field.- Not retried today: the four
REB*tables,DCRM-BRACE/-WALL(the wall ones answerWrong Key, which reads as wanting a wall id),DCREM.
Result: Gen 59/59 and Civil 49/54 through both harnesses (Civil's BEMW
blocked by its Gen-only story seed, then dropped); ledger
ledger-write-2026-09-29-3 (Gen) and -4 (Civil), session
design-tables-2-2026-09-29.
2026-09-29 (design functions) - one RC column design on a solved model¶
First attempt at the design function calls with real results behind them
(until now every *-ANAL/*-TABLE/*-REPORT had only been called on empty
documents, where each answers Please perform analysis). Model: the
disposable column live-analysis.mjs builds (C24, 0.6 x 0.6 user section,
fixed base, DL self weight), the harness's confirmed /db/LCOM-CONC record,
RC DCO as the design_tables case writes it, MBTP COLUMN on element 1;
/doc/ANAL; then each call with a short timeout and a /db/NODE liveness
check after it.
Gen NX (Build 09/24/2026): the whole chain ran.
| Call | Answer |
|---|---|
CD-ANAL (PERFORM_TYPE: "ELEMS", element 1) |
{"message": "success"}, well inside 30 s; session alive |
CD-TABLE (TABLE_TYPE: "MEMB") |
a Result Table with HEAD/DATA and one row for the column (MEMB, SECT, fck, Pu, phiPn, Rat-P ... CHK) |
CD-REPORT (MEMB, Summary, EXPORT_PATH: "C:/temp", OUTPUT_NAME: "cd-report-gen") |
{"SUCCESS": true, "FILE_PATH": "C:/tempcd-report-gen"} |
CD-REPORTjoinsEXPORT_PATHandOUTPUT_NAMEwith no separator.C:/temp+cd-report-gencame back asC:/tempcd-report-gen- a file namedtempcd-report-gen...inC:\, not inC:\temp. Every manual example endsEXPORT_PATHwith a separator ("C:\\MIDAS\\Result\\"), and withC:/temp/the later reports came back asC:/temp/<name>- so this is the documented form working as documented, not a defect; the trap is only for a caller who leaves the separator off. The NX host is another machine, so the file itself was not inspected; the answer is the product's own.- The historical
CC-ANALhang did not appear forCD-ANALon this build and model. One run is one data point.
Civil NX: CD-ANAL killed the product. Civil refuses RC DCO (as on
2026-09-28), so the same model had no RC design code; /doc/ANAL completed,
then CD-ANAL did not answer within 30 s and every /db/NODE afterwards
timed out for more than two minutes while /mapikey/verify still answered
connected. The author found Civil NX dead and restarted it. Do not call
CD-ANAL on Civil with analysis results and no RC design code - risk
design-rc-cd-anal-without-design-code-kills-civil in
contracts/safety/known-product-risks.yaml. An SDK warning for it is
proposed, not made.
Ledger ledger-write-2026-09-29-5 (Gen CD-ANAL), ledger-read-2026-09-29-6
(CD-TABLE), -7 (CD-REPORT, read because the file was not inspected),
-8 (Civil CD-ANAL, crash_or_hang); session design-cd-2026-09-29.
The other 39 design function calls are untouched.
2026-09-29 (design functions, continued) - RC member design and the steel code check on Gen¶
Both products restarted after the Civil CD-ANAL crash; each answered with an
empty open document. Civil was left alone: it refuses the RC and steel
design-code selections, which is the condition CD-ANAL died under. On Gen,
one disposable solved model - RC column 1, beam 2, brace 3, a steel column 11
on the ltsr_material/ltsr_section records, fixed bases, DL self weight, RC
and steel DCO, the fixture's LCOM-CONC and LCOM-STEEL, member types -
then each call with a short timeout and a liveness check. Nothing hung.
| Call | Answer |
|---|---|
BD-ANAL (beam 2), BRD-ANAL (brace 3), steel CODE-ANAL (column 11) |
{"message": "success"} each |
BD-TABLE, BRD-TABLE, CODE-TABLE (MEMB) |
a Result Table with the element's row |
BD-REPORT, BRD-REPORT, CODE-REPORT (Graphic, EXPORT_PATH: "C:/temp/") |
SUCCESS: true, FILE_PATH: "C:/temp/<name>.jpg" (not inspected - another machine) |
RC TABLE BEAMDESIGNFORCES, steel TABLE STEELMEMBERDESIGNFORCES (manual example arguments) |
{} after /doc/ANAL alone; one row, under the key empty, once BD-ANAL / CODE-ANAL had run |
RC TABLE COLUMNDESIGNFORCES, BRACEDESIGNFORCES |
{} - only asked before a design run |
BC-ANAL, BRC-ANAL, CC-ANAL (CC last, for its hang history) |
{"error": {"message": "failed:Rebar"}} at once; session alive; their TABLEs headers only, REPORTs No design results found |
- The design-force tables are fed by the design run, not by the analysis.
An empty
{}right after/doc/ANALmeans "run the member design first". - The RC code checks need rebar data, and no REB* write has been made to
work (see
db-rebb-write-path-refuses-every-payload), so they stop atfailed:Rebar- cleanly.CC-ANAL's historical hang was not reached. - Still untried:
WD/WC(no wall element),HCD(no haunched beam), SRCBC/CC(no SRC section can be made), and the Civil side.
Ledger ledger-write-2026-09-29-9 (the three ANALs), ledger-read-2026-09-29-10
(TABLEs), -11 (REPORTs), -12 (the refused checks); session
design-functions-2026-09-29.
2026-10-04 (manual sync) - MIDASIT's REB* revision, /db/MATD's new rows, and what the product says¶
The manual repo's 2026-10-04 sync (69c3b5b) touched four chapters. Ch09
(SPLC ALONG) and ch25 (DSTL maxProperties gone from the official schema)
are text the contracts already agree with. Two needed the products.
Ch24 REBB/REBC/REBW were rewritten to MIDASIT's 2026-09-28 revision of
all three articles, which moved them to the short-key generation the
server's /info already declares - the same field set the SDK's contracts
carry. The one name still different is REBW's story list: the revision
writes vSTORY_KEY (integers), /info vSTORY_NAME (strings). Gen NX,
Build 09/24/2026, scratch model: beam section 2, column section 1, wall 1
of two WALL elements, stories 1F/2F/Roof, DCON KCI-USD12.
| Body | Answer |
|---|---|
| REBB revised example, key 2 | 201 Unknown Error, nothing stored |
| REBC revised example, key 1 | 201 Unknown Error, nothing stored |
| REBW revised example, key 1 (no story key) | 201 Unknown Error |
REBW + vSTORY_KEY: [1] / + vSTORY_NAME: ["1F"] |
Unknown Error both |
REBB with ID: 1; REBB as PUT |
Unknown Error both |
Then one idea from the REBB risk entry, that the product needs a row it
created itself: on a solved RC frame, BD-ANAL ran (success) but neither
/db/REBB nor /db/REBC held a row afterwards, and the revised examples
as PUT still answered Unknown Error; the RC checks stayed at
failed:Rebar. In that frame - column 1 framing into beam 2 -
CD-ANAL answered failed:BeamData, where the lone column on 2026-09-29
answered success.
So the revision changes the documentation and not the product. The REBC class docstring's "full CRUD confirmed 2026-08-27" was measured on a model this file does not describe and has not been reproduced on a scratch model since; the docstring now says so.
Ch04 /db/MATD gained official rows for bSERVCHECK (Modulus of
Elasticity Ratio Input Option, default true), dSHORTTERM and
dLONGTERM (short- and long-term ratios), all Optional. Contract updated
from the table; npm's JSDoc changes with it. Measured on Gen:
| Step | bSERVCHECK / dSHORTTERM / dLONGTERM read back |
|---|---|
| fresh document, base model's C24 | false / 0 / 0 |
| PUT of the confirmed case's record, the three omitted | false / 0 / 0 |
PUT false, 1.25, 1.5 |
false / 1.25 / 1.5 |
| PUT omitting them again | false / 1.25 / 1.5 - kept |
PUT true, 1.25, 1.5 |
true / 1.25 / 1.5 |
The documented default true is not what the product holds or applies:
omitting the key keeps the stored value. Recorded under the contract's
manualDefects.
Civil NX, once its MAPI connection was back (it had answered
404 client does not exist after the restart; the key was unchanged): the
same steps, and none of the three keys appears in any GET - not on the
fresh document, not after a PUT with false or true and 1.25/1.5 - while
every PUT echoes them back. Unchanged from Build 09/15/2026: Civil accepts
the keys and keeps nothing a caller can read.
Ledger ledger-write-2026-10-04-1 (MATD, Gen), ledger-read-2026-10-04-2
(the refused REB* writes) and ledger-write-2026-10-04-3 (MATD, Civil).
2026-10-06 - /doc/NEW killed Gen NX on an empty document¶
Gen NX 2026 v2.2, Build 09/24/2026, at the start of a vendor-report re-verification. The sequence, all on one connection:
| Call | Answer |
|---|---|
GET /db/NODE, /db/ELEM, /db/STLD |
{"message":""} each - empty document |
POST /doc/SAVEAS C:/temp/rv1006-pre-gen.mgbx |
completed; the file is on disk (NX host = this machine) |
GET /DESIGN/RC/KDS-41-20-2022/DCTL |
200 {"message": ""} |
GET /info/DESIGN/RC/KDS-41-20-2022/DCTL |
404 (A-8, unchanged) |
GET /info/db/NODE |
200, the schema |
POST /doc/NEW |
no answer in 60 s |
Afterwards /mapikey/verify answered connected while GET /db/NODE timed
out, and the author found Gen NX dead and restarted it. No dialog text was
read.
This is the sequence every destructive harness opens with - checkpoint, then
/doc/NEW - and it has run hundreds of times since 2026-07-26 without
incident, including on this build on 2026-09-27 (180 invocations) and
2026-10-04. The 2026-07-26 crash (above) was on a 710-node analyzed model and
pointed at document teardown; this document was empty, so size is not the
whole story. The only calls here that the harness does not make before its
/doc/NEW are the three GETs, and a GET of a /DESIGN table and two /info
reads are not a plausible trigger on the record so far. One occurrence;
cause unknown. Ledger ledger-read-2026-10-06-1.
2026-10-06 (later) - the vendor report re-measured on Build 09/24/2026, minus the crash forms¶
After the restart, the items the report still dated to Build 09/15/2026, on
both products: each document confirmed empty with its own key, checkpointed to
C:/temp, /doc/NEW, _seed_model, the fixture's own seeds where a case
needs them (mvcd + vehicle for MVHL, tdmt_seed, hecb_seed +
stage11_seed for STCT), every answer printed, empty documents at the end.
Left out by the author's scope: the crash forms (A-5's kill window, Civil
CD-ANAL), and Gen's half of A-7, which blocks the session when it
reproduces.
| Item | Gen | Civil |
|---|---|---|
| A-2 | per-id DELETE /db/NODE/6: NODE 10->9, ELEM 4->3; body-form STLD 2->0; body-form NODE 9->0 with ELEM 3->0 |
identical |
A-3 /db/CONS |
8 chars echoed, 7 stored; 6 chars refused | identical |
A-3 /db/SECF |
key 4 (no such section) echoed whole, GET {"message": ""} |
identical |
A-3 /db/MVHL |
NOT-A-VEHICLE stored verbatim |
identical |
A-3 /db/SPLC |
POST ALONG 2.5 stored; PUT 3.5 echoed; GET 2.5 |
(Gen-only block) |
A-3 /db/STCT |
POST echoed iITER 50 / TOL 0.02; GET has neither |
first measured: PUT of the STAG-created record, same - and again with iINC_NLA: 1 |
| A-4 | refusals under 201; /db/STCT PUT refusal under 200 |
refusals under 201 |
A-6 /db/TDMT |
NOT-A-CODE -> Wrong Field; Russian -> input data contain errors |
identical |
| A-7 | not run | SAVEAS to C:/Program Files/ -> command complete; no file on disk; OPEN -> path is wrong; the C:/temp copy reopens with 10 nodes |
| A-8 | /DESIGN/...DCTL 200, its /info 404 |
same, and the IEHG trio's /info 404 |
| A-9 | /db/STBK accepts LCNAME, neither response nor GET carries it |
same; /db/POSL CODE: "" -> Wrong Field, without it created; Civil /info still declares 8 properties incl. CODE |
Everything the report claims reproduced. What is new:
/db/STCT's Civil half is measured, and matches Gen. On Civil the firstPOST /db/STAGcreates STCT id 1 (as recorded 2026-09-27), so the probe PUT that record.iITER/TOLcame back in the response and were absent from the GET, whilebLAST_FINAL,FINAL_STAGE,CPFC,bCONV,bTRUSS,bBEAM,bCAMBER,bCHANGE_CABLE,iNLA_TYPEwere stored. WithiINC_NLA: 1the record gainsiLSTEP,bENEG,bDISP,bFORC,DV/FV/EV,bIEMFand loses the creep/time-step keys - and still has noiITER/TOL. Both products'/infodeclare both. The report's v1.4 guess (AccumulativeiNLA_TYPEignoring Linear-only fields) is withdrawn: this payload sendsiNLA_TYPE: 0.- Gen's STCT record is shorter than Civil's. For the same fixture payload
Gen reads back ten keys; the five booleans above are absent there too. On
2026-09-18, with the manual's payload (
iNLA_TYPE: 1), Gen kept them. Gen refusesiINC_NLA: 1withoutiLSTEP(Item:Number of Load Steps), which Civil fills with 1. Not isolated; kept out of the report. /db/POSLon Civil storesFA1.4 /FV1.5 for a POST of 1.0 / 1.4, echoing 1.0 / 1.4. Plausibly the code's site coefficients forS2atSRF0.22, derived by design; held in the triage as an observation./db/TDMTwithCODE: "European"and nothing butNAMEis accepted and stored as{"NAME", "CODE": "EUROPEAN"}- so "input data contain errors" depends on the code, as the 2026-07-26 table already implies.
Ledger ledger-write-2026-10-06-2 (Gen) and -3 (Civil).
2026-10-11 - both products at v2.2 Build 10/10/2026: one new route on Civil, /db/POSP¶
Both About dialogs were read by the author on 2026-10-11 (screenshots):
MIDAS CIVIL NX 2026 v2.2 and MIDAS GEN NX 2026 v2.2, Build 10/10/2026,
on the author's home PC. The MAPI keys are the same ones .env holds - a key
belongs to the account and product, not to a machine - so every call below
reached whichever session was connected, which the author says was this one.
/info diff, GET only. scripts/info_baseline.py --capture per product,
each with its own key (MIDAS_MAPI_KEY set per run: run without it, the
script sends no key and every pair answers 401 MAPI-Key is missing, which
the capture records as 610 404s - a first attempt here did exactly that), then
--diff against the 2026-09-27 baseline (Build 09/24/2026). 400 pairs answered,
against the baseline's 399:
| Change | Detail |
|---|---|
NEW /db/POSP (civil) |
Civil now answers GET /info/db/POSP and GET /db/POSP ({"message":""}); both were 404 on Build 09/24/2026 |
Nothing else moved on either product: every other schema is identical to the
baseline. /db/EPST still 404s on Civil; /db/EPSE answers there, as before.
Civil's /db/POSP is not Gen's. Same nine shared names (NAME, DESC,
GROUND_LEVEL, BEDROCK_LEVEL, FOOTING_LEVEL, ITEMS[].HEIGHT,
DENSITY, VS, KH, DISP), and then:
| Only on Civil | Only on Gen |
|---|---|
STR_HEIGHT (Structure Height), STR_WIDTH (Structure Width), ITEMS[].POISSON (Poisson Ratio) |
OPT_USE_N (Use N), ITEMS[].ANGLE_OR_N (Angle Or N) |
Gen's schema is unchanged from the baseline.
What this opens, none of it done yet:
/db/POSPisGEN_ONLYin both SDKs and its contract saysproducts: [gen]. Widening it needs the Civil-only fields tagged per product (MD-46) and, before anything claims a request shape, a Civil write - the fixture's Gen payload carriesOPT_USE_N, which Civil does not declare.- Re-baselining
schema/info-baseline.jsonwaits for (1):--against-contractsis a ceiling, and three Civil properties no contract records would fail it. - Re-verification of the confirmed cases on Build 10/10/2026 (destructive).
Checkpoints go to a directory on the NX host; this is a different machine
from the 2026-09-27 run, so
C:/temphas to be confirmed there first.
No ledger record: a build string and a schema diff are not evidence about an endpoint's request shape.
2026-10-11 (later) - /db/POSP on Civil: its own record, both SDKs¶
The NX host is this checkout's machine (DESKTOP-7483A6T): a /doc/SAVEAS of
the empty Civil document to C:/temp appeared on this disk before anything
destructive ran. Then, on a /doc/NEW document:
| Request | Answer |
|---|---|
POST Gen's confirmed fixture record (OPT_USE_N, ITEMS[].ANGLE_OR_N) |
201 Wrong Field, nothing stored |
POST Civil's /info shape: Gen's record without those two, plus STR_HEIGHT: 10, STR_WIDTH: 10, ITEMS[].POISSON: 0.3 |
201, stored as sent |
| POST the shared fields only (neither product's extras) | 201 Wrong Field |
PUT DENSITY 17 -> 20, STR_HEIGHT 10 -> 12, layer 2 POISSON 0.3 -> 0.35 |
200, read back as sent |
DELETE /db/POSP/2 |
200, table empty after |
So Civil's /db/POSP takes Civil's /info record and refuses Gen's, and at
least one of its three extras is required (which, not isolated). The values
for the three extras are the probe's: no document gives any.
SDK: both SDKs' SoilProperty/soilProperty now answer on Civil; the
contract tags OPT_USE_N/ANGLE_OR_N [gen] and the three new fields
[civil] (provenance: info_schema, MD-46). A Civil case was added to
live_crud_check.py and passed through both harnesses (PASS /db/POSP,
create/read/update/delete all ok); it is confirmed. The tier's
posp_seed and posl_seed (Gen records, for Gen-only cases) answer
Wrong Field on Civil during that run, as posl_seed always did; no Civil
case uses them.
Writing the types exposed a generator defect older than this: a field the
contract narrows to one product was still typed required when the manual
required it, so a Civil caller had to send Gen's ANGLE_OR_N, which Civil
refuses. 26 required fields across eight contracts (/db/ELEM, /db/EPSE,
/db/IEHC, /db/POLC, /db/POSL, /db/POSP, /db/SBDO, /db/SPLC) were
in that state. The generator now types them optional and says
"Gen NX only; required there." - the rule it already applied to appliesWhen.
Ledger ledger-write-2026-10-11-1; session posp-civil-2026-10-11.
2026-10-11 (re-verification) - every confirmed case on Build 10/10/2026: nothing regressed¶
Live, destructive, on the author's go-ahead ("1~3까지 진행해줘"), on this checkout's machine, which is the NX host (checked by a save that appeared on this disk). Both documents confirmed empty with each product's own key first.
Plan, scripted this time rather than by hand: per product, one case per
endpoint exactly as live-crud.mjs picks it (the first case for that
product), grouped by that case's tier, at most eight endpoints per npm
invocation, and any case the npm harness can only clean up by a document reset
placed last in its own invocation - 51 npm invocations on Gen, 66 on Civil.
Python ran each tier holding a confirmed case for the product, whole - 30 on
Gen, 39 on Civil. Order npm then Python, Gen then Civil; a real GET /db/NODE
after every invocation. About 75 minutes; both products answered throughout.
| Result | |
|---|---|
| confirmed endpoint-product pairs | 419 of 419 passed through both SDKs (236 endpoints: 183 on both, 37 Civil only, 16 Gen only) |
| Python | 0 regressions; every failure is an unconfirmed case (Gen 14 + 3 blocked, Civil 18 + 5 blocked) |
| npm | 417 on the first pass; RC and steel SRDF on Gen failed, then passed |
The two npm failures were the plan's. RC SRDF and steel SRDF answered
Errors detected in Concrete/Steel Design Control Data because their DCO
case sat in another invocation - the dependency recorded on 2026-09-28 (RC
LMRR/SRDF and steel SRDF take a PUT only after DCO), which no needs
expresses. Re-run as DCO,SRDF for each code, all four passed. Python's
design_tables tier, which runs DCO first, passed them in the main run. The
playbook's selection traps now name it.
The unconfirmed failures match the playbook's reasons word for word
(Wrong Field for EPST/EPSE/TDMF/RPSC/WVLD/ACTL(Gen)/EPMT(Civil), Wrong Key
for HPCE, Unknown Error for FBLA/NLLP/PHGE, Wheel Spacing for the Gen
lane-optimization pair, Not Registered String for TDNA, STCT's dropped
iITER on Gen and its STAG-owned id on Civil, HHCT's wrote 1, read back 0,
LCOM-SEISMIC's unsupported type, NLCT's LINE_SEARCH_OPTION, SINF's missing
id, the design-control refusals of RC LMRR/SRDF and steel DCO/SRDF on Civil).
Nothing that failed before passes now.
Ledger ledger-write-2026-10-11-{2,3,4} (both / Civil / Gen); npm rows in
docs/npm_live_evidence_scratch.md. Both products left on empty documents.
2026-10-20 - four Gen rules from smart-midas-steel, and PUT as create¶
smart-midas-steel (a browser app on npm midas-nx 2.10.1) records Gen rules
in its own CLAUDE.md that this repository had nowhere. Each was re-measured
here before going in, on the author's go-ahead ("여기서할 것만 라이브로 검증하고
진행해"), on Gen NX on this checkout's machine (the NX host), document
confirmed empty with Gen's own key first, checkpoint to C:/temp, /doc/NEW,
the shared base model from live_crud_check.py, empty document restored at the
end. The build was not re-read from the About dialog; the last one the author
confirmed is 10/10/2026. Payloads are the confirmed cases' own.
| Claim (theirs) | Measured | Verdict |
|---|---|---|
| Load-combination names are at most 20 characters | /db/LCOM-GEN NAME of 20 characters stored; 21 and 30 answered 201 {"error": {"message": "[Error] The permitted number of characters to be entered for Load Combination Name(...) is 20."}} and stored nothing; a PUT renaming id 1 to 25 characters answered the same under 200 and left the name alone |
holds, and it is a refusal with an error body, so MidasResultError raises in both SDKs. The manual states no length |
| Two CNLD items for the same load case on one node leave only one | POST of node 3 with FZ -10 and -5, both LC_SCRATCH: echoed both, but GET returns one item with FZ -15. PUT to node 2 did the same. Control, two different cases on node 4: both stored |
corrected: the server sums them into one item, it does not drop one. Silent - no error, and the POST echo shows both. The app sums before sending, which matches the server |
| A TRUSS element takes no beam load | /db/BMLD on TRUSS element 5: {"error": {"message": "[Error] The element no. 5 is an element type in which Beam Loads cannot be entered."}} under 201 (POST) and 200 (PUT); the same item on BEAM element 2 stored |
holds, as an explicit refusal |
/view/CAPTURE with ZOOM_LEVEL: 100 leaves the window fitted afterwards |
the Gen window, captured by itself (PrintWindow) after each call on a model with one node 60 m out: after the PUTs it sat zoomed near the origin with the beam cut off, and /view/ANGLE 30/15 left it pixel-identical. After /view/CAPTURE with ZOOM_LEVEL 190 the window showed the whole frame, and after 100, 30 and an omitted ZOOM_LEVEL it was byte-identical to that. The PNGs did follow ZOOM_LEVEL - 190 zoomed in, 30 out - and the omitted one was byte-identical to 100, the documented default |
holds, but broader: any capture leaves the window fitted, whatever ZOOM_LEVEL it was given; the value applies to the image only |
PUT creates records that do not exist (Gen). smart-midas-steel builds its
whole model with PUT straight after /doc/NEW. Replayed with the base model's
payloads: PUT to an empty /db/UNIT, MATL, SECT, NODE, ELEM, CONS,
STLD, BODF, BMLD, CNLD and LCOM-GEN stored every id sent, read back
whole-table. A PUT of a new id into a populated table worked too: NODE 31
read back under 31. /db/STLD renumbers under PUT exactly as under POST
(see the 2026-07 entry): PUT of id 7 beside ids 1-2 echoed "7", was stored as
id 3, and GET /db/STLD/7 answered Not Found Key. So a PUT echo is no
more proof of the stored key than a POST echo is.
Ledger ledger-write-2026-10-20-1. Gen left on an empty document.
2026-10-20 (later) - Steel-Frame's Gen cautions, re-measured: STEELCODECHECK can hold the session¶
Steel-Frame (E:\AI Study\Steel-Frame, a multi-storey steel frame app on npm
midas-nx 2.10.1) keeps a list of Gen cautions in docs/gen-api-cautions.md.
Re-measured on the author's go-ahead ("위에 내용을 라이브 검증 진행 먼저 해줘"),
Gen NX on this checkout's machine (the NX host), document empty first,
checkpoint to C:/temp, empty document restored after each of three runs. The
model is that app's own 4-storey braced frame (scripts/gate/live-gate.ts,
125 nodes, 324 elements, five storeys of STOR, floor loads, mass from self
weight and loads, Lanczos 12 modes, two RS cases), ported as sent, except that
SPFC got an explicit aFUNC instead of CALC_OPT: true (2026-09-22 entry).
Build not re-read; last author-confirmed 10/10/2026. A dialog was watched for
by listing Gen's own top-level windows after each risky call.
| Their caution | Measured | Verdict |
|---|---|---|
/post/STEELCODECHECK without design results opens a dialog and stops the API |
Analysed model with /db/DSTL GB50017-17 set before the analysis and no /db/LCOM-STEEL: the call did not answer in 20 s; Gen showed a #32770 dialog titled midas Gen NX, text Error Checking Result : No Load Combination exists for Checking., one button; a GET /db/NODE then timed out too. PostMessage(WM_CLOSE) to that dialog closed it, and the next GET /db/NODE answered in 0.3 s. Controls: the same analysed model without DSTL answered {"message": ""} with no dialog (what this repo had recorded before), and DSTL set after the analysis answered MIDAS GEN NX Please perform analysis. - because that PUT discarded the results (next row) |
holds. The empty answer recorded since 2026-07-31 is the no-code case only; with a steel code and no steel combinations the call holds the session until someone closes the dialog |
| A DB write after analysis invalidates the results | REACTIONG answered, then a PUT of /db/MATL 1 with identical values made it [RE1] Cannot generate table data as there is no analysis result.; re-save and /doc/ANAL brought it back unchanged (DL sum 8588.905 kN both times) |
holds, even for a write that changes nothing |
EIGENVALUEMODE fails intermittently with Unknown Error |
Deterministic, not intermittent: without COMPONENTS it answers Unknown Error every time (5 of 5 bare, and with STYLES, NODE_ELEMS or MODES alone); with COMPONENTS it answers every time - 1500 rows (125 nodes x 12 modes), 12 with NODE_ELEMS [101], 2 with the manual's full example. A wrong component list (Mode, Frequency, Period) answered {"message": ""}. PARTICIPATIONVECTORMODE answers without COMPONENTS |
corrected: send COMPONENTS. The sub-tables come back keyed with spaces - EIGENVALUE ANALYSIS, MODAL PARTICIPATION MASSES PRINTOUT (1), (2), MODAL PARTICIPATION FACTOR PRINTOUT (kN,m), MODAL DIRECTION FACTOR PRINTOUT - where the manual and contracts/tables/post-vibration-mode-shape.yaml write them without (MD-63) |
RS STORY_DRIFT drops the top storey |
STORY_DRIFT_X returned 3 rows (3F, 2F, 1F) of 4 storeys under RX(RS) and under DL(ST); STORY_DISPLACEMENT_X returned all 5 levels |
holds, but not RS-specific: the top storey's row is missing for a static case too |
GB50017-17(S) DB steel is refused |
Q355 and Q235 under GB50017-17(S) answered Unknown Error; GB03(S) Q345 stored. Their reading - the English-edition installation does not list the standard - was not tested here |
holds as a measurement; the cause stays theirs |
Per-id DELETE /db/MATL/9 removed only material 9, as DbResource.delete()
assumes; Steel-Frame's own incident (a body-form DELETE that emptied every
material, and another that took all 324 elements) is the documented
whole-table behaviour, reached through raw request().
Ledger ledger-write-2026-10-20-2 and ledger-read-2026-10-20-3.