Files
FESADev/phases/nonlinear-static-newton-raphson/step7.md
T

6.2 KiB

Step 7: newton-iteration-log-writer

읽어야 할 파일

  • AGENTS.md
  • docs/ARCHITECTURE.md
  • docs/nonlinear-static-newton-raphson/io.md
  • docs/nonlinear-static-newton-raphson/formulation.md
  • docs/nonlinear-static-newton-raphson/implementation-plan.md
  • Step 0 files: include/fesa/app/output_paths.h, src/fesa/app/output_paths.cpp, include/fesa/analysis/analysis.h
  • Step 5 files: include/fesa/analysis/nonlinear_static_control.h

이전 Step 전제

Step 0 gives app-owned log path and lease lifetime. Step 5 defines convergence-channel data that log records consume.

소유 파일

  • Create: include/fesa/analysis/newton_iteration_log.h
  • Create: src/fesa/analysis/newton_iteration_log.cpp
  • Create: tests/unit/analysis/newton_iteration_log_test.cpp
  • Modify: src/fesa/CMakeLists.txt
  • Modify: tests/CMakeLists.txt

인터페이스

namespace fesa {

enum class NewtonIterationStage {
  kEntered,
  kKinematicsEvaluated,
  kInternalAssembled,
  kExternalAssembled,
  kSolvedCorrection,
  kConvergenceEvaluated,
  kAccepted,
  kFailed
};

struct NewtonIterationFailure {
  bool present;
  NewtonIterationStage stage;
  std::string diagnostic_code;
  std::string reason;
};

struct NewtonIterationLogRecord {
  std::string step_name;
  std::uint32_t increment_index;
  double load_factor;
  std::uint32_t iteration;
  NewtonIterationStage last_completed_stage;
  NewtonIterationFailure failure;
  std::string transition;
  std::string outcome;
  std::string diagnostic_code;
  NewtonChannelDecision force_residual;
  NewtonChannelDecision moment_residual;
  NewtonChannelDecision translation_correction;
  NewtonChannelDecision rotation_correction;
  bool combined_passed;
};

class NewtonIterationLogWriter {
 public:
  Status Open(const std::filesystem::path& log_path);
  Status Write(const NewtonIterationLogRecord& record);
  Status Flush();
  Status Close();
};

}  // namespace fesa

The serializer, not callers, owns the exact 39 labels and fixed order from io.md. For evaluated convergence channels it serializes only relative or zero-scale branch labels from NewtonConvergenceBranch. For unevaluated typed fields it writes not-evaluated(reason) using NewtonIterationFailure::reason. Callers cannot inject arbitrary fields.

RED

Add tests first.

  • NSNR-LOG-001: a complete Newton iteration writes exactly one LF-terminated line.
  • NSNR-LOG-002: line is UTF-8 without BOM, no header, no trailer.
  • NSNR-LOG-003: line has exactly 39 TAB-separated label=value fields in approved order.
  • NSNR-LOG-004: finite numeric values round-trip without locale dependence.
  • NSNR-LOG-005: each convergence channel serializes identity, numerator_norm, denominator_scale, branch, threshold, threshold_unit, and pass from NewtonChannelDecision.
  • NSNR-LOG-006: evaluated empty free-channel decisions serialize numerator_norm=0, denominator_scale=0, threshold 1.0e-3, the channel-specific zero-scale threshold_unit, and branch zero-scale; no other branch label appears.
  • NSNR-LOG-007: combined pass, transition, outcome, failure stage, and diagnostic code are serialized from explicit record fields.
  • NSNR-LOG-008: early failure fields after the failed stage use not-evaluated(reason).
  • NSNR-LOG-009: embedded tab, LF, CR, and backslash are escaped deterministically.
  • NSNR-LOG-010: write/flush/close failure returns log-output-failure and prevents success classification.
  • NSNR-LOG-011: non-Newton controlled failure path can leave a zero-byte log owned by app lifecycle.

USER-DECISION-003 option-1 revision addendum

Step 7의 completed status, summary, timestamps와 commits는 보존한다. Executor-selected Step 11에서 tests/unit/analysis/newton_iteration_log_test.cpp에 다음 RED assertion을 추가한다.

  • NSNR-LOG-012: synthetic NewtonChannelDecision이 아니라 EvaluateNewtonConvergence가 만든 residual decisions를 record에 넣는다. Exact-zero matching external channel은 denominator exact 0, branch zero-scale, threshold 1.0e-3, force 또는 force-length unit으로 직렬화하고, nonzero matching external channel은 retained denominator, branch relative, threshold 1.0e-2, unit 1로 직렬화한다. 같은 line이 기존 39 labels/order, TAB separation, LF termination을 그대로 유지해야 하므로 기존 selector에서는 RED가 된다.

Run:

cmake --build --preset windows-msvc-ninja-debug
ctest --preset windows-msvc-ninja-debug -R "NewtonIterationLog" --output-on-failure

Expected: new tests fail. Unexpected pass stops.

GREEN

Implement a small log writer with explicit open/write/flush/close state, serializer-owned 39-field order, deterministic escaping, finite numeric formatting, relative/zero-scale convergence branch mapping, typed not-evaluated(reason) substitution, and structured Status failures. USER-DECISION-003는 evaluator-produced decision semantics만 바꾸므로 log writer production 또는 nsnr-log-v1 schema 변경은 예상하지 않는다.

VERIFY

cmake --preset windows-msvc-ninja-debug
cmake --build --preset windows-msvc-ninja-debug
ctest --preset windows-msvc-ninja-debug -R "NewtonIterationLog" --output-on-failure
ctest --preset windows-msvc-ninja-debug --show-only=json-v1
ctest --preset windows-msvc-ninja-debug --output-on-failure

Use the ignored .harness/config.json preset contract. The Harness process must inherit VsDevCmd x64 and FESA_GTEST_SOURCE_DIR, MKL_DIR, TBB_DIR, and HDF5_DIR from its parent launch environment.

상태 기록

Update only Step 7 status and one-line payload. Executor owns timestamps, commits, retry, and advancement.

금지사항

  • Do not duplicate per-iteration log lines to stderr. 이유: approved log is file-only.
  • Do not accept arbitrary caller-provided field vectors. 이유: io.md requires an exact fixed schema and order.
  • Do not write HDF5 trial history. 이유: log is diagnostic and HDF5 stores accepted frames only.
  • Do not continue after log write/flush/close failure. 이유: log failure blocks result commit.
  • Do not add, remove, rename, reorder, or re-delimit any nsnr-log-v1 field. 이유: option 1 changes only residual decision values, not the approved 39-field external log contract.