KOEN
How I work with AI · A field record

Using AI in a Way You Can Trust

Making the output falsifiable, and handing it over so it keeps running after the owner changes
Gichan Lee · AI Product Engineer bit-habit.com Real project cases · 2026
The three questions this document answers

Using AI comes down to proving three things — whether the result can be trusted enough to put into real work, whether the gain stays with the organization and keeps running, and whether the tools are chosen critically. What each topic asks, and why, is restated at the head of its own section.

flowchart TB
  R(["🧭 How I use AI — three things to prove"]):::root
  R --> H1
  R --> H2
  R --> H3
  H1["① Problem solving · architecture  (§1)
Can the result be trusted in real work
reliability = risk management"]:::h1 H2["② Work productivity  (§2)
Does the gain stay and keep running
personal skill → team capability"]:::h2 H3["③ Tools · models  (§3)
Chosen knowing the limits
technical decision-making"]:::h3 classDef root fill:#EFEBFE,stroke:#5B3FD9,color:#3B2A82,stroke-width:2.4px; classDef h1 fill:#EFEBFE,stroke:#5B3FD9,color:#3B2A82,stroke-width:1.5px; classDef h2 fill:#fdf4e8,stroke:#a8560a,color:#7a3d06,stroke-width:1.5px; classDef h3 fill:#eef3f6,stroke:#33505f,color:#333C52,stroke-width:1.5px;

0.Summary

My work is not to use AI faster, but to make its results trustworthy.
Models are confidently wrong. So confidence cannot be used as a signal.
That leaves one method — make the output falsifiable, and hand it over so someone else can carry it on.
Topic (assignment prompt)One lineCase · evidence
1.
Problem solving or
architecture improvement
On a problem whose answers cannot be graded, I made every value the AI produced traceable back to its source.
accuracy → replaced by traceability
💧 Case 1 · Hydrological survey cost verification — Korea Management Analysis Institute, government budget verification · private repository
Four layers of verification — source comparison · channel verification (PDFs shown as images, never extracted) · cross-file invariants · independent second estimate
Invariants 38 of 42 with zero error (the rest within ±1.7%) · two different files both state 355 sites · the ~40% gap against the independent path was not tuned away but attributed to exposed variables
Calculation 10 hours → 1 minute. The goal is not speed but that someone who knows nothing about hydrological surveys can verify it in an hour

✈️ Case 2 · Aviation-law RAG — the same problem under different conditions · data, code and scores all public
A ground-truth set can be built, so 45 configurations were graded automatically. The retrieval axis was made free — 0 API calls
On a tie, take the cheaper one — adopted a 38% token saving (which in fact ranks answers higher) · rejected agentic at 27× · the biggest variable was chunking (coverage 0.136 → 0.864)
[external grading] instructor's score 9/10 for completeness · first among the course participants
2.
Productivity gains
using AI
I left mechanisms so the gain reproduces without me — and those mechanisms are under test right now.
the metric is not hours saved but the scope that reproduces after the owner changes
The way the same organization works — meeting notes → AI proposal → human item-by-item approval → Board
Five mechanisms — division of labour (extraction by AI · Requirement Engineering by human) · approval gate · task model · two-layer leak gate · judgment recorded as ADRs
What the gates actually caught, three times — overturned an assignment (domain) · filtered out internal terminology (security) · reverted "it's done" twice (completion)
[stated] guideline review 10h → 2h
[log] 3 ADRs · 6 learning lessons · three team repositories onto one Board
And that metric is under test right now — since mid-June my available time dropped to two hours a day and two teammates joined. I am still watching how it turns out.
3.
Tool and model analysis
I observed the limits myself — in a different place for each model — wrote them down, and chose knowing them. Primary tool Claude Codelearning mode and flat-rate pricing are the reasons. Not taste, but the result of measuring tools one at a time
Six limits, each on its own model — Solar claims to know what it does not · confidence ≠ accuracy · tokens grow non-linearly in agentic loops · Gemini loses numbers and relationships on long input · GPT · Gemini cannot draw logical development · local models (8B·16B) are weak on narrow domains
The shared conclusion — take facts from tools and source documents; leave the model only judgment and assembly
Why on-premise is separate engineering when data cannot leave the building
Appendix A.
outside the prompt
a system in production
I applied the same principle to a system I run alone.
not an organizational case, so it was moved out of the main text — but it sits on the same line
Single-node k3s — about 20 services under *.bit-habit.com · 4 ARM cores · $0/month
What I asked AI for was not to build the infrastructure but to describe the running infrastructure so a third party can falsify it
Three marks of a falsifiable document — leave the ❌ on the scorecard · name what you chose not to fix · commit the ordering as a decision
Outage postmortem — 200 OK served the wrong site for 103 days. No check that only asked "did it respond?" could see it → checks now assert the response body, not the status code
How the three topics connect §3 raises the problem (models are confidently wrong), §1 builds the mechanisms (make it falsifiable), and §2 leaves them with the organization (personal skill → team capability).
So the same move repeats across all three sections — never leave only the result; leave the path the result came from. §1 attached a source to every number, §2 a rationale to every decision, and Appendix A an ❌ to every box it had not done. A document that records only what went well cannot be checked against anything.
Grades of evidence Throughout the text I mark [log] (verifiable in a repository or session record) and [stated] (internal material that cannot be published, so stated only). The cost-verification app in §1 has a private repository and its figures are masked, but the verification design is published in full. Case 2, §2 and Appendix A have open repositories and live sites (→ Appendix C).

1.Problem solving or architecture improvement

What this topic asks — can the result be trusted enough to put into real work.

Two projects are laid out in the same order — background → key prompts → verification. Read one, and the other puts the same things in the same places.

I chose these two because the presence or absence of a ground-truth set splits the entire verification design. The domains (river budgets / aviation law) have nothing to do with each other, and that is what separates what the design earned from what the domain gave.

flowchart TB
  subgraph GA["💧 Case 1 · hydrology · no ground truth"]
    direction LR
    A1["1-1 Background"]:::s1 --> A2["1-2 Key prompts"]:::s1 --> A3["1-3 Verification
traceable to the source"]:::s1 end subgraph GB["✈️ Case 2 · aviation RAG · ground truth exists"] direction LR B1["1-4 Background"]:::s1 --> B2["1-5 Key prompts"]:::s1 --> B3["1-6 Verification
hundreds of runs, auto-graded"]:::s1 end GA --> GB classDef s1 fill:#EFEBFE,stroke:#5B3FD9,color:#3B2A82,stroke-width:1.3px;

💧 1-1. Case 1 Background — what the work was, and why verification was hard

Assignment question What was the problem, and what were the technical constraints at the time? The work is verifying whether a government hydrological survey budget conforms to the Standard Estimate Manual (government-published labor/cost standards). Previously it was done by hand in Excel, taking more than 10 hours per case, and because estimation and checking happened in the same hands and the same sheet, errors had nowhere to surface. Repositoryprivate (client data, common to 1-1~1-3). Instead, the raw prompts, verification code and screens are carried in this document → Appendix B, masking policy

1-1-1 · What a hydrological survey is

One word first In Korean, sumun (水文) is not the floodgate (水門) of a dam. It means "the record of water" — hydrology.

1-1-2 · What cost verification is

The point is to trace everything back to the standards the state has published, not to instinct or custom.

The Standard Estimate Manual — that standard
flowchart LR
  A["Allocated budget
per-site annual unit cost
money actually set aside"]:::a B["Back-calculated from the Manual
cost-plus-fixed-fee
money the standard implies"]:::b A --- Q{{"The two differ
at which assumption?"}}:::q --- B Q --> T["Trace each assumption back to the source
measurement count · staffing · adjustment factors …"]:::t classDef a fill:#fdf4e8,stroke:#a8560a,color:#7a3d06,stroke-width:1.3px; classDef b fill:#EFEBFE,stroke:#5B3FD9,color:#3B2A82,stroke-width:1.3px; classDef q fill:#EFEBFE,color:#3B2A82,stroke:#5B3FD9,stroke-width:2.4px; classDef t fill:#eef3f6,stroke:#33505f,color:#333C52,stroke-width:1.3px;

1-1-3 · What the app did · did not do

What it did not doWhat it did
Rule on which side is right Put the two values side by side and let the source of the difference be traced
Substitute "the AI calculated it" for evidence Attach the source document and cell to every assumption

Three things are traced — how many measurements were assumed, how many people and hours per measurement, and which adjustment factors were applied. Change an assumption and the screen shows how the numbers move.

What was at stake

1-1-4 · The previous method (10 hours → 1 minute)

The aim — separate estimation from verification The point was never to make the calculation fast. The point was to move the time spent calculating into verification.
Once the logic is set up, estimation takes a minute, and all the time left goes to asking "where did this number come from".
Previous (manual Excel)The app
Estimationover 10 hours1 minute
Verification — hydrology expertnot separated from estimationabout 10 minutes
Verification — non-experteffectively impossibleabout 1 hour ← this is the real goal

That last row is the actual goal of the project: letting someone who knows nothing about hydrological surveys verify the work within an hour, just by following the evidence the app presents. It is about increasing the number of people who can verify.

1-1-5 · There is no ground-truth set

So I replaced accuracy with traceability. Instead of grading whether a value is right, the criterion became whether every number can be traced back to its source — because if it can be compared by eye, you can say it is wrong even without knowing the right answer.

Work that does not end The practitioners' know-how keeps being collected and reflected. Why a given assumption is set the way it is is not fully written in the standards; it is filled in by judgment accumulated in the field. Moving those judgments one by one into the app's evidence is ongoing work (→ the decision-maker feedback in §1-3).

💧 1-2. Case 1 Key prompts — demanding verification before code

Assignment question What was the key prompt (question) you gave the AI, and what was its answer? Describe how the conversation proceeded afterwards. The first prompt did not ask for code. It asked instead that "validation matters most, so cite the evidence for every sentence, every time".

1-2-1 · The first prompt, verbatim

Instead of a polished summary, the first prompt is kept raw. It came from audio dictation, so the sentences are rough and there are typos ("파악을 할 수 있느", "validtion") — which is exactly why it shows the flow of thought rather than a conclusion. Only the key parts are highlighted. (One internal data folder name is masked.)

강 별로 수문조사들을 한 것들이 다 저장되어 있는 데 너무 내용이 많고 그 예산이라고 할만한 부분도 카테고리가 너무 많다. 그래서 이 전체적으로 파악이 안되는데. 파악을 할 수 있느. 어떻게 보면 1분만에 이해할 수 있는 적절한 spread sheet와 인사이트를 보여주는 html을 만들어주고, 그 후 10분 정도 시간 들여서 이해할 수 있는 html도 만들어주고. 그 다음에 결국에는 궁극적으로 내가 원하는것은 1개 강의 수문을 조사시 몇명이 몇시간 얼마의 비용이 들어가는지 분석하는 것이다. 하지만 이게 바로 하게 되면 환각이 일어날수도있고, 이게 나름의 방정식일텐데 이해하기가 어려울 수도 있다. 마치 선형회귀로 서울 아파트 가격을 예측할때 다양한 feature들을 고려해서 더 정확하게 예측할 수 있겠다만, 그러면 이해가 안되니 heuristic하게 일단 size만 가지고 예측하는 것처럼. 처음에는 아주 간단한 마치 하나의 feature 고려하는 것처럼 정확도는 떨어지더라도 validtion이 될 수 있는 방향으로 해야겟다. html을 만들때 아무래도 streamlit으로 해야될 거 같으니. 아까 말한것과 다르게 html이 아니라 streamlit으로 만들어줘. 다시한번 말하는데 validation이 가장 중요하니, 가 문장의 근거는 실제 [내부 데이터]를 한번 가공해서 그 데이터를 매번 citation해줘.

Original prompt, in Korean — kept verbatim.

The line of thought inside that one paragraph

  1. There is too much data to see the whole Many files, and the budget categories are chopped far too finely.
  2. So I asked for the forest and the tree at once It will take a while anyway, so get both out of a single wait. The AI is good at the overall structure; I adjust the details.
  3. Why not ask only for the detail? The narrower and deeper the result, the more easily it diverges from what I wanted. And if the AI invents plausible numbers, there is no way to notice.
  4. So I asked first for a form I could check Even at some cost in accuracy, I must be able to follow where a value came from. Even if it fails, the overall context remains as material for the next turn.
  5. In the end what matters most is verification Before building fast comes whether the result can be trusted.
  6. So I made it attach a source to every number Which file, which cell a value came from is shown on screen alongside it.
  7. I switched tools mid-request too Static HTML → Streamlit. Because I need to change values and see the effect.

Not a single line about code. Every requirement is about "how will I trust this", not "what shall we build".

1-2-2 · Why I asked for the forest and the tree at once

This is the most misread part. It does not mean "make me three screens", nor "I will cross-check three results".

Forest
1-minute view — overall scale
What it makes
Totals and unit costs by river and year, summarized on one screen
Who reads it
The decision-maker. One minute, no explanation
Why delegate it
Pulling an overall structure out of scattered material is what AI does well
Between
10-minute view — decomposition
What it makes
Which items sum to that total, with a source citation on every value
Who reads it
Practitioners. They follow the numbers down to the source
Its role
The stair from forest to tree. Which item to dig into is decided here
Tree
Final — cost of one survey
What it makes
How many people · how many hours · how much — a unit cost built up from the statutory manual
Who reads it
The cost negotiation with the contracting authority
Its role
The basis for a ruling in that negotiation — "what the law implies", presented with the formula

1-2-3 · How the three screens actually came out

Forest screen — four numbered insights, each with a source citation in its footer
Forest · overall scale. Four conclusions and, right beneath them, the evidence lines, all on one screen — down to which file, which sheet, which cell a value came from (D24×E24=F24). All figures here are masked. Even reading only the remaining sentences, you can see what this screen does — every conclusion carries where it came from. And this screen was not a showpiece: the fourth item found that "the Standard Estimate Manual already prescribes person-days per measurement", and it ends with → used on the cost model v0 page. The key to the final calculation was picked up in the forest.
Middle screen — a bar chart of survey sites by province, travel-cost distribution by base, and a note confirming that the site counts in two files match
Between · decomposition. The total is broken down by province and by base. The single line at bottom right is the point of this screen — "sum of the serial-number ranges in the travel-cost file = 355 sites, exactly matching the survey-site file". Two different files were checked for saying the same number; mechanism 3 of §1-3 (cross-file invariants) makes its first appearance here. Travel-cost amounts and internal file names are masked; the site count, which is the basis of the comparison, is kept.
Tree screen — top of cost model v2. Question, statutory formula, collapsible source excerpt, station selector
Tree · final. The question is written verbatim at the very top of the screen — "for one measurement, how many people, how many hours, how much should the law produce?". Directly beneath it is the statutory formula behind that answer, with page 1 of the Standard Estimate Manual attached in a collapsible panel. The order shows the legal path to the value before the value itself.

The conversation that followed is carried below in 1-2-4~1-2-8 as raw (masked) text, and the outcome is organized in 1-3 — the process of turning back an AI that had mistaken the purpose, refusing coordinate citations, and distrusting the extraction channel itself.

How the conversation developed — five corrections

In every one, the AI was wrong first and I found it and changed direction.

App sidebar — 10-minute deep dive, cost model v0/v1/v2, raw Excel viewer, question history page list
Nothing was built in one shot; increasingly local models were stacked as v0 → v1 → v2. The raw viewer and the question history were kept as pages too.

1-2-4 · Misreading the purpose itself

아이고 니가 목적을 완전히 헷갈렸는데 … 우리가 원가 검증을 하는 프로젝트를 하고 있거든. 이 예산이 실제 그 법령하고 맞는지를 항상 보는 …

Original prompt, in Korean — kept verbatim.

Intent
Result

1-2-5 · Narrowing the scope to an atom

누가 그냥 todo를 해줘. 비용모델은 1개 강의 수문 조사시 몇명이 몇시간 얼마의 비용인지 부터 아는거로 하자.

새로운 비용모델을 만들자. 즉 매우 지엽적인 수문 1개 조사시에 몇명이 몇시간 얼마의 비용이 들어가는 지. 즉 특정 수문을 현재 조건을 보고 법령에 맞게 실제로 나오는지. 다른 예산은 일단 필요없다.

Original prompt, in Korean — kept verbatim.

Intent
Result

1-2-6 · Evidence that cannot be falsified

그 근거라는 부분을 spreadsheet의 일부를 복사붙여넣기 해서 누구나 spreadsheet에서 온 것처럼 해줘. … 새로운 수식이 나오면 그걸 근거를 보여줘

Original prompt, in Korean — kept verbatim.

Intent
Result
Evidence excerpt displayed as an Excel viewer — row numbers and column letters preserved, cited rows highlighted in yellow
Each value carries a collapsed evidence excerpt. Opened, it shows the source sheet coordinates (B101:D103) along with the rows before and after the cited one — you need the neighbours to judge whether a value was truncated or is simply like that. Amounts, addresses and internal file names are masked; the grid structure is exactly as in the source.

1-2-7 · Do not trust text extraction — show the source as it is

pdf는 확실히 표로 되어 있으니 읽기가 어렵네. pdf는 스크린샷도 그냥 찍어서 근거로 보여주라

Original prompt, in Korean — kept verbatim.

Intent
Result

Extracting the staffing table as text actually produces this.

(1) 평ㆍ저수 유량측정회0.050.650.850.90②●
Evidence rendered as an image of the Standard Estimate Manual staffing table — a published government document
This is how PDF evidence is attached — the page is rendered as an image so the table stays a table, and only the cited part is highlighted. Since nothing passes through an extractor, there is nothing to suspect was dropped, and the reader only has to look at the highlighted part. (Standard Estimate Manual — a published government document.)
The method in use, and its limit

1-2-8 · Demand the formula, not the result — so the evidence, not the answer, can be compared

현장 출동인원이 몇명이 필요한지는 원래 알 수 없나? … 적용보정계수 같이 수식으로 계산한것들은 그 수식까지 표현해야지. 모든 수식은 다 표현해줘.

Original prompt, in Korean — kept verbatim.

Intent
Result
  1. Finding — "on-site crew size" was hard-coded to the default 3. There was nothing to write in the formula slot as evidence.
  2. Check — the Standard Estimate Manual prescribes only cumulative person-days; it does not fix how many people work simultaneously.
  3. Derivation — a range from the data. Assuming completion within one day, and since people cannot be split, ⌈2.45⌉ = 3 people, with an upper bound of 4 given the grade composition.

A constant was turned into a derivation. Without demanding the formula, that spot would never have been visible.

Derivation of the water-surface-width adjustment factor — page 7 of the Standard Estimate Manual rendered as an image
The adjustment factor is the example. Writing only 1.0 gives no way to check why it is 1.0, but unfolding the decision rule alongside makes the evidence comparable right there: 100 ≤ B=150 < 200 → factor 1.0. Page 7 of the published manual, the source of the rule, is attached as the original image.

💧 1-3. Case 1 Verification and rollout — four layers before it reaches real work

Assignment question Before applying AI-written code or guidance to a real environment, what verification (test/review) did it go through? With no ground-truth set, accuracy was replaced by "traceability". Instead of grading whether a value is right, the criterion is whether every number can be traced back to its source.

1-3-1 · How to read this section

This is the core of the work — the validation that AI output passes through before it enters real use. In an environment where data cannot leave the building and a wrong value is immediately a legal and financial risk, reliability was not a feature but a requirement.

No individual promptsUnlike 1-2, these verification mechanisms had no individual instructions. Under the principle set in P1 — "verification comes first" — the AI built them itself, and I reviewed and adopted them. Deciding what to verify is human; executing it is AI. That is where judgment is spent.

Since there is no single correct answer, nothing can be scored. Instead every value is made traceable to its source, so that if something is wrong, a person can find where.

flowchart TB
  A["AI output"]:::src
  A --> B["Source comparison
excerpt keeping row·column coords"]:::dev A --> C["Channel verification
PDF as image, table intact"]:::dev A --> D["Cross-file invariants
do other files say the same"]:::dev A --> E["Independent 2nd estimate
a path that never sees the budget"]:::dev B --> F["Put into real use"]:::ok C --> F D --> F E --> F D -.->|"mismatches are not hidden"| G["published as known data issues"]:::warn classDef src fill:#eef3f6,stroke:#33505f,color:#333C52,stroke-width:1.3px; classDef dev fill:#EFEBFE,stroke:#5B3FD9,color:#3B2A82,stroke-width:1.3px; classDef ok fill:#5B3FD9,stroke:#3A2A7A,color:#ffffff,stroke-width:1.4px; classDef warn fill:#fdf4e8,stroke:#a8560a,color:#7a3d06,stroke-width:1.3px;

Below is the actual code — not a claim, but how it runs. (File names and amounts are parameters, so nothing is exposed; the logic is unchanged.)

1-3-2 · Source comparison — show the cited cell in its original grid

flowchart LR
  Q["cell to cite
e.g. E9"]:::inp --> R["raw_slice
keeps Excel row no. · column letter"]:::act R --> S["_row_style
called for every table row"]:::act S --> T{"is this cell
in the cited list"}:::dec T -->|"cell matches"| U["deep yellow + bold"]:::ok T -->|"row only"| V["pale yellow"]:::ok T -->|"no"| W["no colour"]:::inp classDef inp fill:#eef3f6,stroke:#33505f,color:#333C52,stroke-width:1.2px; classDef act fill:#EFEBFE,stroke:#5B3FD9,color:#3B2A82,stroke-width:1.2px; classDef dec fill:#fdf4e8,stroke:#a8560a,color:#7a3d06,stroke-width:1.3px; classDef ok fill:#eaf6f0,stroke:#0a7048,color:#08512f,stroke-width:1.2px; classDef bad fill:#fdeeec,stroke:#a3241d,color:#7a1a15,stroke-width:1.2px;
Highlighting cited rows and cells applib.py
def evidence(rel_file, sheet_name, row_from, row_to, col_from="A", col_to=None,
             note="", expanded=False, hl_rows=None, hl_cells=None):
    """Attach evidence as an excerpt of the original spreadsheet, highlighting cited rows (pale yellow) and cells (deep yellow)."""
    if hl_rows is None:
        hl_rows = []
    if hl_cells is None:
        hl_cells = []
    rows = set(hl_rows)    # Excel row numbers to highlight
    cells = set(hl_cells)  # cell coordinates to highlight (e.g. "E9")
    df = raw_slice(rel_file, sheet_name, row_from, row_to, col_from, col_to)

    # callback pandas Styler calls per row (same role as a function pointer argument in C)
    def _row_style(row):
        out = []
        for col in df.columns:
            cell_name = col + str(row.name)  # column letter + row number = cell coord (e.g. "E9")
            if cell_name in cells:
                out.append("background-color:#ffd54a; font-weight:600")  # cited cell
            elif row.name in rows:
                out.append("background-color:#fff3c4")                   # cited row
            else:
                out.append("")
        return out
# → an invented coordinate and a real one are separated by colour on screen.
Evidence excerpt screen — Excel row numbers 50·51·52 and column letters A~E preserved, cited row in pale yellow and cited cell in deep yellow
This is the screen the code above produces. Row numbers 50·51·52 and column letters A~E are exactly the original Excel coordinates, so the reviewer can open the source file and check the same spot. Pale yellow is the cited row, deep yellow the cell the value actually came from — the two branches of _row_style rendered directly as colour. Keeping the neighbouring rows (50·52) was deliberate too. Internal file names are masked.

1-3-3 · Channel verification — distrust the extraction path itself

flowchart LR
  A["PDF evidence requested"]:::inp --> B{"is there a rendered
image of that page"}:::dec B -->|"yes"| C["show the image as is
table layout survives"]:::ok B -->|"no"| D["fall back to extracted text
accept that tables may break"]:::bad classDef inp fill:#eef3f6,stroke:#33505f,color:#333C52,stroke-width:1.2px; classDef act fill:#EFEBFE,stroke:#5B3FD9,color:#3B2A82,stroke-width:1.2px; classDef dec fill:#fdf4e8,stroke:#a8560a,color:#7a3d06,stroke-width:1.3px; classDef ok fill:#eaf6f0,stroke:#0a7048,color:#08512f,stroke-width:1.2px; classDef bad fill:#fdeeec,stroke:#a3241d,color:#7a1a15,stroke-width:1.2px;
PDFs as images, with a text fallback applib.py
def evidence_pdf(label, txt_name, note="", expanded=False, hl=None):
    """PDF evidence: show a page screenshot (cited part highlighted). Fall back to text if absent."""
    title = "📎 근거 발췌 — `표준품셈(2023).pdf` " + label
    with st.expander(title, expanded=expanded):
        png = DATA / (txt_name + ".png")
        if png.exists():
            st.image(str(png), width='stretch')      # the image as is — nothing breaks the table
            st.caption("↑ PDF 페이지 스크린샷 (etl.py가 렌더링, 🟡 = 인용 문구). " + note)
        else:
            st.code(_read_txt(txt_name), language=None)  # fallback: machine-extracted text
            st.caption("↑ PDF에서 기계 추출한 원문. " + note)

# raw_slice — slice into a 2-D array keeping Excel coordinates (row number, column letter) alive
data = []           # data[row][col]
row_names = []      # Excel row numbers as the index
for r in range(row_from, row_to + 1):
    line = []
    for c in range(c0, c1 + 1):
        line.append(ws.cell(r, c).value)
    data.append(line)
    row_names.append(r)

1-3-4 · Cross-file invariants — do different files state the same fact

This first checks whether the baseline the last mechanism will use is sound. The per-site unit price in the budget table is not a value to accept just because it is written down, and if the baseline is wrong, however precisely the gap (%) is computed it means nothing.

Where the previous three mechanisms make things checkable by a person, this check catches things even when nobody looks. A self-consistent hallucination cannot pass it.

Invariant checkedHowResult
quantity × unit price = totalRecompute the product without looking at the total cell, then compare38 of 42 exact · 4 within ±1.7%
Number of survey sitesCounted separately from the site-status file and from a separate travel-cost fileBoth give 355
Before / after revisionRow-by-row comparison7 mismatching rows printed individually
Missing valuesCheck whether the address carries a province1 case found
flowchart TB
  A["row list: records"]:::inp --> B{"any blank among
qty · price · total"}:::dec B -->|"yes"| S["not eligible — skip"]:::inp B -->|"no"| C["model = qty × price
the total cell is not read"]:::act C --> D["err = total − model"]:::act D --> E{"is the error below 0.5"}:::dec E -->|"yes"| F["exact-match count +1"]:::ok E -->|"no"| G["update max error rate, publish"]:::bad classDef inp fill:#eef3f6,stroke:#33505f,color:#333C52,stroke-width:1.2px; classDef act fill:#EFEBFE,stroke:#5B3FD9,color:#3B2A82,stroke-width:1.2px; classDef dec fill:#fdf4e8,stroke:#a8560a,color:#7a3d06,stroke-width:1.3px; classDef ok fill:#eaf6f0,stroke:#0a7048,color:#08512f,stroke-width:1.2px; classDef bad fill:#fdeeec,stroke:#a3241d,color:#7a1a15,stroke-width:1.2px;
The invariant check loop app.py
# Cross-file invariant check: quantity × unit price = total. Recompute the product without reading the total cell, then compare.
records = items.to_dict("records")  # DataFrame → array of dicts (iterated like an array of structs in C)
n_exact = 0         # count of rows matching with zero error
max_err_pct = 0.0   # maximum error rate (%)
for i in range(len(records)):
    row = records[i]
    qty, price, total_val = row["수량"], row["단가_백만원"], row["총계_백만원"]
    if pd.isna(qty) or pd.isna(price) or pd.isna(total_val):
        continue  # if any of the three is blank, the row is not eligible
    model = qty * price          # these are facts stated by different cells, so
    err = total_val - model      # a self-consistent hallucination cannot satisfy this equation
    if abs(err) < 0.5:
        n_exact = n_exact + 1
    if total_val != 0:  # rows with a zero total are excluded from the error rate
        err_pct = abs(err) / total_val * 100.0
        if err_pct > max_err_pct:
            max_err_pct = err_pct
Invariant check screen — item, year and quantity columns visible alongside an error column, every row showing zero error
The actual screen. The last column, error (in millions of won), is zero throughout — meaning the value recomputed as quantity × unit price, without reading the total cell, matches the original total. The sentence above is its summary (38 of 42 with zero error, the other 4 within ±1.7%). The unit-price, total and model columns are masked because they are internal budget amounts, but what this mechanism proves is not those values but the equation among the three, so masking leaves the argument intact.

How the 4 mismatches were handled

WhereThey were not random but clustered in one item group — the new programme line being converted to automated measurement.
WhyThe total is not an Excel formula but a separately computed value, and the unit price is that value rounded to an integer for display, so dividing the total by the quantity diverges below the decimal point.
OutcomeA single equation caught a 0.13% difference no eye would find — and narrowed it down to which item group, at that.
ThereforeThe items used as the baseline held with zero error across all years. The divergences were not in the baseline, so the final comparison could proceed as planned. Without this check, there would have been no way even to ask whether the baseline was sound.
Anomalies found — published, not hidden All of them — the 4, the 7 and the 1 — were published as known source-data issues under "verification status" in the app and in the repository documents. Quietly correcting problems in the source would cost the verification tool its own credibility.

The [data] / [assumption] labelling convention settled here

WhatValues with a confirmed source are distinguished on screen from assumptions that were filled in.
WhyWhen verification fails, "is the data wrong or is the assumption wrong" has to be separated immediately. Mixed together, that is impossible.
In practiceWhen the AI plausibly filled in a particular unit price without a source, that value was marked [assumption] and left editable by the user.

1-3-5 · Independent second estimate — reach the same answer by two paths

The same cost is computed by two paths that know nothing of each other. Like debit = credit in double-entry bookkeeping, or two independent witnesses.

Path A · from the budget
allocated budget → per-site unit cost
top-down · based on tender material
≠ ?
Path B · from the law
Standard Estimate Manual × wage rates → cost
bottom-up · never sees the budget
Path A · from the budgetPath B · from the law
Directiontop-down — allocated budget → per-site unit costbottom-up — Standard Estimate Manual × published wage rates → cost
InputTender materialPublished law and published wage rates — never sees the budget
PreconditionA's unit price is used as the baseline only after the check in 1-3-4. If the baseline is wrong, the gap is meaningless.
If the two agreeThey have verified each other.
If they differIt is a signal of where something is wrong. In practice a gap of about 40% appeared, and rather than forcing the model to match, the causes of the gap (published wage rates · measurement counts · water-surface width) were exposed as adjustable variables and attributed.
Why compare against the budget at all Because the output is a ruling, not a number. The sentence needed is "within ±20%, therefore consistent" or "outside it, therefore evidence is required" — and without something to compare against, this is calculation, not verification. So an independent path shows its value precisely when the two diverge.
flowchart TB
  L["Manual person-days
by grade"]:::inp --> M["× adjustment factor
derived from width band"]:::act M --> N["× published wage rates
summed by grade = direct labour"]:::act N --> O["× overhead·fee + travel"]:::act O --> P["annual cost
the budget has never been read"]:::ok P --> R{"gap = annual vs UNIT
how far apart"}:::dec U["allocated unit cost UNIT
an entirely separate source"]:::inp -.-> R R --> Z["expose the causes as adjustable variables"]:::act classDef inp fill:#eef3f6,stroke:#33505f,color:#333C52,stroke-width:1.2px; classDef act fill:#EFEBFE,stroke:#5B3FD9,color:#3B2A82,stroke-width:1.2px; classDef dec fill:#fdf4e8,stroke:#a8560a,color:#7a3d06,stroke-width:1.3px; classDef ok fill:#eaf6f0,stroke:#0a7048,color:#08512f,stroke-width:1.2px; classDef bad fill:#fdeeec,stroke:#a3241d,color:#7a1a15,stroke-width:1.2px;
Building the cost from the law alone cost model v2
def once_cost(task_name, fct):
    """Payment for one measurement (travel included, VAT excluded) — the budget is never read."""
    r = labor[labor["업무"] == task_name].iloc[0]  # one row for this task from the manual
    dl = 0.0                                       # running sum of direct labour cost
    for g in GRADES:
        man_days = float(r[g]) * fct               # person-days by grade × adjustment factor
        dl = dl + man_days * wages[g]              # × published wage rate → accumulate
    cost = dl * (1 + ovh_rate) * (1 + fee_rate) + team * fare * 2
    return cost

# Direct labour for per-site fixed tasks: double loop over task rows × grades
fixed_records = fixed_tasks.to_dict("records")
fixed_dl = 0.0
for i in range(len(fixed_records)):
    r = fixed_records[i]
    for g in GRADES:
        fixed_dl = fixed_dl + float(r[g]) * wages[g]

annual = (n_py*cost_py + n_hs*cost_hs + fixed_cost) * vat_mult  # annual cost derived from the law alone
gap = (annual - UNIT) / UNIT * 100      # UNIT = allocated unit cost (value lives elsewhere). Difference between the two paths (%)
# → annual has never seen the budget. That is why the gap is a real signal.
Independent second-estimate screen — annual cost expanded into formula, substituted numbers and result columns, with the law-based cost set beside the budget unit price
Path B running for real. The values on the left are built up from Standard Estimate Manual person-days and published wage rates alone — the budget file is never read. Every amount is masked. Masking only one would let the rest reconstruct it: erase the total and the items still add up; keep the cost and the budget follows from cost ÷ (1+gap). So absolute amounts, ratios and component items all have to be masked together. The item and formula columns are kept, because this section's claim is about structure, not values — once you can see which terms sum to the annual cost and which formula each term comes from, the screen is verifiable without the numbers.

1-3-6 · The screen that passed four layers

Cost calculation expanded into formula → substituted numbers → result columns, based on published wage rates
The final output is not just a result number. Formula → substituted numbers → result sit in three columns side by side, so if a value looks off, which term diverged is narrowed down on the spot. The state the four preceding steps aimed at is this screen — not asking to be believed, but letting people check for themselves.

1-3-7 · After rollout — decision-maker feedback

The four above are verification before shipping; this is after. What is said here becomes the input to the next cycle.

The analysis closed with a results briefing to the decision-maker, a non-developer. There were three points. (Names and amounts masked; summarized, not verbatim.)

✅ What worked"The direction is right" was confirmed repeatedly. In particular, the structure where you enter inputs and a result comes out was said to be what had been wanted.
⚠ What to improveLine items and labour costs should be adjustable by the field staff themselves, an equipment item was missing, and the cost side was expected to produce a more finished, real deliverable.
→ Going forwardThe conclusion was one line — "we need someone available continuously, communicating alongside us and producing results." That remark became the starting point of the role of running an AI-collaboration system on an ongoing basis in that organization. Not a one-off deliverable but a relationship that keeps running.

✈️ 1-4. Case 2 Background — finding the right clause in 1,297 pages of regulation

Assignment question What was the problem, and what were the technical constraints at the time? A RAG system that finds the governing clause in the 1,297-page US Federal Aviation Regulations (14 CFR). It is a learning project built in a public repository, so the data, code and scores are all public and reproducible. Repositorygithub.com/bookseal/llm-app-lab · live at llm-app-lab.bit-habit.com
The ground-truth set, the grading code and the results for all 45 configurations are public, so everything described in 1-5 and 1-6 can be reproduced.
First — what RAG is Think of it as an open-book exam. Instead of making the model memorize all 1,297 pages (= stuffing everything into the model), when a question comes in you have it open only the relevant clause and answer from that. Reciting from memory invites fabrication; reading the page first leaves a record of which clause was consulted — the premise of this whole document (to trust it, the grounds must remain) applies here directly.
Two reasons not to stuff it all in — long inputs the model doesn't fully read (§3-3 limitation ④), and feeding it every time is expensive. So it is "find and feed," not "feed it all."

To find and feed, the code has to be prepared in advance. The terms that keep recurring below (1-5·1-6) are exactly those assembly parts.

PartWhat it does (analogy)Where the choice is
① Split
chunking
Cut 1,297 pages into searchable pieces — breaking a book down to sticky-note sizeCut on § clause boundaries, or by character count? Performance turns on this.
② Index
embedding
Turn each piece into a meaning coordinate — a map that places similar meanings close togetherWhich embedding model. Even with no shared words, close meaning still matches.
③ Retrieve
search method
Pull the pieces that fit the questionBy meaning (vector) · by word (keyword) · blend (hybrid)
④ How many
top-K
How many top pieces to hand over as groundsToo few drops the grounds; too many lets noise in.
⑤ Score
LLM judge
Whether the answer is good is graded by another model — a grader instead of a personAccurate, but it costs money every call.
Why this is a design problemMultiply ①×②×③×④ and the combinations run to dozens. You can't pick the right one by eye. Narrowing it by building an answer set and grading overnight, automatically is what 1-5·1-6 are — an approach that holds beyond RAG: when the options are too many and the answer can be written down, turn judgment into an experiment.

1-4-1 · What this project is

1-4-2 · What was at stake

1-4-3 · A ground-truth set can be built

✈️ 1-5. Case 2 Key prompts — asking not about the answer, but where it came from

Assignment question What was the key prompt (question) you gave the AI, and what was its answer? Describe how the conversation proceeded afterwards. I did not argue with the AI's answers; I asked where they came from. All three times, this followed the AI having answered fluently.

This section shows the principles set in 1-2 operating in the same places even as the domain changes. Here too the prompts are kept raw, typos and dictation artefacts included.

How this differs from 1-2 1-2 was the prompt at the start of the work. All three here come after the AI had already produced a result — the places where things are pressed on, rejected, and hardened into rules.

1-5-1 · Catching a description that differed from the code

Context — the AI described the hybrid search as RRF (rank fusion), and that description went straight into five places in the public documentation: diagrams, glossary, body text. Yet reading it, I never quite got it.

아니, 내가 궁금한건 앙상블을 어떻게 한지 아직 이해안돼. 어느 비율로 어떤 것을 쓰고, 언제 어떤 임베딩을 썼나?

Original prompt, in Korean — kept verbatim.

Intent
Result
Preserving the correction history

1-5-2 · Taking back a judgment the AI deferred — rejecting agentic

Context — after implementing agentic RAG itself and showing a quality advantage, the AI handed the decision over with Your call. Which way should we settle on?

지금 에이전틱으로 하면 그래도 10배 정도의 토큰 소모가 있는거 아니가? 우리는 단일 래그로 했을 때 복잡한 문제도 이미 잘 풀었다는것을 확인했어. 이정도 데이터에서는 에이전틱 루프 보다는 단일 래그도 잘 된다면 굳이 토큰 많이 써가면서 에이전트를 붙일 필요성ㅇ ㅣ있을까?

Original prompt, in Korean — kept verbatim.

Intent
Result
What the human did The AI showed "the quality is better" accurately. But it handed over the act of putting quality and cost on the same scale. It is easy to assume that adding an agent is always better, but once the tokens were measured, at this data scale the single-shot path fit better — "when to use an agent" was a call for whoever knows the corpus size and the cost to make.

1-5-3 · Put rules in configuration, not conversation

Context — I was running two sessions at once. One handled experiment code, the other documentation, both on the same repository. That leads to one session committing the other's unfinished work.

그리고 너가 커밋할때는 너가 작업한것만 올려줘. 너가 작업하지 않은건 그대로 둬

claude-memory-backup 에서 커밋 관련된 모든 엠디 파일에 '한 세션에서는 그 세션이 작업한 것만 커밋한다'는 것을 추가해줘.

Original prompt, in Korean — kept verbatim.

Intent
Result
Where this connects to §2 "Does it reproduce after the owner changes" is the criterion in §2, and that criterion already appears once here. Does the rule survive when the session changes — the same question at a different scale.
What these three share All three happened after the AI had answered fluently — not so much wrong as leaving something unexamined. Outwardly, none of them looked off. So what was used was not better intuition but one and the same question — "this part: where is the evidence, and was it considered?"

✈️ 1-6. Case 2 Verification and rollout — with a ground-truth set, grade hundreds of runs automatically

Assignment question Before applying AI-written code or guidance to a real environment, what verification (test/review) did it go through? With a ground-truth set available, verification was raised from something a person looks at into an experiment a machine grades. 45 configurations were run overnight.

Where verification in Case 1 was about making things traceable by a person, here it is about making them gradable by a machine. Two mechanisms were built, and 45 configurations were run on top of them.

1-6-1 · A secret exam — set aside questions never used for tuning

Holdout — sitting the exam with questions you tuned on inflates the score. So a few questions are set aside from the start as a "secret exam" used only for grading, never for tuning. I wrote 14 by hand and split them by purpose into three.

QuestionsPurposeWhy split
4Final exam — never used for tuning (split:"final")Fitting configurations to the remaining questions makes you strong only on those questions. Studying from the exam paper raises the score, not the ability.
3Refusal is the right answer — out-of-scope questionsMeasuring only how well it answers puts the model that bluffs about what it does not know in first place.
7For tuningThe questions used to fit configurations.

The refusal questions weren't there at first — I was only writing in-scope questions until I realized late that "does it avoid making up an answer to an out-of-scope question" also had to be tested, and added them.

1-6-2 · Cheap grading / expensive grading, separated

Retrieval grading retrievalGeneration grading generation
What is measuredIs the correct § among the retrieved resultsThe quality of the answer actually produced
Grading methodCompared in code — local embeddingsLLM judge
Cost0 API calls · $0Charged per call
ExecutionAll 45 configurations, overnightOnly the few survivors, after retrieval was settled

Because retrieval grading runs in code, all 45 configurations were swept for $0, and the paid generation grading was spent only on the few survivors — the same volume of experiments at roughly a tenth of the cost. That said, neither the generation grading nor checking that the grading is right is free, so this is less "completely free" than calling the expensive grader as little as possible.

1-6-3 · Result — on a tie, the cheaper one

Coverage = the fraction of correct clauses retrieval actually found (found ÷ total correct). MRR = how high the correct answer ranked in the results (closer to 1 the higher). Both are retrieval grading, scored in code — which is why they could be applied to all 45 configurations.

ConfigurationCoverageMRRTokens
§ boundary · bge · hybrid · K80.8640.63617,284
§ boundary · bge · vector · K5 — adopted0.8180.71810,802
char count · minilm · hybrid · K3 (last)0.1360.1822,939
JudgmentGrounds
The difference is marginalA coverage gap of 0.046 against first place (K8) — across 11 questions, effectively one question. Not a gap wide enough to decide on.
The adopted one is betterFirst place packs 8 chunks of evidence (K8), so it responds slowly. The adopted K5 uses 38% fewer tokens and answers faster, while ranking the correct answer higher (MRR 0.718 vs 0.636). It loses only 0.046 in coverage — put usability on the scale too and K5 wins.
On a tie, the cheaper oneIn an on-premise deployment, both inference cost and response latency are product constraints.
Rejected for the same reasonThe agentic retrieval loop grows tokens roughly quadratically (about 81k · 27× the single-shot path), too expensive for the gain. The deployment is single-shot; the loop was kept as a documented experiment.
The biggest variableChunking. Switching from character count to § clause boundaries moved coverage from 0.136 to 0.864. In regulation the clause is the unit of meaning, and cutting at 1,000 characters slices across it.

1-6-4 · After rollout — the instructor's score

Same here. After the automatic grading was done, what a person pointed out became the starting point of the next improvement.

Instructor's score — first among the course participants, 9/10 for completeness The grader was Larry Arnstein — who led Impinj to an IPO and Xnor.ai to its acquisition by Apple, and is now CTO of a generative-AI startup (Simply Augmented). Among several axes — speed, completeness and more — he weighted completeness especially highly, and on that axis, the one that rewards depth of thought, this placed first among the course participants. There was one criticism — "polish the UI further." Retrieved chunks, token counts and scores were exposed on screen as they were. That exposure was deliberate, for verification, but in a setting judging completeness it was the wrong default. Next time it goes behind a toggle — what the builder needs and what the user needs are different.
The limit of this verification, and the next moves I wrote the grading standard (the ground-truth set) myself, so self-bias remains — though completeness placed first even on the instructor's score, so that was not the decisive flaw. What looms larger is the retrospective:

1-7. What the two cases leave behind

Different conditions split the verification method. Here is where they split, on one page.

Case 1 · 💧 hydrology cost verificationCase 2 · ✈️ llm-app-lab RAG
DomainRiver budgets · government standardsAviation law (14 CFR)
Ground-truth setNoneCan be built (holdout)
Verification methodA person traces back to the sourceCode grades automatically
BottleneckCan it be trustedToo many configurations · grading costs money
What is the sameNever trust AI output as given — make it falsifiable
The two verifications side by sideThe hydrology case (one-off practice · traceability) and llm-app-lab (ground truth · automatic benchmarking) are the two faces of reliability — with no correct answer, make every value traceable to its source; with a correct answer, grade hundreds of runs automatically. They share one thing: instead of "trust me", "check it yourself".

2.Productivity gains using AI

This section's subject — the boundary of delegation Give it the meeting notes and the Board fills up. The problem is what comes next. All three actually happened here. So what this section covers is not the pipeline but what was delegated, and how the delegated work was pulled back.

What this topic asks — does the gain remain as team capability rather than personal skill. And for that, how far can work be delegated to AI.

flowchart LR
  M{{"productivity = the scope that reproduces
after the owner changes"}}:::root M --> P["Meeting notes
where decisions are made"]:::s2 P --> A["AI — read and propose
quoting the supporting sentence"]:::s2 A --> V["Human — judge
approve · question · reject, item by item"]:::gate V -->|"only what is approved"| B["GitHub Projects board
where the record lives"]:::s2 V -.->|"ask back if ambiguous"| P classDef root fill:#EFEBFE,color:#3B2A82,stroke:#5B3FD9,stroke-width:2.4px; classDef s2 fill:#fdf4e8,stroke:#a8560a,color:#7a3d06,stroke-width:1.3px; classDef gate fill:#EFEBFE,stroke:#5B3FD9,color:#3B2A82,stroke-width:1.8px;

2-1. Background — the problem the organization had

Assignment question What problem was the organization facing? The bottleneck was not development speed but the transmission of intent. What the decision-maker wanted reached the team lead and stopped there. Repository — KIBA-Automation/project_management_with_ai_agent · the raw meeting notes are private

2-1-1 · Intent stops at one person

[stated] About 40 staff, of whom 3 are developers — the team lead (me) and two team members.

WhoWhat they knowSo
The decision-makerWhat they want. Though not interested in AI as such — only whether it gets automated.Delegates technical judgment and looks only at results.
Team leadAttends the meetings, so gets the intent and the nuance.Up to here it travels.
Team membersKnow the meeting outcome but not what to build.This is where it breaks.
So the team lead is both bottleneck and gate

2-1-2 · Why the notes cannot be used as they are

Meetings run over video, following whatever comes to mind. Two things are in that record at once.

What survives transcriptionWhat does notSo
Decided facts · items mentionedUrgency · importance — carried by non-verbal expression and the nuance of tone.Priority can only be set by someone who was in the meeting, and must be re-aligned with the decision-maker.
Delegate the summary and it disappears
The problem in one line Intent stopped at the team lead, and turning it into something team members could execute was entirely manual. How far can that work be handed to AI — this section is the record of finding that boundary.

2-2. Approach and implementation

Assignment question How did you solve the problem? I split the work of turning intent into something executable into stages, and divided each stage between AI and human.

2-2-1 · Extraction is AI, Requirement Engineering is human

StageWhoWhat
ExtractionAISplits the transcript into chunks, reads line by line, pulls out Issues. Nothing is summarized wholesale, so no context is lost, and in practice almost everything is caught.
Requirement EngineeringHumanSplits the extracted Issues, writes the body and the checklist, and assigns urgency and importance.
ExecutionTeam members + AI agentsTake the organized Issue and work on it with AI agents.
Why priority cannot be handed over
The direction for reducing that effort Requirement Engineering has to stay human, but the time it takes can shrink. By continually injecting domain context and past judgments into the AI, drafts are coming out with less to fix — lowering the cost of passing the gate, not removing the gate.

2-2-2 · Approval gate — how far to delegate, and where to cut

It starts from the premise that AI can be wrong. So what was designed is not "how to instruct it well" but "how to make it come back to a human when it is wrong".

PermissionWhat
Done without askingObserving the Board · searching for duplicates · drafting proposed changes
Per-item approval requiredEvery write. The default is item by item; blanket approval only when a human has seen the whole list and says so explicitly
Forbidden even with approvalDeletion · permission and visibility changes · writes outside the designated Board · code and Issues below the Board · exposing note content on GitHub
Always requiredQuote verbatim the sentence from the notes that grounds each proposal · when ambiguous, do not guess — surface it and ask back
The criterion that split the rules

2-2-3 · Task model — put information in the structure, not the title

Moving what was said in a meeting into a Board item, the altitude to write at kept wobbling. You can write the ultimate goal, or a single checklist line.

I fixed it with one test — if you can clearly answer "is this done or not?", it is at task altitude.

AltitudeTestExampleGoes to
Too highNo end, so doneness cannot be judgedBuild a staffing recommendation systemMilestone
Task (standard)Doneness can be answeredAdd a filter to a given screenIssue
Too lowA single checkbox lineAdd a parameter to a functiontask list
The principle in one lineThe more information you put in the title, the worse; the more into the structure, the better. Nest child items under a parent and progress is computed automatically, but write the same information into the title and it has to be updated by hand.

2-2-4 · Leak gate — keeping meeting notes from leaving the machine

LayerWhatWhy
1 · Human reviewNotes first go into a folder excluded from git tracking. Only what passes review moves into the repository.Once pushed, deleting the file later still leaves it in history. The gate has to sit before the push.
2 · Machine patternsThe promotion script blocks five categories: national ID, phone, card number, bank account, emailThe last net for whatever human review missed.
Not doneSeparating by branchA staging branch also lands on the remote once pushed. It must be exclusion from tracking, not separation.
The limits of this gate

2-2-5 · Judgment into record

What was leftContent
3 ADRsWhy the tooling moved · the task model · the safety contract. Each records why it was decided that way.
Rejected alternativesWritten alongside each record. E.g. — "write first, audit later" was rejected because irreversible actions cannot be undone after the fact.
Open questionsPinned down as open — "These really are undecided. Written down so we do not pretend otherwise."
Abandoned pathsTools explored and dropped were preserved read-only rather than deleted. Not a deletion but a record of the route.
Where this connects to §1 Code shows what the system does; an ADR shows why it is that way. It is the same move as attaching a source to every number in §1 — never leave only the result; leave the path the result came from.

2-3. Effects

Assignment question What changed in productivity? [stated] Guideline analysis went from 10 hours to 2. And work the team lead alone used to clear began to be shared by the team — though it does not yet run evenly.
[log] 3 ADRs, 6 learning lessons, three team repositories onto one Board.
What productivity is measured by Not by hours saved but by "the scope that reproduces after the owner changes" — a tool that depends on one individual is a risk, not an asset.
The subject is the same organization that did the hydrological survey cost verification in §1, and this time it is the way of working itself.

2-3-1 · Changes felt in the organization

[stated] Changes felt directly in the organization.

WhatHow it changed
Long-document reviewOne guideline document, 10 hours → 2 hours (about 80% less)
Meeting → IssuePreviously the notes were effectively thrown away. Now Issues are extracted from the transcript without omission and go to the Board.
Requirement EngineeringStill human work, but the more context is injected, the less there is to fix.
ExecutionWork the team lead used to clear alone began to be shared by the team — not evenly yet (→ 2-3-5).

2-3-2 · What the records confirm

[log] Verifiable in the repository and session records.

ItemValue
Team repositories gathered onto one Board3
Work items migrated to the Board8 (all of them)
ADRs3
Tool-usage learning course6 lessons (5–15 min each)

2-3-3 · What the gates actually caught

Three things a human actually blocked · The AI proposed an item assignment as its top choice, calling it "nearly certain" → I overturned it, saying another item was correct. Domain judgment cannot be delegated.
· A document written by the AI retained terminology that would identify our internal domain → I caught it and generalized it. Security judgment cannot be delegated either.
· The AI declared "done" → I sent it back twice. Judging completion cannot be delegated.
The mechanisms in 2-2 exist to make sure these three always reach a human.

This is the evidence that the earlier mechanisms were not decoration. It is the record of the three things named at the head of this section actually being caught — because the proof that a system works is not speed but what a human blocked.

What the AI didWhat the human didSo
Paired Board items with repositories and proposed one as "nearly certain", ranked firstOverturned it, saying another item was correctDomain judgment cannot be handed over.
Wrote a repository introduction — terminology identifying the internal domain remainedCaught it — "it has to be more general so as not to leak company information…"In effect, the security standard from §1 applied to its own output.
Declared "done"Sent it back twiceThe introduction still described the old tooling, and the examples were internal work verbatim.

2-3-4 · The metric under test

At the head of this section I set "the scope that reproduces after the owner changes" as the metric. That metric is now being tested in a way I did not design.

Point in timeState
May 2026System started · full-time on it.
Mid-JuneTwo team members joined. At the same time my available hours shrank to two a day.
NowThe team members mainly carry the work · my remaining role is coordination and review.
Why two hours a day 6/22–8/14, eight weeks in Seattle, USA — the global education programme of the Ministry of Science and ICT's AI/SW talent initiative, 30 participants selected (Electronic Times · Kyongbuk Ilbo). Based at the University of Washington.
I did not step away; the structure changed so that I coordinate for two hours a day and the team members carry the rest. After 14 August the constraint is gone.
An unplanned test The builder's available time fell to a quarter and two new people joined. ADRs, an operations manual and a learning course are exactly what is needed in that situation — and the real conditions arrived a month after they were made.

2-3-5 · Limits and next steps

This is not a one-time handover but a loop that keeps turning. A person stands where business language becomes development language, and that spot is passed every week. Two things need to rise — verification speed and accuracy. Raising only one means nothing.

Where it is stuckCurrent responseWhat remains
Issues lack detail
Even organized and handed over, what to start with is unclear
Keep injecting context into the AI so drafts need less fixing Split approval into two points — ① is this a requirement worth starting ② does the implementation match that requirement. ①'s checklist becomes ②'s acceptance criteria.
Cannot get started with Claude Code
Given the tool, they stall on the first move
Demonstrating it alongside them — not explanation but a scene they can copy Turn the demonstration into an asset. I have not yet decided the form in which to preserve what I show — the learning lessons are the beginning of it.
Intent is missed
What the Issue says gets done, but anything beyond it must go through the team lead
Priority judgment stays human — nuance does not survive transcription There is no automatic verification. Attach §1's verification design (invariants · citation consistency) ahead of human approval, so approval becomes comparison rather than judgment.
What cannot be claimed yet

3.Tool and model analysis

What this topic asks — are the tools chosen with their limits understood.

flowchart TB
  C1["Tools · models used
what was used"]:::s3 --> C2["Why chosen
why this tool — a strategic choice"]:::s3 --> C3["Strengths · limits
where to trust, where to doubt"]:::s3 classDef s3 fill:#eef3f6,stroke:#33505f,color:#333C52,stroke-width:1.3px;

3-1. Tools and models used

Assignment question (e.g. Cursor, Claude Code, ChatGPT, Gemini, Perplexity, etc.) The current combination — work in Claude Code (flat-rate subscription, learning mode), current-events exploration in Perplexity (Comet browser), long videos and documents absorbed with Gemini. A feel for on-premise came from Ollama (local) and Upstage Solar.

3-1-1 · How I got here

  1. Asking and learning — the arrival of ChatGPT ChatGPT appeared while I was at École 42. I learned concepts by asking them one at a time, and started with copy-and-paste for code. Once search was added, I made it search first for anything current.
  2. Does it read everything if you put in a lot? — the Gemini context experiment Exploiting the large input, I fed in meeting transcripts of 1, 2 and 10 hours. Up to one hour it held; from two or three hours content started vanishing, and numbers and relationships in particular came out wrong. A million-token context is not the same as accuracy.
  3. Hence RAG — and NotebookLM's opposite limit The conclusion: rather than putting in a lot, find and insert only what is needed. NotebookLM was faithful to its sources but weak at weaving complex context together. That is where I saw that precise citation and broad understanding pull against each other.
  4. How far does generation go? — images and video I measured the limits while making learning material. Korean text in infographics barely works (GPT ✗ · Gemini ○), and logical development such as matrices or network flows only looks plausible while being wrong. So I draw those myself with Manim (3Blue1Brown's visualization library).
  5. On to agents — Antigravity → Cursor Antigravity gave me my first feel for how an agentic IDE runs, and in Cursor I saw it — what matters is not model performance alone but a design that asks about the workflow first. Attaching a browser, it even checked its own work by screenshot. But the API charges were expensive.
  6. Converging on Claude Code — and learning mode A flat rate could carry the same work, and above all the output style could be switched to learning. That was decisive.
  7. Now — roles divided Work in Claude Code, current news in Perplexity, long videos and documents in Gemini. And I am checking with local models what kind of constraint on-premise actually is.

3-1-2 · Role of each tool

ToolWhere it is usedWhy there
Claude CodeCode · verification · documentslearning mode · Plan · sessions · worktrees · conversation export. A flat rate means no cost anxiety about repeated experiments.
Perplexity
(Comet browser)
Current news · light browser workFaster than search, and with browser use it can even make simple configuration changes in a cloud console. ChatGPT Atlas has the same feature but its quota fills up quickly.
GeminiLong videos · bulk documentsDrop in a YouTube link and absorb one to two hours at reading speed. But without custom instructions a generic summary is useless.
Ollama (local)A feel for on-premiseRunning it on a laptop made hardware, memory and load time tangible as product constraints.
GrokTried in conversation onlyRelatively unconstrained and free-form. I have not decided where to use it — I am waiting because it is said to be coming to the car (Tesla).
GitHub CopilotBriefly, at a hackathonTried it at a Microsoft-hosted hackathon. Unremarkable. If it were far cheaper perhaps, but Claude Code is not especially expensive, so there was no reason to switch back.
Upstage SolarService implementation (Booktoss)It worked well as an agent that calls tools. Its limit is in 3-3-2 ①.

3-2. Why these were chosen

Assignment question Among the many AI models available, why did you choose that model (or tool)? I chose Claude Code as my primary tool, because I needed something usable as a senior engineer and a teacher, not as a thing that writes code for me — you cannot take responsibility for code you built without understanding.

3-2-1 · learning mode was decisive

Switch the output to learning under /configOutput style and, before giving the answer, it also explains why it did it that way and what should be learned. (The old command was /output-style, deprecated in v2.1.73 and removed in v2.1.91.)

The Output styles page of the official Claude Code documentation — the three built-in styles besides Default (Proactive · Explanatory · Learning), the TODO(human) description of Learning, and the note to use /config
Not my claim but Anthropic's own documentationcode.claude.com/docs/en/output-styles (checked 2026-07). Besides Default there are three built-in styles, and Learning is defined as a "collaborative, learn-by-doing mode where Claude will not only share 'Insights' while coding, but also ask you to contribute small, strategic pieces of code yourself". That it leaves TODO(human) markers in the code for a person to fill in is documented too — meaning "not a tool that writes it for me but a senior engineer and teacher", as stated above, is not my personal usage but the definition of the style itself.
What is differentSo
It makes you type terminal commands yourselfYour hands remember. Typed for you, you still cannot type it next time.
It gives context and intent alongsideWhat remains is not "this was done" but "this was done because of that".
It inserts insights along the waySomething learned remains after the task ends.
Why a prompt cannot substitute

3-2-2 · Cost is part of the choice

ToolBillingResult
CursorMetered APIThe design was good but it got expensive with use. It makes you hesitate to experiment.
Claude CodeFlat rate · around $100/monthThe same work can be repeated without cost arithmetic — part of why the 45-configuration experiment in §1 was possible.
GeminiFamily planGoogle offered it cheaply per family, and I started using it seriously from then. Which tool gets used when is sometimes decided by the pricing plan.
GitHub CopilotIf it were far cheaper perhaps, but Claude Code is not especially expensive, so there was no reason to move.
Could I have gone cheaper I weighed whether Antigravity or Codex would do. The conclusion is that learning mode alone keeps me here — on cost alone there are other choices, but my criterion is whether understanding remains alongside the result.

3-3. Assessment of the models — strengths and limits

Assignment question What strengths and limits of the model did you feel while doing this work? Strengths (Claude) — once a principle was set, it followed without individual instruction, and told to criticize its own plan it produced valid objections.
The limits appeared in different places for different models.
ModelWhere usedLimit observed there
ClaudeWork overallConfidently wrong (②) · in agentic loops tokens grow close to quadratically (③)
Upstage SolarService implementationWorks well as a tool-calling agent, but claims to know what it does not (①)
GeminiBulk inputOn long transcripts, numbers and relationships break from the 2–3 hour mark (④)
GPT · GeminiImages and videoCannot draw logical development — plausible but wrong (⑤)
Local (8B·16B)On-premise experimentsWeak on lesser-known localities and narrow domains (⑥)
One shared conclusion — take facts from tools and source documents, and leave only judgment and assembly to the model. The evidence for each number is in 3-3-2. Evidence repositoriesbookseal/Booktoss (①) · llm-app-lab (②③)

3-3-1 · Strengths — where the model earned its keep

StrengthModel observedEvidence
① Set a principle and it follows without instructionClaudeAfter nailing down "validation matters most" once in §1-2, the four verification mechanisms in §1-3 appeared without individual instruction. Follow-up work maintained that standard without being told each time what to verify. → What a human must set is the principle; repeatedly applying it can be delegated.
② Told to criticize its own plan, it actually bitesClaudeAsked to argue against its own RAG experiment plan, it produced six valid objections — "there is no reason to explore even the free axis sequentially", "binary recall is a false signal on multi-answer questions", "do not trust the scores before label verification". All were flaws in my original plan, and all went into the experiment design.
③ Context does not break in a large repositoryClaudeThrough file exploration → edit → execution it held on to earlier decisions. Code you cannot write by looking at a single file — such as an invariant check spanning several files — comes from that.
④ It leaves the reasoning in writingClaudeThe prose quality is good enough that, alongside the code, why it was done that way survives as documentation. For someone who treats "can a successor pick this up" (§2) as the productivity metric, that was the point, not a side effect.

3-3-2 · Limits — observed directly, per model

LimitModel observedEvidence and conclusion
① It claims to know what it does notSolarI built a library federated-search agent on the Upstage Solar API and it worked correctly. But when I named that service and asked "what is this", it answered as if it knew while it did not. → It can be trusted as an agent that calls tools, but you must not assume the model knows facts. Take facts from tools and source documents; leave judgment and assembly to the model.
② Strength of confidence ≠ accuracyClaude · SolarBoth ① and ③ below are cases of a model being confidently wrong. If confidence cannot be used as a signal, the only option is to make things falsifiable by structure. That is why the mechanisms in §1 were a requirement, not a choice.
③ Non-linear cost growthClaudeIn an agentic loop that calls repeatedly to improve retrieval quality, tokens grew close to quadratically (about 81k · 27× the single-shot path — measured in §1-5-2). The quality gain was not proportionate. → On equal quality take the cheaper option; the loop was kept as a documented experiment.
④ It does not read all of a long inputGeminiFeeding meeting transcripts of 1, 2 and 10 hours, it held up to one hour and content began vanishing from two or three. Numbers and relationships in particular came out wrong. → Context size is a ceiling on accuracy, not a guarantee. Rather than inserting a lot, I moved to finding and inserting only what is needed (RAG).
⑤ It cannot draw logical developmentGPT · GeminiAsk for matrix operations or network flows as images or video and the output is plausible but wrong. Korean infographics barely work either (GPT ✗ · Gemini ○). → I draw this part myself with Manim. Presentation can be delegated; logic cannot.
⑥ Weak on small localities and narrow domainsLocal (Ollama)I have a benchmark of my own — "where is Gamman-dong?". It is a lesser-known neighbourhood in Busan, so whether a model has learned that far is a ruler for how much it knows. Local models (8B/16B class) said a lot of wrong things here.
→ Even so, there are places to use them. For short reactions like "nice · keep going" they are sufficient and affordable. But they cannot be used where judgment is required.
Beyond the limitsThese limits are not left as criticism. For instance, Solar's inability to express confidence can be turned back into a score by attaching a separate verification signal (such as a Groundedness Check) — naming a tool's limit and then building the side that improves it — that is the work I want to do.

3-3-3 · When to use what

SituationChoiceReason
Exploration · learning · writing documentsClaude Code (learning mode)Result and understanding both remain
Looking up a factNot the model — tools and source documentsLimit ①
Bulk repetitive processingSingle-shot first; loops only after measurementLimit ③
Sensitive dataLocal execution or on-premiseEnvironments where data cannot leave the building really exist
The actual conversation that set the rule When the AI tried to implement a whole module, I cut it off like this. (llm-app-lab · original prompt, in Korean — kept verbatim)
"워워.. 니가 다 짜면 안 된다. 우리는 공부중이고. 다시 전으로 돌아가서 개념노트를 보고 뭘할지 같이 고민하자. 내가 코딩을 하면서 공부할거고 … 너가 시니어라 생각하고 나를 가르쳐주면서 같이 파일을 만들고 하면서 공부해야지."
The last item — on-premise Running local models on a laptop made it tangible. Where data cannot leave the building, the model has to be brought next to the data, and at that point hardware, memory and load time become the product's constraints. That is where I understood why on-premise demands separate engineering.

3-3-4 · The direction I am interested in

The cost verification in §1 could not send client data outside, and the meeting notes in §2 ran into the standard that "company material must not be handed to outside services". Most of the work I have done has been in places like that.

OptionWhat I weighed
Local modelsI have run them, but the level drops in narrow domains, so they cannot be used as they are. Useful for getting a feel.
Open-weight modelsI intend to attach recently released ones to toy projects. But a model whose training process and alignment method cannot be inspected is hard to put where judgment itself becomes evidence.
Domestic on-premiseThe option that actually remains where data cannot leave. Both cases in this document fall there.
An aside — on all the noise about domestic AI
Which is why this role interests me §1 was about "how to make a value produced by AI falsifiable", and §2 about "how to leave that method with an organization". If the role requires doing both at once in an environment where data cannot leave the building — the work so far carries straight over.

A.Appendix — making a running system verifiable by others

The claim in §2 is about an organization; this appendix is the record of applying the same principle to a system run by one person. It is not an organizational case, so it was moved out of the main text, but it sits on the same line as this document's theme — "make what AI wrote falsifiable by a third party".

The subject is a single-node k3s cluster I have run alone since 2025 — about 20 services under *.bit-habit.com run on it.

A-1 · How I got here

I passed a Linux certification in my first year of middle school. I passed it by rote, and I knew then that I had not understood it. I am thirty-eight now, so for 25 years since, I have been looking for ways to overturn that.

This cluster is the continuation of that, and I imposed the constraint myself — how far can one person get on one free machine. Four ARM cores, 20 services, $0 a month.

Documentation forced by constraint With no slack, if I do not write down what is set up and why, I am the first to forget. So what I asked the AI to do was not to build infrastructure but to describe already-running infrastructure so a third party can falsify it.

A-2 · What I asked the AI to do · did not

TaskWho
Collecting the cluster's actual state (kubectl measurements)AI — the source to compare the document's claims against
Writing the 5-stage learning structure · checkpoints · glossaryAI — scaffolding
Deciding what to publish and what to record as a limitHuman — judgment
Touching the production clusterHuman — the AI is given no execution rights

The result is infra.bit-habit.com. The source is in the public repository bookseal/bit-habit-infra, and the live state is checked externally every 60 seconds at status.bit-habit.com.

A-3 · Three marks of a falsifiable document

"The documentation is good" is an unfalsifiable claim. Instead I look at whether it is in a form a third party can compare against. Three things went in.

① The ❌ on the scorecard A document listing only successes cannot be compared. So the current position against the GitOps standard is laid out in a table, with the failing cells left in place — Secrets ❌ gitignored, applied by hand · Namespaces ⚠️ mostly a single default. And the conclusion is written in one line: "the gap from industry standard is not the tooling and not the services, it is secrets."
② Naming what was deliberately not fixed At the end of an incident postmortem, the things deliberately not fixed in the same change were recorded separately — a stale copy of the routing table left in another repository, an image mount method whose commit hash cannot be determined. The reason is in the document as written:
"Writing down what you decided not to fix is part of the retrospective too. A known issue that is not written down is indistinguishable from an unknown one."
③ Writing the order as a decision

A-4 · Incident postmortem — 200 OK

habit.bit-habit.com served a different site for months. Not an error page — a valid certificate and 200 OK, serving a perfectly wrong site. Because the uptime monitor and my own status page both asked only "did a 200 come back?", the incident was invisible to every automated check.

Diagnosis went by layer-wise bisection — at each step, ask "is the problem above or below this layer" and cut one side away. The decisive move was calling the app's Service directly from inside the cluster. The app was fine, so the fault lay in front of it. The real cause was two independent failures overlapping.

flowchart TB
  B["Browser requests
habit.bit-habit.com"]:::s2b --> T["Traefik reads the routing table"]:::s2b T --> F1["Failure ①
rule points at the wrong Service
portfolio ← not the app"]:::bad F1 --> N["nginx in the portfolio Pod
receives the request"]:::s2b N --> F2["Failure ②
no server_name matches this host,
so it falls back to the default block"]:::bad F2 --> R["200 OK + the wrong site
no error anywhere"]:::bad APP["Flutter app
fine · healthy · unreachable
0 traffic for 103 days"]:::ghost classDef s2b fill:#EFEBFE,stroke:#5B3FD9,color:#3B2A82,stroke-width:1.3px; classDef bad fill:#fdeeec,stroke:#a3241d,color:#7a1a15,stroke-width:1.6px; classDef ghost fill:#f2f2f4,stroke:#8a8a95,color:#55555f,stroke-dasharray:4 3;

The root cause was not a routing bug. It was a single-source-of-truth bug. The app existed only in the cluster and in no repository at all. So the one line pointing at that app lived in a file that did not know the app existed. An ownerless rule drifts, and nobody notices.

What came out of it — a flaw in the verification system itself

A-5 · Why I built it, and how I used AI

WhyWhat I got
Learning was the pointI had seen k3s while evaluating other people's assignments, but without building it myself I did not know it. It is the standard I have kept for 25 years since passing a certification by rote in middle school — what must remain is understanding, not the artifact.
I wanted my own serverI wanted to see how far one free machine goes. Certificates, routing, deployment, incidents — once all of it passes through your own hands, you get a feel for it.
How AI was used — scaffolding by AI, execution by me
Current deployment structure

B.Appendix — masking policy

Before publication, everything was substituted exhaustively against the following criteria and re-checked by searching again.

TargetTreatment
Names of contracting authorities, agencies, clientsReplaced with [contracting authority] and similar
Internal team and unit namesRemoved
Facility and site addressesRemoved (counts kept). Site names published by the government, such as the national observation network, are kept so the screens remain readable
Internal budget amounts in absolute termsAll removed; only ratios used (±1.7%, about 40%)
Internal file namesReplaced with generic names
Local paths · accountsRemoved or generalized
IPs · API keys · tokens · passwordsRemoved after an exhaustive search of text and logs
Personal data (names, contact details, etc.)Exhaustive search found none
Published documents such as the Standard Estimate ManualQuoted as is, being published government material
Note — the same standard applies routinely When moving related projects into public repositories, the .gitignore was built on the standard that "statutory and manual PDFs are published documents, so include them; internal budget spreadsheets are excluded". AI session logs are a learning asset but are not published as they are — terminal output drags along absolute paths, environment values and credentials, so the exporter script is tracked while its output is excluded.

C.Appendix — public material

The public repositories and live sites that support each claim in the text. You can open them and check directly.

What it supportsRepository · live
§1-4 ~ §1-6 Case 2 — ground-truth set · 45-configuration benchmark · grading code github.com/bookseal/llm-app-lab
llm-app-lab.bit-habit.com (live)
All of §2 — agent operating rules (CLAUDE.md) · ADRs · Board scripts KIBA-Automation/project_management_with_ai_agent
Raw meeting notes are private — meetings/ is excluded from git tracking
§3 limit ① library federated-search agent
(built on the Solar API and working, but does not know its own name)
github.com/bookseal/Booktoss
booktoss.bit-habit.com (live)
Publishing the limits of the operating and observability infrastructure as open problems github.com/bookseal/bit-habit-infra
status.bit-habit.com (live status)

What is not publishedThe repository for the cost-verification app, the central case of this document, is private because it handles client data. The §1 screens above have internal budget figures, survey site addresses and internal file names masked, leaving only the published Standard Estimate Manual (Appendix B). Not being able to show the strongest evidence as it is, is the price accepted in this kind of work.