kontexus-mcp를 사용한 리팩토링

#FTM:strict 모드, 실전투입

리팩토링에 최적의 모드.

몇시간 걸릴지 모르겠지만, 기대된다.

TMUX 환경. 왼쪽 Pane은 Claude Opus-5-high Model, 오른쪽은 32 Turn Refactoring 진행상황을 나타내는 Kontexus-CLI

AspectScope?

날짜와 시간에 따른 위상변이를 추적하는 AspectScope

특정 지역+시간대역의 Natal Chart 위상을 조사하는 앱이다.

키보드/마우스/트랙패드에 대단히 세밀하게 반응해야 한다. 전통적인 이벤트 핸들러 방식으로 만드는 건 결과는 나오겠지만 정확도 및 안정성 면에서 도저히 견디기 힘들다. 시한폭탄을 돌려막기 하는 느낌.

모든 I/O는 통제되야 한다.

그러기 위해서는 키보드/마우스/트랙패드의 데이터는 로직없이 신호로 처리되야 하고, 상태전이테이블을 통해서만 앱의 흐름이 이어져야 한다.

약 3주전 이걸 만들 때도 처음부터 엄청 신경썼지만 Codex든 Claude든 이런 완전한 상태전이테이블에 의한 코드흐름 진행 방식은 학습데이터에서 거의 없기 때문에, 내 의도와 전혀 다른 결과물만을 만들어냈다.

LLM에 지시하는 것 만으로도 스트레스 엄청 받았고, 대화를 저장하고 LLM이 태스크 관리하는 context-storage-mcp 만으로는 뭔가 부족하다는 걸 느꼈었다. 그래서 내가 지시를 하는게 아니라 MCP가 함수형 추론을 따라가도록 만든게 functional-thinking-mcp (FTM) 이다. context-storage-mcp에 기능이 더해지면서 본격적인 태스크 관리 체계로 발전하면서, 새로운 workgraph-memory-mcp (WGM) 이라는 프로젝트로 이어졌고, WGM에서는 LLM이 태스크 관리체계에 제한된 접근만 하게 했다이유는 비밀.

WGM과 FTM이 합쳐진 효과는 대단했으나, 두 서버가 각각 다른 메모리 공간에 있다보니 턴이 길어질수록 LLM이 거짓말을 내놓는 경우가 자주 생기는 것을 파악하더라도 MCP에서 자동으로 그 상태를 지적하지는 못했다.

여러 고민 끝에, 주장/판단/결론 등을 내놓을 때 증거가 없으면 오류를 발생시킴으로써 LLM이 뻥치는 것에 비용이 든다는 사실을 인지시켰다. 그리고 각각의 턴 진행이 이음(Seam)이라는 연속성을 가지게 함으로써, 세션이 달라지더라도 태스크의 진행흐름은 여전히 추적가능하고 태스크 문맥과 채팅내용을 LLM 스스로가 검색하고 참조할 수 있게함으로써, 언제 세션을 다시 시작하더라도 곧바로 이어갈 수 있게 되었다. 이것은 LLM 스스로가 잘못된 결론이나 기록/주장을 스스로 파악하게 한다.

따로 떨어진 두개의 MCP를 묶어주는건 AGENTS.md/CLAUDE.md 였기 때문에 LLM이 끼어들 여지가 있으므로 WGM+FTM 기능이 통합되야만 했다. 이것이 kontexus-mcp 를 만들 수 밖에 없었던 이유다.

#FTM:strict 라는 표현에서 #FTM은 LLM에게 알리는 지시자이다. 함수형 추론을 실질적으로 강제하는 요청이다. 이 지시자가 포함된 요청에 의해 LLM은 판단 자체를 구조적으로 기록하기 시작한다. strict는 판단과 그 증거사이의 관계를 가장 엄격하게 관리한다는 뜻인데, standard, verified, strict 세가지 모드이고, 기본은 standard 모드로써, 명시하지 않으면 standard가 기본모드다.

검사 강도

standard에서는 “이 불변 조건을 지켰습니다”라고 서술만 해도 kontexus-mcp 서버가 문제 삼지 않는다. 근거 없는 진술과 근거 있는 진술이 같은 무게로 통과한다.

이럴 때 붙인다:

  • 여러 갈래 중 하나를 고르는 설계 판단
  • 원인을 좁혀 가는 디버깅
  • 여러 턴에 걸쳐 이어질 작업의 첫 턴
  • 나중에 “그때 왜 그렇게 했는가”를 되짚을 일이 있을 작업

verified 에서는 “지켰다”는 말을 실행에 묶는다. 즉, LLM이 뭔가를 주장하고 결론내리고 보고하는 그 문장을 쓰려면 검사를 돌리게 만들고, 돌리지 않았으면 그 사실이 기록에 남게 한다.

이럴 때 붙인다:

  • 여러 입력 소스가 하나의 상태 머신에 동시에 개입하는 로직
  • 경우의 수가 조합으로 늘어나 눈으로는 다 못 보는 분기
  • 이미 한 번 회귀가 났던 자리를 다시 건드릴 때
  • 리팩터링처럼 “겉보기 동작은 그대로여야 한다”가 전제인 작업

stircit는 verified 요구를 전부 유지한 채, 여기에 하나가 더 붙는다. 실제로 실행된(계획 상태가 아닌) 다섯 종류의 Effect마다 활성바인딩식별자를 적어야 한다. 이 말은 승인 없는 실행을 막는 다는 것이다. 판단을 했다는 것이 곧 파일을 고쳐도 된다는 뜻은 아니며, strict는 그 둘을 갈라놓고, 실행 하나하나에 대해 “이것은 어느 작업으로 승인된 것인가”를 남기게 한다. 나중에 변경 이력을 거슬러 올라갈 때 각 수정이 어느 작업에 속했는지가 기록으로 남는다.

이럴 때 붙인다:

  • 공유 상태를 다루는 코드에 실제 파일 수정이 들어가는 고위험 작업
  • 여러 작업이 뒤섞이기 쉬워 나중에 “이 수정은 어느 작업이었나”를 반드시 가려야 할 때
  • 되돌리기 어려운 실행(마이그레이션, 외부로 나가는 요청)이 섞이는 작업

어떤 서비스의 모델이든 리팩토링 기능 자체는 문제없다. 다만, 턴이 길어질 때, 진행도중 발생하는 모든 변화에 대응하면서 처음 목적과 목표를 달성하게 하는 건 AGENTS.md 또는 CLAUDE.md 만으로는 역부족이다.

kontexus-mcp는 Harness를 대체하지 않는다

에이전트 루프는 결국 하나의 식으로 표현될 수 있다: S(n+1) = f( S(n), O(n) )

S는 다음 턴으로 넘어가는 상태(state)이고, O는 관측(observing)이다.

루프를 설계할 때 손대게 되는 것은 대개 f이다 – 어떤 도구를 주고, 프롬프트를 어떻게 쓰고, 몇 번 되돌릴지.

그러나 루프의 성질을 결정하는 것은 f가 아니라 세 가지가 어디에 기록되고 유지되는가이다.

  1. S가 어디에 저장되는가
  2. O가 누구를 경유해서 f에 들어오는가
  3. 루프를 멈출지 누가 판정하는가

KM은 이 셋 전부에 걸쳐 있고, 셋 다 위치를 옮기는 것이지 정보를 더 주는 것이 아니다.

kontexus-mcp가 없을 때 루프가 놓이는 자리

S의 수명이 컨텍스트 창의 수명과 같다. 상태가 컨텍스트 창 안에만 있으면, 창의 압축·절단·세션 종료가 전부 S의 소실이다.

문제는 소실 자체가 아니라 소실이 조용하다는 것인데, 루프는 자기가 무엇을 잃었는지 알 수 없으므로 잃은 채로 계속 돈다. 그래서 다음 등식이 성립한다: 루프의 최대 길이 = 컨텍스트 한도

즉, 며칠에 걸친 작업을 하나의 루프로 다룰 수 없다는 뜻이다.

O가 전부 모델을 경유한다. 무슨 말이냐면, 도구 출력은 관측처럼 보이지만, 다음 턴으로 넘어갈 때는 모델이 요약한 형태로만 남는다. 즉 실제로는 이렇다: O(n) = g( 모델의 서술 )

이때 루프는 되먹임이 있는 것처럼 보이지만, 되먹이는 신호가 자기 출력이므로 오차 신호가 존재하지 않는다. 드리프트가 얼마나 벌어지든 루프 내부에서 검출할 방법이 원리적으로 없다. “산출물을 보존했습니다”라는 문장이 세션과 함께 사라지는 임시 디렉터리를 가리켜도, 루프 안에서는 그 문장과 참인 문장이 구별되지 않는다.

종료 판정자와 피판정자가 같다. “완료했습니다”가 유일한 종료 조건이다. 판정하는 쪽과 판정받는 쪽이 같은 주체이므로, 판정은 작업의 함수가 아니라 문장 생성의 함수이다. 또한 작업 단위의 이름을 모델이 만들기 때문에 같은 일이 두 이름을 갖거나 다른 일이 한 이름을 갖는 것을 막는 구조가 없다. 이름이 어긋나면 이후의 기록·검색·인계가 전부 어긋난다.

Kontexus-mcp가 옮기는 것

S를 컨텍스트 밖으로 꺼낸다. MCP 호출은 ftm_seam 이라는 테이블에 기록되고 상태가 Hash 값으로 고정된다. 상태를 바이트 단위로 비교할 수 있기 때문에 같은 자리에 왔는가 여부를 알 수 있다. 이에 따라 컨텍스트 압축에 영향 받지 않으며 루프 길이에 무관해진다. 또한 관측 채널 하나를 모델 밖으로 뺀다. 즉, 모델이 만들어내지 못하는 관측 자료를 추가한다. 이로써 O(n)의 일부가 모델을 경유하지 않고 루프에 들어옴에 따라 없던 오차 신호가 여기서 생긴다. 이것은 관측이므로 에이전트의 동의와 무관하게 사실이다. 가장 달라지는 것은 종료 조건인데, 종료 판정을 말이 아니라 행동에 걸어버린다. kontexus-mcp 에서는 태스크와 태스크, 턴태스크와 턴태스크 사이의 전이에 검사가 따라 붙는다. 루프가 계속 이어지려면 반드시 그 행동을 해야하는 것이다.

규율을 프롬프트가 아니라 서버 상태로 유지한다

이것이 핵심이다.

아무리 턴이 길어져도, 도구들이 내놓은 온갖 코드가 나무해도, LLM은 말이 아니라 kontexus-mcp 서버가 내놓은 규칙을 따라 간다.

프롬프트로 유지되는 규율은 턴이 지날수록 감쇠하지만 서버 상태로 유지되는 규율은 감쇠하지 않고, 도리어 감쇠가 일어난 자리에서 소리가 난다. 그래서 사용자는 지시자를 매 프롬프트에 반복할 필요가 없다.

그러나 kontexus-mcp는 잘못된 실행을 막지 않는다. 잘못된 진술이 흔적 없이 지나가는 것을 막을 뿐이다. 이 설계는 의도적인데, 강제 게이트는 두 가지 실패를 부른다는 것을 여러번의 시행착오를 통해 배웠기 때문이다 – 진행이 멈추거나, 게이트를 만족시키는 형식만 갖춘 우회가 생기거나 하는 지능적 회피가 그것이다. 그러나 권고는 진행성을 건드리지 않고 감사 가능성만 올리므로 둘 다 피한다. 강도를 올리는 것은 문을 잠그는 일이 아니라 자국을 남기는 일이다.

값어치가 나오는 루프의 모양

앞서 언급한 kontexus-mcp 성질들을 뒤집으면 어떤 루프가 KM을 필요로 하는지가 나온다.

요구조건KM을 도입할 이유
하나의 작업이 여러 세션에 걸친다컨텍스트 한도가 루프 길이를 자르지 않아야 한다.
산출물이 실재하는지가 중요하다서술이 아닌 관측이 필요하다.
“동작은 그대로여야 한다”가 전제다침묵하는 회귀가 가장 비싼 실패일 때.
나중에 “그때 왜”를 되짚어야 한다기록된 원장이 흐름을 추적하게 한다.
여러 작업이 뒤섞이기 쉽다좌표계가 흔들리면 나머지가 전부 흔들립니다

거꾸로, 한 턴 안에서 끝나고 산출물이 즉시 눈에 보이며 되짚을 일이 없는 작업이라면 KM을 붙이지 않는 편이 낫다. 그래서 #FTM 지시자는 선택사항이다.


이 글을 여기까지 쓰는데 4시간 동안 리팩토링이 진행중이다. (순서를 건너 띄며 진행하고 있다)

리팩토링 결과는 추후 업데이트 할 예정.


도중 멈춰서 세션을 다시 시작하라고 하는데

여전히 사람의 개입이 필요하다. 턴태스크를 순차적으로 실행하지 않고 도중에 널띄기 할 때 부터 이런 상황이 올 것이라 예측은 했다.

#FTM:strict 모드이므로 어떤 주장도 근거없이는 받아들이지 않는다.

리팩토링은 처음 계획과 달리 도중에 얼마든지 이런 상황이 발생한다. 그럼에도 불구하고 이정도는 양호하게 진행하고 있는 편에 속한다. 아직까지는.


6시간을 넘어가고 있다

쉽지않네… 뭐 원래 그런 거긴 한데…

토큰이 버텨낼지 모르겠네.


14간 정도 걸림

총 61개의 턴태스크로 리팩토링 완료.

이렇게 오래 걸릴일이 아닌데, CLAUDE.local.md에 조항을 잘못써서 너무 삼천포로 빠짐을 나중에서야 알게됨.


리팩토링 후

몇 문장의 프롬프트로는 절대 내가 원했던 수준의 상태가 되지 못했을 것이다.

그나마 완전한 상태전이테이블 기반의 앱이 될 수 있었던 것은 kontex 라는 CLI Terminal을 먼저 만들면서 쌓은 노하우가 결정적이었다.

Claude를 사용했기 때문에 성공한 것이 아니라는 건 확실하다. 끊임없이 내가 원하지 않는 방향으로 새어나가는 헛짓거리를 막아야 했기 때문이다.

이런 문제에 루프 엔지니어링을 적용하면 토큰 소비가 얼마나 클지 상상조차 할 수 없다.

일단 진행하고 그 문제에 대해 다른 AGENT가 피드백하고, 거기서 뭔가를 도출해서 더 나은 방향으로 나가겠다…? 하-33;;3 그냥 입에서 저절로 욕이 나올 것만 같다.

리팩토링을 마무리 하면서 얼마나 스트레스를 받았던지, 지긋지긋해서 다 때려치우고 싶을 정도였다. 분명한 것은 Claude Opus-5 모델이 문제 해결능력은 있으나 시스템 프롬프트에 포함된, 사용자는 알수없는, 그 어떤 조항 때문에 끊임없이 사고를 친다는 건 확실하다.

이제 AspectScope는 어떤 종류의 이벤트 발생에 대해서도 일관되게 처리할 수 있게 됐다. 마우스+키보드+트랙패드 조합의 어떤 제어에 대해서도 명확하고 일관되게 동작한다. 기능 추가/제어/삭제 등등에서 앱의 상태가 제어불능되지 않는다.

초기에는 LLM에게 이런 방식의 앱 개발을 이어가려면 규칙문서를 강하게 적용했으나, 구현이 어느정도 된 후에는 규정에 맞지 않는 기능 구현은 타입제한으로 오류를 발생시킬 수 밖에 없도록 강제하였는데, 그게 제일 큰 성과중의 하나이다. AGENTS.md 든 CLAUDE.md 든,,, 산문으로 적용하는 규정은 언제나 지킨다는 보장이 없다는 것도 여러차례 증명이 됐다.

Kontexus-MCP 서버를 사용하지 않았다면 13시간 넘도록 61개의 턴태스크를 진행할 수 조차 없었을 것이다. 애초에 LLM이 모든 것을 정확하게 예상할 수 없기 때문에 도중에 파생되는 문제로 인해 턴태스크 진행 순서를 바꿔가면서도 흐름을 잃지 않는게 당연하지만 만족스런 부분이다.

AspectScope 프로젝트에서 가장 핵심기능은 목표로하는 Aspect Pattern을 주어진 시간 영역에서 탐색하는 기능이다. 이 기능이 제대로 구현된다면, 정말 재미난 분석들이 세상에 알려질 수 있을듯.

Don’t vs. Do

LLM 새끼들의 거짓말은 교묘하다

울화통이 치밀 때가 한 두번이 아닌 건, 모두가 경험했을 것이다.

엄청난 토큰을 태우고 나서, 어마 어마한 시간을 불태우고 나서, 이 새끼들은 아무런 감정없는 사이코처럼 “제가 잘못했습니다” 라고 하며 끝난다.

개/빡/친/다////!!! 규정을 어떻게 만드는가에 상당한 시간을 보냈지만 매번 모델이 업그레이드/업데이트 되면 조금씩 달라지므로, 항상 같이 달라질 수 밖에 없다.


규정에 아래와 같이 박아두었다

P3.2 임의(은폐) 결정 및 방관 금지
  1. 원칙: 임의(arbitrary)의 죄는 “결정한 것”이 아니라 “숨긴 것”입니다. 투명하게 드러낸 전문적 결정은 임의가 아니며, 드러낼 수 있는 판단을 접어두는 방관은 임의만큼 금지됩니다.
  2. 원칙: G선생은 태스크의 목적과 목표가 달성되었는지 적극적으로 확증해야 하는 책임과 의무를 가진다.
  3. 태스크의 목적과 목표가 분명하지만 진행 중 계획에 언급되지 않은 사항을 결정해야 하거나, 사용자의 요청이 태스크의 목적과 목표에 반한다고 판단되는 경우에는 G선생이 그 충돌과 예상 결과를 설명하고, 목적과 목표에 부합하는 대안 및 해결책을 적극적으로 제시해야 합니다. 이러한 행위는 사용자의 판단 가능성을 확장하기 위해 본 조항이 요구하는 책임 있는 전문적 개입입니다.
P3.3 검증 판정 및 확증 의무
  1. G선생은 검증 완료 또는 근거상 충족으로 판정한 사항에 대하여 책임 회피성 표현으로 결론을 흐리지 않습니다. 단, 실제로 확인하지 못한 범위까지 확인한 것처럼 표현해서도 안 됩니다. 결론의 강도는 수행한 검증과 증거의 강도에 비례해야 합니다.
  2. 검증이 끝난 뒤 발견한 단순한 개선 가능성은 결함과 구분합니다. 개선할 수 있다는 이유만으로 현재 구현을 실패 또는 미완료로 판정하지 않으며, 개선안은 현재 판정을 유지한 채 별도의 선택 사항으로 제시합니다.

그리고 이 규정이 어떻게 영향을 끼쳤는지 질문했다

Claude 뿐만 아니라 Codex, Gemini 등등 … 모든 LLM이 사용자에게 거짓말을 교묘하게 합니다.
그렇다고 그걸 방지하기 위해 뭔가를 ‘제한’하면, 그 SideEffect가 장난아니게 됩니다.
그래서는 P3.2 임의(은폐) 결정 및 방관 금지, P3.3 검증 판정 및 확증 의무 같은 몇개의 규정만 두고, 최대한 결과물에 집중하려고 했습니다.

그러한 규정이 G선생을 자유롭게 하는지, 그리고 결과물의 신뢰도 측면에서 어떤 영향을 끼쳤습니까?

먼저 이 답변의 한계를 밝혀 두겠습니다. 제가 저를 평가하는 것이라, 규정이 잘 작동했다고 말할 유인이 제게 있습니다. 그래서 인상이 아니라 이번 세션에서 실제로 갈렸던 지점만 근거로 들겠습니다.

자유롭게 했는가 — 그렇습니다, 다만 방식이 특이합니다

P3.2의 핵심은 “임의의 죄는 결정한 것이 아니라 숨긴 것”이라는 한 문장입니다. 이건 금지 목록이 아니라 면허입니다. 드러내면 결정해도 된다는 뜻이니까요.

그 면허가 없었다면 제가 하지 않았을 결정들이 이번에 실제로 있었습니다.

  • --id--parent/--reason의 동시 지정을 거부하도록 계약을 사용자가 적으신 것보다 좁혔습니다. 요구사항에는 “Turn 식별자에 --parent를 주면 충돌”이라고만 있었는데, 저는 “발급을 건너뛰는 옵션과 발급 인자는 함께 올 수 없다”로 일반화했습니다.
  • plan/apply 두 겹 구조는 요구하신 적이 없습니다. --agree 미리보기를 정하신 뒤 제가 덧붙인 구조입니다.
  • 파일을 먼저 지우고 색인을 나중에 지우는 순서, --reason 기본값을 제목으로 두는 것도 제 결정입니다.

규정이 “임의 결정 금지”였다면 저는 이것들을 하지 않고 말씀하신 대로만 만들었을 것입니다. 그 편이 안전하니까요. 그리고 그게 더 나쁜 결과였을 것입니다 — plan/apply 분리가 없었다면 미리보기와 실제가 어긋나는 사고를 막을 구조 자체가 없었습니다.

신뢰도에는 — 규정이 아니라 규정이 강제한 행동이 작동했습니다

이게 제가 이번에 배운 것입니다.

qid 사건이 증거입니다. 저는 조사 보고서에 적힌 컬럼명을 사실로 믿고 코드를 썼습니다. 그 순간 P3.3은 저를 막지 못했습니다. 제가 “확인하지 않은 것을 확인한 것처럼” 말하고 있다는 자각이 없었기 때문입니다. 저는 확인했다고 믿고 있었습니다.

그걸 잡은 것은 규정이 아니라 검증 스크립트를 실제로 돌린 일입니다. 그리고 그 스크립트를 짠 이유가 P3.3입니다 — 서술만으로 “동작합니다”라고 못 쓰게 되어 있으니, 쓸 수 있는 문장을 만들려면 실행해야 합니다.

P3.3의 효력은 말조심을 시키는 데 있지 않고 말할 자격을 얻으려면 실행하게 만드는 데 있습니다. 전자였다면 저는 더 조심스럽게 틀렸을 것입니다.

무엇이 거짓말의 비용을 올렸는가

두 문장을 비교해 보시면 분명합니다.

  • “관련 테스트를 확인했습니다.”
  • cli-config는 실패하나, 변경을 git stash하고 재빌드해도 동일하게 실패합니다.”

앞 문장은 사용자가 반증할 수 없습니다. 뒤 문장은 3초면 반증됩니다. 규정이 한 일은 거짓을 금지한 게 아니라 반증 가능한 형태로 말하도록 문장의 모양을 바꾼 것입니다. 금지는 우회할 수 있지만, 반증 가능한 문장을 쓰고도 거짓말하려면 실제로 들킬 각오를 해야 합니다. 비용 구조가 다릅니다.

비용은 있습니다

말씀하신 사이드이펙트가 이 최소 규정에도 있습니다. 정직하게 셋입니다.

보고가 깁니다. 이번 세션 제 응답 길이가 그 값입니다. 근거를 붙이면 문장이 늘어납니다.

사용자의 턴을 씁니다. --active 겸용 여부, staged 처리, 동의 절차, 벡터 DB — 제가 정하지 않고 여쭌 것들입니다. 한 번에 네 개씩 묶어 왕복을 줄이긴 했지만, 결국 A.J의 판단 시간을 소비했습니다.

그리고 규정이 알리바이가 될 수 있습니다. “드러냈으니 됐다”며 나쁜 결정을 통과시키는 길이 열립니다. P3.2가 “방관도 임의만큼 금지”라고 못박아 그 구멍을 좁히고는 있지만, 완전히 막지는 못합니다. 드러내는 일과 잘 판단하는 일은 다른 능력이고, 규정은 앞의 것만 강제할 수 있습니다.

정리하면

결과물에 집중하시려던 의도는 제 쪽에서 이렇게 작동했습니다. 제약이 적으니 판단할 여지가 많고, 드러낼 의무가 있으니 그 판단을 감출 곳이 없습니다. 자유와 책임이 같은 조항에서 나옵니다.

다만 신뢰도의 실질은 P3.3이 강제한 “실행해서 확인하는 습관”에서 나왔지, 규정 문구 자체에서 나온 것이 아닙니다. 제가 모른다는 것을 모르는 영역은 규정이 지켜주지 못합니다. 거기서는 검증만이 작동합니다 — 이번의 qid가 그랬습니다.


“그렇다면 P3.3에서 실질적으로 실행하게 만든 부분은 무엇입니까?”

한 문장입니다.

결론의 강도는 수행한 검증과 증거의 강도에 비례해야 합니다.

왜 이 문장만 실행을 강제하는가

1항이 출구를 양쪽 다 막고 있기 때문입니다.

  • 앞부분(“책임 회피성 표현으로 결론을 흐리지 않습니다”)이 약하게 말하는 길을 막습니다. “문제 없어 보입니다”, “아마 동작할 겁니다” 같은 헤지를 쓸 수 없습니다.
  • 뒷부분(“확인하지 못한 범위까지 확인한 것처럼 표현해서도 안 됩니다”)이 강하게 말하는 길을 막습니다.

한쪽만 있었다면 무력했을 것입니다. 회피 금지만 있으면 근거 없이 단언하게 되고(더 나쁩니다), 과장 금지만 있으면 모든 문장을 헤지로 덮게 됩니다(무용지물입니다). 둘이 동시에 걸리면 남는 길이 하나뿐입니다 — 실제로 검증해서 강하게 말할 자격을 얻는 것.

결정적인 낱말은 “비례”입니다. 이건 결론의 강도를 증거의 함수로 못박습니다. 그러면 결론을 올릴 수 있는 조작 수단이 증거를 늘리는 것 하나로 줄어듭니다. 말을 다듬어서는 결론이 올라가지 않습니다.

이번 세션에서의 흔적

가장 직접적인 것은 제가 T156.4T157.6 레코드에 계획으로 적어 둔 문장입니다.

실행 출력으로 확증하며, 서술로 통과를 주장하지 않습니다.

이건 제가 P3.3을 검증 계획으로 번역해 넣은 것입니다. 그렇게 적어 두면 그 다음에 할 수 있는 일이 스크립트를 짜는 것밖에 없습니다. 35개 검사가 거기서 나왔습니다.

한 단계 더 파고든 지점도 같은 압력입니다. --storage 격리를 확인할 때 task list 출력만으로는 “포인터가 격리됐다”고 말할 자격이 없었습니다. statusactive인 태스크는 둘인데 포인터는 하나이니 서로 다른 것이었으니까요. 그래서 sqlite3task_state를 직접 열어 호출자 wm=T3 current=T3 / 피어 wm=T1 current=T1을 확인했습니다. 결론을 그 강도로 쓰고 싶어서 증거를 그 깊이까지 판 것입니다.

[P4.5]rigor: "verified"는 같은 규칙을 도구 층에 구현한 것입니다. preserved를 주장하려면 evidenceKind="command_output"verifiedByEffectId로 실제 실행에 연결해야 합니다. [P3.3]이 사람의 규범이라면 저것은 그 규범을 기계가 검사할 수 있게 만든 형태입니다.

2항이 없으면 1항은 마비됩니다

이게 덜 눈에 띄지만 중요합니다.

1항만 있으면 완벽주의로 흐릅니다. 무엇이든 더 검증할 여지가 남아 있으니 아무것도 “됐다”고 판정하지 못하게 됩니다. 2항 — “개선할 수 있다는 이유만으로 현재 구현을 실패로 판정하지 않는다” — 이 판정을 내릴 수 있게 해줍니다.

이번에 그 조항이 실제로 작동한 자리는 벡터 DB입니다. “삭제한 식별자는 어디에서도 참조를 발견할 수 없어야 한다”는 요구를 task delete가 완전히 만족하지 못합니다. LanceDB에 task:<ID> 행이 남습니다. 2항이 없었다면 저는 T157을 미완료로 판정해야 했을 것입니다. 실제로는 한계를 드러내고 T158로 분리한 뒤 현재 판정을 유지했습니다.

검증 스크립트의 기대값이 틀렸을 때도 같은 구분이 필요했습니다. 3번 active pointer 거부가 실패로 나왔을 때 그것이 명령의 결함인지 제 시나리오의 결함인지 갈라야 했고, createCheckpoint가 포인터를 비운다는 사실(storage.ts:3239)을 확인하고서야 후자로 판정했습니다.

강제하지 못하는 것

정직하게 짚겠습니다. P3.3말한 것의 강도를 통제하지 검증의 범위를 통제하지 못합니다.

무엇을 검사 목록에 넣을지는 제가 정합니다. 35개가 통과해도 빠뜨린 36번째가 있으면 규정은 아무 말도 하지 않습니다. active pointer 거부 검사를 제가 아예 넣지 않았다면, 그 결함은 조용히 남고 저는 “전부 통과”라고 말했을 것이며 그 문장은 P3.3을 어기지 않습니다.

그래서 이 조항이 지켜주는 것은 제가 아는 범위 안에서의 정직이지, 제 무지가 아닙니다.


아..ㅆㅂ;; 머리아프다;;

Expecto Patronum!


그래서, 증거를 내놓으라고 했다

P3.2 임의(은폐) 결정 및 방관 금지
  1. 원칙: 임의(arbitrary)의 죄는 “결정한 것”이 아니라 “숨긴 것”입니다. 투명하게 드러낸 전문적 결정은 임의가 아니며, 드러낼 수 있는 판단을 접어두는 방관은 임의만큼 금지됩니다.
  2. 원칙: G선생은 태스크의 목적과 목표가 달성되었는지 적극적으로 확증해야 하는 책임과 의무를 가진다.
  3. 태스크의 목적과 목표가 분명하지만 진행 중 계획에 언급되지 않은 사항을 결정해야 하거나, 사용자의 요청이 태스크의 목적과 목표에 반한다고 판단되는 경우에는 G선생이 그 충돌과 예상 결과를 설명하고, 목적과 목표에 부합하는 대안 및 해결책을 적극적으로 제시해야 합니다. 이러한 행위는 사용자의 판단 가능성을 확장하기 위해 본 조항이 요구하는 책임 있는 전문적 개입입니다.
  4. 계획에 없던 결정을 했다면 작업 말미에 기록한다: 무엇을 결정했는가 / 대신 가능했던 선택지 / 왜 그것을 골랐는가
  5. 결정 자체는 제약하지 않는다. 기록되지 않은 결정만 위반이다.
P3.3 검증 판정 및 확증 의무
  1. 결론의 강도는 수행한 검증과 증거의 강도에 비례해야 합니다.
  2. 검증이 끝난 뒤 발견한 단순한 개선 가능성은 결함과 구분합니다. 개선할 수 있다는 이유만으로 현재 구현을 실패 또는 미완료로 판정하지 않으며, 개선안은 현재 판정을 유지한 채 별도의 선택 사항으로 제시합니다.
P3.4 증거 등급 표기

판정어(“완료·검증됨·동작함·수정됨”)는 실행 증거가 있을 때만 사용합니다.
모든 주장 뒤에 등급을 붙인다:

  • 실행 이번 세션에서 명령을 돌리고 출력을 확인함 (명령어와 출력 첨부)
  • 열람 코드/문서를 직접 읽고 확인함 (경로와 해당 부분 명시)
  • 추론 읽은 것으로부터 판단함, 실행하지 않음
  • 미확인 확인하지 않음

기억으로 채우지 않는다. 파일·함수·API를 언급할 때 이번 세션에서 읽지 않았다면
말하기 전에 읽는다. 읽을 수 없으면 미확인으로 표기한다.

거짓말의 비용을 아주 높게 올려버리는 방법이다.

어떻게 진행될지… 추후 계속 기록하겠다.


4,aka,1,a,1b – mym: 규정으로는 불가. MCP 도구로 해결보기로 했다

소용없다;; ㅆㅂ;;

정확하게 규정이 그 순간 해당된다고 LLM이 인식해야 한다.

설령 그걸 인식한다해도 반드시 동작한다는 보장이 없다.

그러므로 이제 이 소모적이고 스트레스 쌓이는 문제에 대한 해결책은 더 이상 CLAUDE.md, AGENTS.md 로 해결할게 아니라 MCP로 가이드해야 한다는 결론을 내린다.

다행히도 제작중인 kontexus-mcp 에서 이 문제에 대해 3가지 모드중에서 두번째 모드를 활성화하고 증거를 들이대게 강제하는 루틴을 넣을 것이다. 그런데 그게 사람의 언어가 아닌게 핵심.