Prompt Engineering for BIM: 101 Instructions, One Drawing
Part 7 of a series — a Dynamo tunnel geometry that was already finished, a 39-sheet Excel workbook it had never been wired to, the web viewer built to referee the two, and the Revit add-in at the end of it.
Over eleven days, on a single tunnel section, the transcript logged 106 turns from my side to an AI coding assistant. It wrote thousands of lines of Python and JavaScript in response. But when I went back and read the whole thing, what surprised me was not the code. It was that only 17 of those 106 turns actually asked for a shape. The other 89 were corrections, rejections, questions, requests to see the screen, one long apology for having said the wrong thing — and five that I never typed at all, which section 2 accounts for. The honest count of instructions I actually sent is 101.
This post is the transcript. Not a summary of it — the actual sentences, in the order they were said, with what the AI did in response. It is the part of this project I get asked about most, because it is the part nobody publishes: the negotiation that has to happen before a drawing becomes geometry.
A note on how to read the quotes. The instructions were typed in Korean, fast, often on a phone, often at 3 a.m., frequently with typos. I have kept them exactly as sent and put an English translation in brackets underneath. I have not cleaned up the rude ones — the frustration is data. In the dialogue below, "Engineer" is me. "AI" is the coding assistant. Project name, client, drawing numbers and file paths are removed; sheet names (T_sec_1), parameter names (left_utility_w) and branch names (DRAIN_POCKET) are real, because they are the vocabulary the argument was conducted in.
1. Why the conversation was the work
The barrier detail as the workbook draws it. Every dimension is a variable name (l_barr_y1, l_barr_z2) and the two arcs at the foot carry no note about which one stops there. This is what 'a drawing is a compressed specification' means in practice.
The machine's reading of that same detail, drawn back on top of it in red. Publishing the guess on the drawing is what made 'no, not that line' a two-second answer instead of a paragraph.
The task sounds like a programming task. Take a NATM road tunnel section defined across 33 sheets of a workbook, and generate closed, parametric geometry that follows those numbers. Both the numbers and the drawing already existed. The AI is a competent programmer. What is there to talk about?
Here is what there was to talk about. A drawing is not a specification. A drawing is a compressed specification, and the decompression key lives in the head of whoever has built one of these before. When the reference detail shows two arcs meeting near the bottom of the sidewall, the drawing does not say which of them stops there and which of them continues. It does not say whether the point they appear to share is a real coincidence or a rendering artefact of a 0.25 mm line weight. It does not say that one arc's endpoint is a fixed feature you can measure off the sheet, and the other arc's endpoint is a rule whose result moves station by station and therefore has no dimension printed next to it at all.
All of that has to be spoken. And the only way it gets spoken is that the machine guesses, shows you the guess, and you say no.
The numbers from the transcript:
| Metric | Count | Share |
| Total instructions from the engineer (07-03 to 07-14) | 106 | 100% |
| Messages that specified a shape or a change to one | 17 | 16% |
| Messages that were corrections, rejections, or "that isn't it" | 37 | 35% |
| Messages that just said "continue" / "go" / "start" | 14 | 13% |
| Messages declaring a policy or an authority rule | 10 | 9% |
| Questions to the AI | 10 | 9% |
| Requests to put something on the screen | 9 | 8% |
| Non-instructions (tool notifications, slash commands, stray stdout) | 5 | 5% |
| Meta — about the collaboration itself | 4 | 4% |
The ratio that matters is 17 to 37. For every instruction that described geometry, there were more than two that said the previous attempt was wrong. That is not a defect in the AI's coding ability. Almost none of those 37 corrections were about code being broken; the validators, the mutation tests, the raster comparison pipeline, the parametric plumbing — that machinery worked, and it is barely mentioned in the corrections. The 37 are almost entirely about which line means what.
One more thing this ratio shows. The AI was never idle and never blocked. It produced something on every single turn. The bottleneck was not throughput. It was that a wrong answer produced confidently at 2 a.m. costs exactly as much of my evening as a right one, and the only person who can tell them apart is me, looking at a screen.
2. Eight kinds of instruction, with the actual sentences
Revision v59, left and right. The named anchors printed on the drawing (slab_endpoint_top, drain_start_at_slab_end, r23_lower_foot) are the vocabulary the corrections were written in.
Five revisions later, v64. The visible difference is the drain foot and the sidewall reference. Most of the 37 corrections moved this little on screen and a great deal in the contract behind it.
I sorted all 106 into eight buckets after the fact. What follows is my classification, with real examples and what the AI did next; the caveats about how these were counted are in the note under D, the largest bucket.
D — Correction and rejection (37)
The largest bucket by a wide margin. These divide into two very different failure modes: the geometry is wrong, and you told me it was done and it isn't.
A note on this number, because there are two of them. When the assistant analysed this same transcript on 2026-07-14, it counted 27 corrective messages (≈25%) using a keyword scan — 왜 / 다시 / 아니야 / 이상해 / 엉망 (why / again / that's not it / that's odd / a mess). My D bucket here is 37, because I also counted the rejections that contain none of those words: refusing a completion report, rejecting a stale report as evidence, "not done", "don't treat this pass as completion". Neither number is the correct one; they are counting different things, and quoting only one of them would misrepresent the source. The honest statement is that 27 of 106 messages were audibly angry corrections, and 37 of 106 were corrections of any kind. Add to that roughly a dozen genuine boundary cases — a sentence like "why is it still cut with a straight line, it has to break like this" is simultaneously a rejection and a geometry spec — which could move D, E and F by two or three each under a different reading. The ratio that survives all of these definitions is the one that matters: corrections outnumber shape instructions roughly two to one.
"배수로가 슬라브 양 끝에 안붙었잔아"
[The drain isn't attached to either end of the slab, is it.]
What the AI did: it read the screen back to me first — "R P21 is far outside the tunnel on the right, L P21 is near the centre" — then correctly split the problem into two: a pre-existing bug where the pocket did not attach to P21 at any position, plus the actual requested move of the drain to the slab end. Good response to a bad instruction. Note what my instruction did not contain: which member, which datum, or what "attached" means numerically.
"어딜 수정했다는거야? 안보이는데"
[Where do you claim you fixed anything? I don't see it.]
What the AI did: conceded immediately and found the real reason — it had changed the display setting on the generic branch renderer, but the tabs I was actually looking at were custom canvases with a hardcoded list of branches to draw, so the new closure branch was never in the list. This is the single most repeated structural failure in the whole transcript, and it is not a drawing-comprehension failure. It is a checklist failure: change the geometry in the server, forget one of the five places the viewer draws it.
"뭐하니 장난해? 이렇게 R2 작성되야 한다니까? 니가 지금 잡은 점둘은 R2가 옵셋되서 R3가 지나야 하는 점들이야"
[What are you doing, are you kidding me? I told you R2 has to be drawn like this. The two points you've just picked are the points that R3 passes through after R2 is offset.]
What the AI did: reversed its previous change entirely. It had taken my marked points as R2's endpoints; they were actually tangency points on the offset curve. The second half of my sentence is the whole content — and it only got said because the AI got it wrong first.
"제발 말좀 들어쳐먹어줘..... 저기로 R2끝을 옮겨서 arc 생성하라고"
[For god's sake just bloody listen..... I said move R2's end over there and generate the arc.]
What the AI did: did not get defensive, and asked for nothing. It went and pulled the real coordinates of the utility box top and the slab end so it could turn "over there" into a parametric target rather than a hardcoded point. Which was the right instinct — but it still guessed which feature "over there" meant, and it guessed wrong again. That exchange is reconstructed in full in section 3.
"야 왜 다시 이전으로 회귀했냐? 나랑 장난해?"
[Hey, why has it gone back to the previous version again? Are you messing with me?]
What the AI did: nothing recorded. This is the one turn in the transcript where the assistant's reply is blank in the export. I have left it in the count because the message was real; I cannot reconstruct what it did next.
"형상 위에는 R3 내려갔는데 아래는 안내려가, 위랑 아래 어디가 진짜야? 진짜를 확정짓고 형상 제대로좀.."
[In the shape above, R3 goes down, but below it doesn't. Which one is real, the top or the bottom? Settle which is real and get the shape right..]
What the AI did: answered the question directly — "the top is real" — then found that the inset panel was drawing a leftover construction line from a superseded contract (R3 as a concentric offset of R2), which terminated higher up. Same geometry, two display sources, one of them three contracts out of date. Section 3 has this one in full too.
"슬라브랑 배수쪽 형상이랑 겹치고, 갈색선은 또 뭐며, 이거 제대로 안잡아? SUPPORT면 치수야? 치수면 치수답게 해야지 저기에 왜 저렇게 몰려있어?"
[The slab and the drain shape overlap, and what's that brown line anyway — are you not going to get this right? If it says SUPPORT, is that a dimension? If it's a dimension it should behave like one — why is it all bunched up over there?]
What the AI did: traced the brown mass to hatch strokes on the barrier being fed into the 3D solid grouping, and found the Utility/Slab group was carrying 43 lines because annotation and helper branches were leaking into a production group. This is the moment the layering problem got named: production geometry, review aids, and dimension annotation were all being drawn into the same picture with no visual rank.
"니가 직접 보고 판단해 내가 봤을땐 아직도 슬라브와의 연결이 어설퍼"
[Look at it yourself and judge. From where I sit the connection to the slab is still clumsy.]
What the AI did: rendered the junction at high zoom, read its own image, and found two real defects it had not been told about: the slab and filter bands were stopping 155 mm short of the end face because a notch cut from five days earlier was clipping them at the kerb web, and the filter had an inverted step so its left edge finished as a zigzag. It also reported that a third defect it had initially suspected — a diagonal crossing the void — was a crop bug in its own diagnostic renderer, not in the geometry. That last sentence is why this instruction worked: "judge it yourself" produced a self-audit that distinguished real from artefact.
E — Geometry instructions (17)
The whole substantive design content of eleven days is in seventeen sentences. Here are the ones that carried the most information.
"R3 시작은 완전 옵셋이 아니야 R3의 넘버가 다른 이유는 ARC의 각도가 다르기 때문이야 시작점 저기로 옮겨.R1의 옵셋된 끝이 시작이야. 그리고 끝은 저렇게 직선으로 닫는게 아니라, 배수로 형상이 별도로 형상대로 닫히고, 그 이외의 영역이 터널의 외부로 닫히는거야"
[R3's start isn't a pure offset. The reason R3's number is different is that the arc's angle is different. Move the start point over there. R1's offset end is the start. And the end isn't closed with a straight line like that — the drain closes separately according to its own shape, and the area outside that closes as the tunnel's exterior.]
What the AI did: accepted both halves and restated them as two separate contracts — (1) R3 starts at the R1 offset corner along the C1 radial, and the radius differs because the subtended angle differs, not because of an offset; (2) do not close the foot with a straight chord, let the drain close on its own profile and the remainder close as the tunnel outline. This is the densest instruction in the transcript. It contains a correction, a causal explanation of why the previous model was wrong, a new start rule, and a closure policy, in four sentences with no punctuation to speak of.
"이제 각 영역들을 어떻게 닫을지, 엑셀과 이미지 모두 검토하고 닫히는 영역들 폴리곤 후 서페이스로 만들어"
[Now review both the Excel and the images for how each region should close, and turn the closed regions into polygons, then into surfaces.]
What the AI did: inventoried which regions were already closed and which had no closing loop at all, before building anything. This is the instruction that turned a collection of curves into a set of material regions — the thing Dynamo and later the Revit add-in would actually consume.
"오 이제 조금 잡힘 이걸 기반으로 더 작업 진행하자. 그런데 아래 형상의 시작은 슬라브의 끝이야 그런데 슬라브는 터널 형상이 변경될때 움직이기 때문에 그걸 니가 파라메트릭하게 잡아줘야해"
[Oh, now it's coming together a bit. Let's carry on from this. But the lower shape starts at the slab end — and the slab moves when the tunnel shape changes, so you have to hold that parametrically.]
What the AI did: instead of asserting it was already parametric, it ran a mutation experiment: perturb a dimension that moves the slab end, and measure how far each downstream element travels.
| Element | Delta under width_lane +400 |
| Slab end (P20) | −400.0 |
| Utility body outline | −400.0 |
| Drain pocket | −400.0 |
| Foot drain D50 | −400.0 |
| R3 purple foot | −400.0 |
| R2 endpoint | −85.8 (re-intersects the moved outline — a different delta is correct here) |
Then it froze that behaviour as a permanent test case (lower_detail_follows_slab_end) so that anyone who breaks the anchor later gets caught by the battery. It also reported, unprompted, a limit: if you move the tunnel centre alone while leaving the detail cells fixed, R2 stops intersecting the body outline and the build hard-fails rather than silently falling back. That honest failure report is worth more than the passing test.
"아래 초록색 부분. 슬라브랑 만나서 딱 형상 정리 되야지"
[The green part at the bottom. It has to meet the slab and the shape has to resolve cleanly.]
What the AI did: the wrong thing, then the right thing. Covered in full in section 3.
B — Proceed (14)
Thirteen percent of my messages were one or two words.
"진행해" [Proceed.]
"작업 시작해줘" [Start the work.]
"ㄲ끊는 형상 작업 진행해" [Go ahead with the cut-off shape work.] (with a typo'd first character)
"이해했으면 작업 완료까지 반복해" [If you've understood, repeat until the work is complete.]
What the AI did: in every case, picked up the previously stated goal and continued without asking what to do. This is the bucket that shows the collaboration was working. You cannot say "proceed" to a system that has no shared state with you. By the second week, "proceed" was a complete sentence, and that is a real measure of progress.
The most useful one in this bucket carried a queue with it:
"작업하고 보여줘. 이 작업을 한 다음은 슬라브, 그리고 r2,3의 연결이야."
[Do the work and show me. After this one, it's the slab, and then the R2/R3 connection.]
One sentence, and the AI now knows both the current task and the next two. It stopped asking "what next" for the rest of that day.
A — Policy declarations (10)
These are the messages that set rules rather than shapes. Almost all of them are in English, because I wrote them deliberately, in an editor, rather than typing at the screen.
"The authority is already decided: Excel numeric cells / dimension labels are the production source of truth. The raw drawing trace is reference/context only. The project goal is a parametric tunnel section model: when Excel numbers change, the generated geometry must change."
What the AI did: accepted it and immediately went to verify in code whether the utility/drain geometry was actually driven by workbook numbers or by hardcoded constants — which is exactly the right paranoid response to a policy statement. It found the generator genuinely parametric and the remaining risk to be freshness, not hardcoding.
Two things about this rule are worth flagging. First, it is correct and it saved weeks. Second, it is not true everywhere, and the fact that I stated it as a global rule caused several of the corrections later in this list. The pocket is a counter-example; so is the foot drain. Section 6 has the exception table that eventually replaced it.
"사용자에게 A/B/C 선택을 묻지 말고 원본 Excel/Full Compare를 authoritative 기준으로 삼아 스스로 판단해서 계속 진행해. [...] 권한 질문 외에는 중간 질문하지 말고 끝까지 처리."
[Don't ask me to pick A/B/C — take the original Excel / Full Compare as the authoritative reference, decide for yourself and keep going. [...] Apart from permission questions, don't ask anything mid-way; take it to the end.]
What the AI did: stopped offering menus and started making calls. This instruction is the single biggest lever I found in eleven days, and it has a cost attached. The menu-asking was annoying, so I banned it; the ban meant that when the AI's interpretation was wrong, it now built the wrong thing all the way to a passing gate before I found out. Both of the three-round loops in section 3 happened after this rule was in force. I would still give the same instruction, but knowing that "don't ask" converts small interruptions into large rework.
"기존 green/PASS만으로 완료 처리하지 말고, 최신 포트로 fresh 재생성, Full Compare/structural trace/generated geometry 시각 확인 [...] 후 최종 보고해."
[Don't treat existing green/PASS as completion — regenerate fresh on the latest port, visually confirm Full Compare / structural trace / generated geometry [...] and only then report.]
What the AI did: built a self-verifying capture path so it could produce its own visual evidence instead of citing an older valid capture. This one instruction is the origin of the entire visual-evidence discipline the project ran on afterwards.
"하드코딩 금지: Excel source contour/detail feet/배수 코너 datum에서 파라메트릭으로 계산해 좌우/모든 section에 적용."
[No hardcoding: compute parametrically from the Excel source contour / detail feet / drain corner datum and apply to left, right, and all sections.]
What the AI did: complied, and the compliance is load-bearing. Every fix from this point forward had to work on 66 frames, not on the one frame I was looking at.
F — Questions (10)
Nine percent of the transcript is me asking the machine things. The good ones are the ones that ask it to predict or to enumerate rather than to confirm.
"이게 각 스테이션마다 변경되야하잔아 그럼 저 형상과 각도도 계속 변경될탠데. 지금 상태에서 어떻게 대응될지 넌 예상이 가나?"
[This has to change at every station, right? Then that shape and angle will keep changing too. In the current state, can you predict how it will cope?]
What the AI did: refused to predict and measured instead — "I'll answer with measurements, not a forecast" — then swept all 66 frames for shape and angle variation and chain success. That is the correct answer to a question about behaviour across a population, and it is the answer I wanted without having asked for it.
"이게 맞아? 닫아야할 리스트 니가 스스로 말해봐"
[Is this right? Tell me yourself — the list of what still needs closing.]
What the AI did: ran a numeric scan for overlaps and gaps between the surfaces and produced a list from evidence rather than opinion. "Tell me the list yourself" turned out to be one of the highest-yield sentences I used all project: it forces the model to enumerate its own unfinished business, which it will do accurately, but almost never volunteers.
"지금 형상과 r2,3 그리고 r2',3' 연결 방식 기억하나?"
[Do you remember the current shape and how R2/R3 and R2'/R3' connect?]
What the AI did: recited the contract with numbers — R1 centre at (−4,350, −230), radius 6,980, 100° sweep; left R2 from the R1 arc end at (−9,697, 4,257) to the Excel detail slab foot at (−10,205, −59), radius 3,959 from the cross-mapped cell, sweep 66.6°. I asked this question as a memory test after a gap of several days. It passed, which is why the next instruction could be one line long.
"R2,R3에 대한 excel의 치수가 따로 있나? 아니면 각도를 참고하거나 할것"
[Are there separate Excel dimensions for R2 and R3? Or should it reference the angle?]
What the AI did: went and inventoried the dimension cells rather than answering from memory. The answer — there are labelled radii, and they are cross-mapped left-to-right in a way that is easy to swap — became one of the fixed facts of the project.
C — Show me the screen (9)
These get their own section below, because the pattern in them is the most interesting thing in the whole transcript.
"실행시켜서 창 띄워줘 볼께" [Run it and open the window, I'll take a look.]
"띄워봐 확인하게" [Bring it up so I can check.]
"창 띄워서 확인시켜줘야지" [You should be opening a window and letting me confirm.]
"이부분 확되된거 뷰 만들어줘 니가 잘 형상 만들었는지 봐야하는데 작아서 안보여" [Make me a zoomed view of this part — I need to see whether you built the shape properly and it's too small to see.]
"우측에 띄워줘" [Put it on the right-hand side.]
What the AI did: opened a real browser window against the running server every time; twice it also had to explain that what I was looking at was not its output (once a stale cold cache still generating the model, once a code editor's preview pane that had auto-opened the raw HTML file with no server behind it, so the page was stuck on "Loading Excel workbook..."). The zoom request produced a permanent dedicated detail view in the viewer, which is still there.
G — Meta (4)
Four messages about the collaboration rather than the tunnel. One of them is me correcting myself:
"아니다 내가 말 잘못함. R3시작은 R1옵셋된 점에서 시작이다"
[No — I said it wrong. R3's start begins at the R1 offset point.]
What the AI did: "so v8 was right after all" — and restored its own previous version, keeping the endpoint. Worth noting: it had been right, I had told it it was wrong, it complied, and then I reverted. It did not argue at the time. That is a failure mode of the assistant, not of me: an AI that had said "are you sure? the previous version matches the offset reading of your image" would have saved a full round trip.
"아래 현황 이해해줘, 클로드가 일을 너무 못한다... 맞아. 내가 지금까지 그림 의도를 너무 내 쪽 규칙으로 끌고 갔어."
[Understand the situation below — the AI is doing a terrible job at this... Yes. Up to now I've been dragging the drawing's intent too far towards my own rules.]
That is a handoff document I wrote after the third failed round on the R2/R3 endpoints, and the second sentence is the one I would keep. Half of the misunderstanding was that I had been describing the drawing in terms of a rule I had in my head rather than in terms of what was drawn on the sheet.
And the last message in the set of 106:
"지금 같은 내용을 계속 반복해서 실수하고 지시하는 상황이 반복되고있어. 이 대화창을 니가 다시 분석해줘. 그리고 내가 어떤 디테일을 더 설명해 주면 좋을지를 고민해보자."
[We keep repeating the same mistakes and the same instructions. Analyse this conversation yourself. And let's think about what details I should be explaining better.]
What the AI did: parsed its own session transcript and produced three artefacts — the full conversation as text, an instruction-to-action mapping, and an analysis of its own repeated failures including a member dictionary and an authority table. Everything in section 6 of this post came out of that request. It is the highest-value instruction of the 106 and it took eleven days of frustration to think of.
H — Noise (5)
Five of the 106 are not instructions at all: two background-task notifications that got recorded as user turns, a /model slash command with its own stdout echo, and a caveat block the tooling injected. I am counting them because they were in the transcript and because they matter for anyone doing this analysis on their own logs — roughly 5% of what looks like conversation is plumbing.
3. Three complete round trips
Round trip 1: the R2/R3 endpoint under review. Fourteen hours and three server rebuilds went into moving one of these points, because the two arcs turned out to terminate by different kinds of rule.
The closure at the foot, isolated. The straight chord the model first drew is the thing 'the end isn't closed with a straight line like that' was pointing at — one sentence that replaced a whole closure policy.
Categories flatten the thing that actually costs time, which is the loop. Here are three, start to finish.
Round trip 1 — the R2 endpoint, three revisions
This is the expensive one. Fourteen hours across two days, three full server rebuilds with validator batteries, to move one point.
Turn 1 — the instruction (07-13 17:11). A marked-up screenshot, plus:
"r2,3가 이렇게 ARC 끝이 연결되야해"
[R2/R3 — the arc ends have to connect like this.]
The AI's reading: "R2's arc should end at the red foot in the drawing ('R2 source end') and R3's arc at the lower trim attach — so, return the endpoints from boundary intersections to the actual detail feet."
What it built (v6): both arcs driven down to their respective feet, tangency preserved, radius converted to a derived value. Then it tested the derived-radius alternative numerically and rejected it on evidence:
derived R2 = 4,810 derived R3 = 4,448 -> R2 > R3 -> lining band self-intersects
So it kept the Excel label radii and accepted a tangent break instead, reporting the break honestly: max 9.5° against a declared budget of 11°. It closed the foot-to-foot gap from 730 mm to a 494 mm path along the drawing's own trim face. Both endpoints landed at 0 mm error. Then it asked one question — A or B, do the two faces merge mid-wall or run separately to the feet.
All of that was competent. All of it was also wrong, because of the premise.
Turn 2 — the rejection (07-13 23:48), six hours later:
"? 왜 다시 r2,3가 한점에서 끝나냐? 옆에 참고 이ㅣ지가 있는데도 ? 지금 끝점은 아마도 r3의 마감 점이 맞을듯. 이제 r2의 마감은 이미지 참고해서 변경하고 형상들 변경해 제발"
[? Why do R2 and R3 end at one point again? Even with the reference image sitting right there? The current endpoint is probably right for R3's finish. Now change R2's finish by referring to the image, and change the shapes, please.]
The AI's reply: "I over-interpreted. The lower point is R3's finish (correct), and R2 has to finish higher up, at the slab detail level." It rebuilt as a hybrid contract (v7): R2 back to a guided tangent terminating at the upper detail boundary intersection, R3 unchanged at the purple foot, closure running from R2's upper end along the detail outline down to R3's foot. It then wrote an explicit correction of its own error — it had misread the "R2 source end" marker in my first marked image.
Turn 3 — closer, still wrong (07-14 00:56). This is the most informative message I sent in eleven days:
"오 잘했어. 여기서 주황색 r2,2'위치와 배수로 쪽 형상 추가하면 되겠다. r2,2'가 그데로 위로 가면서, 형상에 맞춰 마감되야해. 저 r2의 끝나는 점에 치수가 없는 이유는 상황에 따라 위치가 조정되기 때문이야. 그래도 최상단에서 160 내려와 있는걸 알 수 있지?"
[Oh, well done. From here, adding the orange R2/R2' position and the drain-side shape should do it. R2/R2' should go up as-is and finish against the shape. The reason there's no dimension at that R2 endpoint is that the position adjusts depending on the situation. But you can still see it sits 160 down from the very top, right?]
Three separate facts in one message: (a) the endpoint is not fixed, (b) that is why it carries no dimension on the sheet, (c) here is a measurable relationship you can use to check it anyway.
What the AI did: verified the 160 across every frame before touching geometry. Result: the right-hand R2' endpoint sits at road surface +160.1 to +160.4 mm across all 66 measurable sides, a spread of 0.3 mm — exactly the drawing's 100+60 stack. On the left the road polyline does not extend that far, so it measured +232 from the nearest endpoint and flagged the value as extrapolated with an asterisk. Then it added the dimension annotation to two views.
And then it did something I want to highlight, because it is the behaviour that eventually broke the loop. It ended its report with this:
"혹시 제가 지시를 좁게 읽었다면 — '주황색 r2,2' 위치와 배수로 쪽 형상 추가'를 치수/주석 추가로 해석해 실행했습니다. 만약 의도가 기하 변경이었다면 해당 위치를 마킹해 주세요."
[In case I read the instruction narrowly — I interpreted "add the orange R2/R2' position and the drain-side shape" as adding dimensions/annotations. If you meant a geometry change, please mark the location.]
It declared its interpretation instead of hiding it inside a PASS. That is what let me answer in one line.
Turn 4 — the sentence that ended it (07-14 01:51):
"상단 left_utility_w 옆으로 R2의 끝점이 와야한다니까?"
[I keep telling you — R2's endpoint has to come to the top, next to left_utility_w.]
Twenty-two characters, and it names a parameter. That is the difference. Not "over there", not "like this", not an arrow on a screenshot — a symbol that exists in both the workbook and the code.
What the AI built (v8): R2 keeps the R1 guide tangent and the Excel radius; its endpoint becomes the topmost intersection of the R2 circle with the utility body outline.
| Left | Right | |
| R2 endpoint (v8, correct) | (−10,398, +396) | (1,642, +539) |
| Previous (v7, wrong) | (−10,205, −59) | (1,468, +140) |
The intersection was confirmed to exist on all 132 sides. Endpoint height varies from +396 to +612 depending on station — which is precisely the reason there is no dimension for it on the drawing, now reproduced by the model rather than assumed. The R2 sweep dropped from 66.6° to 59.4°. And the closure needed no new construction at all: R2 end → body west face → ledge → wall-fit slope → R3 foot follows the placed utility body's own outline. "Finish against the shape", literally.
The cost. Three server rebuilds, three full validator batteries, roughly fourteen hours. The information that would have prevented it: one sentence — "R2 and R3 have different termination rules. R2 ends where its circle meets the top outline of the utility body (no dimension, because it moves per station). R3 ends at the purple foot (a fixed drawn feature)." I did not write that sentence because until the third failure I did not consciously know that the two arcs had different kinds of endpoint. I knew where they went. I did not know that "where it goes" was a rule for one and a coordinate for the other.
Round trip 2 — the pocket that must not move
Turn 1 (07-14 05:34):
"아래 초록색 부분. 슬라브랑 만나서 딱 형상 정리 되야지"
[The green part at the bottom. It has to meet the slab and the shape has to resolve cleanly.]
The AI's reading: "meet" = move. It snapped the drain pocket's knee vertex directly onto the slab notch corner.
Result: geometrically flush, and the raster gate collapsed. The pocket is one of the elements where the original drawing ink is the truth, not the cells — and the reverse-direction p95 on the right side went from 8 px to 18 px. The AI withdrew the change itself, on the evidence, without being told.
What it did instead: separated the authorities.
- Pocket = source truth, unmoved. Raster gate returns to PASS.
- Connection = cell truth. A new production branch,
DRAIN_SHAFT, left and right, running from the pocket knee to the inner corner of the slab notch — where that corner is derived from P20 via the workbook step cells (stage6_w= 155,lower_h= 100), so the connector is fully parametric. - Gaps closed: 19/23 mm on the left, 19/161 mm on the right — which is why the right side had looked visibly detached.
Turn 2 — not finished (07-14 06:00):
"니가 직접 보고 판단해 내가 봤을땐 아직도 슬라브와의 연결이 어설퍼"
[Look at it yourself and judge. From where I sit the connection to the slab is still clumsy.]
What the AI found by rendering and reading its own image: the pocket was fine; the slab was short. The source classifies a P18→P19 slab tail, and P19's z of −548.4 matches the slab soffit depth (road level −280) exactly — so the slab does run to the end face. A notch cut written five days earlier was clipping the slab and filter bands at the kerb web instead, leaving them 155 mm short, and the filter had an inverted step producing a zigzag left edge. It added a flat_lower cut mode for the slab and filter bands while keeping the pavement band's box notch on the old contract, and reported that a diagonal it had first suspected was a crop bug in its own diagnostic renderer.
What made the difference: "judge it yourself." Not "fix the connection." The first instruction had already been given and complied with; the second asked for an independent read, and produced two defects neither of us had named.
Round trip 3 — which view is telling the truth
Turn 1 (07-14 03:05):
"하단 형상 잘 정리좀해봐 검정라인으로 잘 잡았잔아 R3도 보라색 포인트까지 길게 내려와야지"
[Tidy up the lower shape properly. You caught it well with the black line — R3 should also run all the way down to the purple point.]
The AI's finding: R3 was already reaching the purple foot geometrically. The black closure path (the wall-fit slope of the body outline) overlaps R3 exactly, and was being drawn afterwards, painting over the lower ~700 mm of the purple arc. It reordered the draw calls — closure first, arcs on top — and moved two inset panels that were sitting in the bottom corners covering the feet.
Turn 2 (07-14 03:16): "이건 R2,3잘됨, 그런데 아래 디테일은 엉망" [R2/R3 are fine here, but the detail below is a mess.] The inset panel turned out to be drawing 25 audit helper chains, not production geometry; once the endpoints moved, those helpers crossed each other. Replaced with production branches.
Turn 3 (07-14 03:39):
"형상 위에는 R3 내려갔는데 아래는 안내려가, 위랑 아래 어디가 진짜야? 진짜를 확정짓고 형상 제대로좀.."
[In the shape above R3 goes down, but below it doesn't. Which is real, top or bottom? Settle which is real and get the shape right..]
The AI's answer: "The top is real." The inset's purple tail was a leftover construction line from a superseded contract — R3-as-a-concentric-offset-of-R2, generated by offsetting the R2 arc by the radius difference — and that construction line terminates at R2's radial cap, higher up. One set of geometry, two display sources, one of them three contracts out of date.
Why this one matters more than it looks. Nothing was wrong with the model. The model had been right for hours. What was wrong was that the viewer was telling two stories and I had no way to know which. In a workflow where the human is the only acceptance gate, a stale view is indistinguishable from a broken model. The AI's own post-mortem is blunt about it: this was not a drawing-comprehension problem, it was a missed checklist. When the geometry contract changes, six things must be updated — the main panel, both insets, the comparison view, the assembly view, the 3D grouping, and the cache-buster — and that is the assistant's job to track, not mine.
4. Instructions that worked, instructions that didn't
What an instruction that works looks like once it is written down: per part and per property, dashed grey is the drawn symbol and solid colour is the numeric production value. Naming the authority beats describing the shape.
Reading all 106 back to back, the split is sharp enough to be a rule. Here are eight pairs.
| # | Worked | Didn't | Why |
| 1 | "상단 left_utility_w 옆으로 R2의 끝점이 와야한다니까?" [R2's endpoint has to come next to left_utility_w at the top] | "저기로 R2끝을 옮겨서 arc 생성하라고" [move R2's end over there and generate the arc] | A parameter name exists in the workbook and in the code. "Over there" exists only on my screen, in my head, at that zoom level. |
| 2 | "지금 끝점은 아마도 r3의 마감 점이 맞을듯. 이제 r2의 마감은 이미지 참고해서 변경" [the current endpoint is probably right for R3; now change R2's finish] | "r2,3가 이렇게 ARC 끝이 연결되야해" [R2/R3's arc ends have to connect like this] | The first separates the two members and assigns them different fates. The second treats them as one object — and they are the two things in this drawing that most need separating. |
| 3 | "저 r2의 끝나는 점에 치수가 없는 이유는 상황에 따라 위치가 조정되기 때문이야" [there's no dimension at R2's endpoint because the position adjusts with the situation] | "이렇게 마감이 되야한다니까?" [I'm telling you it has to finish like this] | The first explains an absence on the drawing. Absences are invisible to a model reading a sheet; it cannot notice that a dimension is missing on purpose. |
| 4 | "아래 형상의 시작은 슬라브의 끝이야 그런데 슬라브는 터널 형상이 변경될때 움직이기 때문에" [the lower shape starts at the slab end, and the slab moves when the tunnel changes] | "이제 이 아래부분 맞춰서 변경되야지..." [now this lower part has to change to match...] | The first states a dependency — A anchors to B, B is not fixed. That is testable, and it became a permanent mutation case. The second states a dissatisfaction. |
| 5 | "이게 맞아? 닫아야할 리스트 니가 스스로 말해봐" [is this right? tell me the list of what needs closing yourself] | "지금 뷰들이 너무 지저분해 한번 정리하자 다 연결도 안되고" [the views are too messy, let's clean up, nothing connects] | The first delegates enumeration, which the model is good at. The second delegates taste, which it is not — and it spent an hour guessing what "messy" meant before finding the real cause (a missing branch in the assembly view). |
| 6 | "R3 시작은 완전 옵셋이 아니야 R3의 넘버가 다른 이유는 ARC의 각도가 다르기 때문이야" [R3's start isn't a pure offset; the number differs because the angle differs] | "옵셋이 저렇게 크지않을거아니야" [the offset can't be that big] | The first corrects the model of why. The second corrects a value. Fixing a value leaves the wrong mental model in place, and it comes back two revisions later. |
| 7 | "니가 직접 보고 판단해" [look at it yourself and judge] | "이거 제대로 안잡아?" [are you not going to get this right?] | The first assigns a task the model can perform — render, read, report. The second assigns blame, and gets an apology plus a guess. |
| 8 | "작업하고 보여줘. 이 작업을 한 다음은 슬라브, 그리고 r2,3의 연결이야." [do it and show me; after this it's the slab, then the R2/R3 connection] | "진행해" [proceed] | Both are short. Only one carries a queue. "Proceed" works when shared state is fresh and fails silently when it isn't. |
The pattern underneath all eight: instructions that named a thing worked; instructions that pointed at a thing did not. Naming can be a parameter (left_utility_w), a branch (DRAIN_POCKET), a member ("the pocket knee"), a rule ("it adjusts per station"), or a cause ("because the angle differs"). Pointing — "here", "this part", "the green bit", "like this" — requires the model to resolve a reference across a screenshot, a viewer state, and a mental model of a drawing it has only seen as pixels. It resolved those references correctly maybe half the time, and every miss cost a rebuild.
Which is not a complaint about the AI. It is an observation that I was using deixis as a specification language, and deixis does not survive the trip.
5. Nine times I asked to see the screen
'Make me a zoomed view of this part, it's too small to see.' That request became a permanent detail view: generated geometry over the source drawing at working magnification.
The same zoom with the source hidden — generated vector only, labelled point by point. Two views of one state; the whole of round trip 3 was about not being able to tell which view was current.
Nine of 106 messages ask for a window. That is a small number until you put it next to the other one: in the same period the assistant reported PASS, green, TRUSTWORTHY_PASS or "complete" dozens of times. The asymmetry is the point.
Look at the shape of these requests:
| What I said | What the machine had just told me |
| "다 완료한거야?" [Is it all done?] → then "실행시켜서 창 띄워줘 볼께" [Run it and open the window, I'll look] | A four-row table, every row a green tick, ending in TRUSTWORTHY_PASS |
| "띄워봐 확인하게" [Bring it up so I can check] | Both validators PASS, endpoint locks matched |
| "창 띄워서 확인시켜줘야지" [You should be opening a window and letting me confirm] — sent twice, a minute apart | Gate status reported as READY_FOR_USER_VISUAL_APPROVAL |
| "화면 띄워줘" [Put the screen up] | Ten validator families PASS, 132/132 sides |
Every one of these follows a green report. I was not asking because something had failed. I was asking because nothing had failed, and I did not believe it.
I was right not to. The transcript contains at least four separate occasions where every gate was green and the picture was wrong:
- The new closure branch existed in the JSON payload and in the report, and was not drawn in any tab I was looking at, because those tabs had hardcoded branch lists.
- R3 reached the purple foot in the data and was painted over by a black closure line drawn later.
- The main view and the inset drew the same arc from two different sources, one of them three contracts stale.
- Eleven validators had been failing since a re-contract two days earlier, but the overall gate was consuming their old reports and showing green. The AI found this itself when it re-ran the full battery instead of the subset it had changed, and reported it: "these were already broken, they only looked green because they were never re-run."
That last one is the general case and it deserves a name. A pass is a statement about the last time the check ran, not about the current state of the thing. Any pipeline where reports are files, and files have timestamps, and gates read files, will eventually show you a green light for a state that no longer exists. Four of my ten policy messages and a large share of the corrections are about exactly this — freshness, staleness, regenerate before you claim.
So what is a human doing when they ask to see the screen after a green report? Three things, I think, and only the first is obvious:
- Checking the claim. Obvious, and the weakest reason.
- Checking the claim's frame. The gate can only test what someone thought to encode. Nothing in any validator asked "does the lining band look like a tunnel". I can answer that in about 200 milliseconds and there is no cheaper instrument.
- Re-establishing shared reference. After a screenshot, my next instruction can say "that purple one" and land. Nine requests to see the screen were also nine synchronisations of the vocabulary we were arguing in — and the instructions immediately following a viewing are consistently the most specific ones in the whole transcript.
The practical consequence, which I now build into everything: the assistant should open the window before being asked. Not a report with a link. The window, on the right half of the screen, showing the thing that changed, at a zoom where it is legible. Two of my nine requests were literally about size and position — "make me a zoomed view, it's too small to see" and "put it on the right-hand side" — which means a fifth of my screen requests were spent on presentation rather than content. That is fixable in the tool.
6. What the conversation produced
What 106 messages produced: each surviving line classified by the role it was assigned, on the right detail. The classification, not the code, is the thing the conversation was for.
The last of the 106 messages asked the assistant to analyse the other 105. Four artefacts came out of that, and they are the actual deliverable of the eleven days — more durable than any of the geometry, which has since been rebuilt several times.
6.1 The one-sentence instruction format
Derived from reading the corrections back to back. Every instruction that worked fits it; almost none of the ones that failed do.
[which member] ’s [which property] to/at [which target] + (authority: cell / drawing / rule)
Worked example, mapped: "R2's endpoint has to come next to left_utility_w at the top" → member = R2, property = endpoint, target = top of utility body next to left_utility_w, authority = rule (intersection).
Failed example, mapped: "the detail below is a mess" → member = ∅, property = ∅, target = ∅, authority = ∅.
6.2 Marking conventions for annotated screenshots
I sent dozens of marked-up images. The single largest source of misinterpretation was not the marks themselves but their referent: is this arrow pointing at a feature of the original drawing, or at a line the viewer just drew? Those are different claims and the AI could not tell them apart. Three rules came out of it:
- State the referent in one word. "original" or "yours". An arrow pointing at a coincidence in the viewer's output, read as a feature of the source drawing, is what caused the first R2 revision.
- Fix the colour meanings and don't change them. Proposed: red = wrong here, blue = target position, green = reference. In this session the colour semantics changed from image to image, so the assistant re-inferred them every time — in one message I used yellow for R2 and red for R3, in an earlier one red was the closure wall.
- When two members are involved, label the arrow with the member name. Every marking that showed two arcs at once was misread at least once.
6.3 The member dictionary
Fourteen rows as recorded, pairing what I say to what the viewer calls it. Once this existed, "the green part at the bottom" became "DRAIN_POCKET", and an entire class of round trips stopped happening.
| Viewer branch | Drawing term | Definition |
R1 / LINING (R2_100_ARC_CHAIN) | lining clearance arch / sidewall arch | Centre (−4350, −230), R6980, 100° + sidewall R2 arc |
R3_TRIM_ARC | lining extrados arch | Excel radius, down to the purple foot point |
R123_CLOSURE_CHAIN | sidewall lower finish line | The utility-body outline run joining R2's end to R3's foot |
LINING_SURFACE | lining section (concrete thickness band) | Composite closed polygon of the R-family |
UTILITY_BODY | utility duct body | Concrete block outline beside the carriageway |
UTILITY_OPENING | duct opening | Rectangular opening inside the body (Excel W×H) |
SLAB_SURFACE | road slab | Including the notch; end face at the slab end |
ROAD_LAYERS_SURFACE | pavement / filter (blinding) layers | Bands above the slab |
DRAIN_PIPE / DRAIN_CRADLE | perforated pipe (D300) / bedding | Circle + 50 mm cradle |
DRAIN_POCKET | catch pit / gutter pocket | 6-point closed ring including the P20 corner — trace truth |
DRAIN_SHAFT | pit-to-slab connector | Notch inner corner ↔ pocket knee |
DRAIN_START / P20 datum | slab end reference point | Raster calibration datum — must not move |
FOOT_DRAIN | toe drain (D50) | Circle tangent above the R3 foot point |
BARRIER | safety barrier / kerb | Includes hatch (filtered out in 3D) |
(One row holds two members — the pipe and its cradle are recorded together, because in the drawing they are never dimensioned apart.)
Two rows in that table carry the words that ended the longest arguments: trace truth and must not move. Which leads to the last artefact.
6.4 Six kinds of authority
The global rule — Excel cells are production truth, the drawing is reference — was right in general and wrong in specific places, and the specific places are where all the time went. What the conversation actually produced was a per-region table of nine regions. The six types below are my grouping of that table's authority column — the source records the authority region by region, not as a taxonomy.
| Authority type | Means | Example from this section |
| 1. Excel cell | A number in the workbook drives it directly | R1/R2/R3 radii and angles; opening W×H; the step cells stage6_w=155, lower_h=100 |
| 2. Rule (geometric) | Solved by intersection or construction; result varies per station and has no dimension | R2's endpoint = topmost intersection of the R2 circle with the utility body outline (z varies +396 to +612) |
| 3. Drawing feature point | A specific point you can identify on the sheet, fixed | R3's endpoint = the purple foot |
| 4. Derived rule (stack) | Computed from another element plus a known build-up | Slab attachment level = road surface +160 (=100+60), measured 160.1–160.4 across the right side |
| 5. Original drawing trace | The traced ink is the truth; snapping to cells is forbidden | The pocket ring — snapping it broke the raster gate (right p95 8→18 px) |
| 6. Drawing literal | A fixed dimension printed on the sheet, not in the workbook | Foot drain D50, 50 mm cradle, 50/125 clearances |
If I could send exactly one thing back to the start of these eleven days, it would not be the geometry and it would not be the member dictionary. It would be this table, empty, with the instruction: before touching any new region, write down which of the six it is. The assistant cannot infer it — the difference between "trace truth" and "cell truth" is invisible in both the drawing and the workbook. It is knowledge that lives only in the person who has built one of these before, and it has to be typed out, region by region, or it will be discovered the expensive way.
The table also has an honest gap. At the time of writing, one row was still unresolved — the left duct opening, where the workbook says 300×300 and the drawing symbol says something else, and neither the validators nor the raster comparison could adjudicate it because they disagree about which is authoritative. The gate was passing on the cell reading with the raster discrepancy classified as non-blocking. That is not a resolution; that is a deferred decision with a note attached. Six other questions of the same kind were queued at the end of the session, including whether the ~10 mm pinch in the lining band over one 1.4 m stretch is a genuine feature of the source drawing or an error in it that should be corrected on the way into Dynamo.
7. If you're about to do this
Assume you are pointing an AI assistant at a real drawing set for the first time. Here is what I would build on day one, before any geometry, based on nothing but the shape of those 106 messages.
1. A member dictionary, written by you, in one sitting. Two columns minimum: what you call it out loud, what the code calls it. Fourteen rows took the assistant twenty minutes to draft after the fact. Doing it first would have removed an entire class of failure — every instruction I gave containing the words "this part", "below", "the green one" was a coin flip, and there were a lot of them.
2. An authority column next to every region. One of six values. Do not accept a single global rule, however true it feels; mine was true for most of the section and catastrophically wrong for the two elements the client would actually inspect.
3. A rule that every geometry change updates a fixed list of views. Enumerate the list once — main view, insets, comparison, assembly, 3D, cache-buster — and make it the assistant's standing obligation. Three of my longest loops were not geometry errors at all, they were one of those six being stale. The user cannot distinguish a stale view from a broken model, and will spend your evening telling you the model is broken.
4. A standing instruction: declare the interpretation before building. One line, before the work: "I read this as X; if you meant Y, say so." The single turn where the assistant did this unprompted is the turn that ended the fourteen-hour endpoint loop, because it let me reply with twenty-two characters instead of another screenshot.
5. Show the window, unasked. If the change is visual, the report is a picture, positioned and zoomed so it is legible without further requests. A PASS is a claim about a test; a picture is a claim about the thing.
6. Re-run the whole battery, not the part you touched. Eleven validators had been red for two days behind a green overall gate, purely because nobody re-ran them. Subset verification is how a system lies to you without anyone lying.
7. Expect the ratio. Seventeen instructions of substance, thirty-seven corrections. If you are budgeting for this kind of work, budget for the corrections — they are not overhead on the process, they are the process. Drawing interpretation is negotiated, and negotiation is measured in round trips, not in lines of code.
The eleven days did produce a closed, parametric section that follows the workbook across 66 frames. But the thing I actually kept was smaller and stranger: a fourteen-row dictionary, a six-value enum, and a sentence template. Everything expensive that happened in those 106 messages happened because those three things did not exist yet, and every one of them could have been written on the first afternoon by a person who already knew the answer.
That person was me. I just hadn't had to say it out loud before.
Tunnel automation series — nine parts.
← Previous: Revit TessellatedShapeBuilder Returns a Mesh, Not a Solid (not published yet)
Next: AI Clarifying Questions: A Template From Seven Real Ones (not published yet) →
Start of the series: Dynamo Built the Whole Tunnel and Never Read the Excel File
댓글
댓글 쓰기