onto-mcp 0.3.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.onto/processes/reconstruct/actionable-ontology-seed-recomposition-design.md +447 -0
- package/.onto/processes/reconstruct/foundry-style-ontology-seed-contract.md +934 -0
- package/.onto/processes/reconstruct/reconstruct-boundary-contract.md +303 -725
- package/.onto/processes/reconstruct/reconstruct-contract-registry.yaml +1645 -0
- package/.onto/processes/reconstruct/reconstruct-execution-ux-contract.md +26 -22
- package/.onto/processes/reconstruct/source-profile-contract.md +49 -23
- package/.onto/processes/reconstruct/source-profiles/code.md +6 -3
- package/.onto/processes/reconstruct/source-profiles/database.md +5 -2
- package/.onto/processes/reconstruct/source-profiles/document.md +5 -2
- package/.onto/processes/reconstruct/source-profiles/spreadsheet.md +5 -4
- package/.onto/processes/review/review-execution-ux-contract.md +40 -0
- package/.onto/processes/shared/pipeline-execution-ledger-contract.md +26 -10
- package/.onto/processes/shared/target-material-kind-contract.md +29 -16
- package/AGENTS.md +6 -4
- package/README.md +135 -76
- package/dist/cli.js +8 -8
- package/dist/core-api/reconstruct-api.js +117 -31
- package/dist/core-api/review-api.js +47 -0
- package/dist/core-runtime/cli/codex-review-unit-executor.js +39 -2
- package/dist/core-runtime/cli/complete-review-session.js +2 -2
- package/dist/core-runtime/cli/mock-review-unit-executor.js +1 -1
- package/dist/core-runtime/cli/review-invoke.js +9 -9
- package/dist/core-runtime/cli/run-review-prompt-execution.js +39 -5
- package/dist/core-runtime/cli/spawn-watcher.js +266 -47
- package/dist/core-runtime/cli/start-review-session.js +3 -3
- package/dist/core-runtime/llm/llm-caller.js +11 -0
- package/dist/core-runtime/llm/llm-tool-loop.js +2 -0
- package/dist/core-runtime/observability/runtime-stream-observation.js +118 -0
- package/dist/core-runtime/onboard/cli-host.js +149 -0
- package/dist/core-runtime/onboard/host-target.js +22 -0
- package/dist/core-runtime/onboard/json-config-host.js +122 -0
- package/dist/core-runtime/onboard/path-scan.js +26 -0
- package/dist/core-runtime/onboard/prompt.js +51 -0
- package/dist/core-runtime/onboard/register.js +207 -0
- package/dist/core-runtime/onboard/types.js +27 -0
- package/dist/core-runtime/reconstruct/actionable-seed-validation.js +1777 -0
- package/dist/core-runtime/reconstruct/artifact-types.js +10 -4
- package/dist/core-runtime/reconstruct/contract-registry.js +623 -0
- package/dist/core-runtime/reconstruct/domain-id.js +10 -0
- package/dist/core-runtime/reconstruct/governing-snapshot.js +716 -0
- package/dist/core-runtime/reconstruct/material-profile-validation.js +191 -0
- package/dist/core-runtime/reconstruct/materialize-preparation.js +49 -11
- package/dist/core-runtime/reconstruct/pipeline-execution-ledger.js +269 -79
- package/dist/core-runtime/reconstruct/post-seed-validation.js +1194 -51
- package/dist/core-runtime/reconstruct/record.js +104 -20
- package/dist/core-runtime/reconstruct/run.js +2107 -413
- package/dist/core-runtime/reconstruct/seed-claim-projections.js +268 -0
- package/dist/core-runtime/reconstruct/source-profiles.js +93 -4
- package/dist/core-runtime/reconstruct/terminal-validation.js +807 -0
- package/dist/core-runtime/review/review-invocation-runner.js +4 -4
- package/dist/mcp/server.js +110 -38
- package/dist/mcp/tool-schemas.js +20 -6
- package/package.json +8 -17
- package/scripts/onto-review-watch.sh +486 -0
- package/scripts/onto-runtime-watch.sh +122 -0
- package/scripts/postinstall-hint.js +22 -0
- package/.onto/processes/reconstruct/top-level-concept-discovery-contract.md +0 -387
- package/dist/core-runtime/cli/bootstrap-review-binding.js +0 -186
- package/dist/core-runtime/cli/codex-nested-dispatch.test.js +0 -390
- package/dist/core-runtime/cli/codex-nested-teamlead-executor.test.js +0 -335
- package/dist/core-runtime/cli/coordinator-helpers.js +0 -583
- package/dist/core-runtime/cli/coordinator-state-machine-deliberation.test.js +0 -167
- package/dist/core-runtime/cli/coordinator-state-machine.js +0 -794
- package/dist/core-runtime/cli/e2e-codex-multi-agent-fixes.test.js +0 -615
- package/dist/core-runtime/cli/e2e-start-review-session.test.js +0 -312
- package/dist/core-runtime/cli/health.js +0 -44
- package/dist/core-runtime/cli/inline-http-review-unit-executor.test.js +0 -567
- package/dist/core-runtime/cli/materialize-review-execution-preparation.js +0 -104
- package/dist/core-runtime/cli/migrate-session-roots.js +0 -118
- package/dist/core-runtime/cli/repo-layout-migration-replace.smoke.test.js +0 -106
- package/dist/core-runtime/cli/review-invoke-auto-resolution.test.js +0 -268
- package/dist/core-runtime/cli/review-invoke-coordinator-topology.test.js +0 -136
- package/dist/core-runtime/cli/review-invoke-resolver-caching.test.js +0 -201
- package/dist/core-runtime/cli/review-invoke-topology-dispatch.test.js +0 -192
- package/dist/core-runtime/cli/session-root-guard.js +0 -168
- package/dist/core-runtime/cli/spawn-watcher.test.js +0 -457
- package/dist/core-runtime/cli/strip-wrapping-code-fence.test.js +0 -79
- package/dist/core-runtime/cli/teamcreate-lens-deliberation-executor.js +0 -412
- package/dist/core-runtime/cli/teamcreate-lens-deliberation-executor.test.js +0 -351
- package/dist/core-runtime/cli/topology-executor-mapping.js +0 -139
- package/dist/core-runtime/cli/topology-executor-mapping.test.js +0 -173
- package/dist/core-runtime/cli/write-review-interpretation.js +0 -81
- package/dist/core-runtime/config/onto-config-cli.js +0 -278
- package/dist/core-runtime/config/onto-config-key-path.js +0 -288
- package/dist/core-runtime/config/onto-config-key-path.test.js +0 -195
- package/dist/core-runtime/config/onto-config-preview.js +0 -108
- package/dist/core-runtime/config/onto-config-preview.test.js +0 -132
- package/dist/core-runtime/discovery/config-chain.js +0 -118
- package/dist/core-runtime/discovery/config-chain.test.js +0 -103
- package/dist/core-runtime/discovery/config-profile.js +0 -199
- package/dist/core-runtime/discovery/config-profile.test.js +0 -233
- package/dist/core-runtime/discovery/host-detection.test.js +0 -186
- package/dist/core-runtime/discovery/installation-paths.test.js +0 -65
- package/dist/core-runtime/discovery/lens-registry.test.js +0 -81
- package/dist/core-runtime/discovery/path-normalization.test.js +0 -22
- package/dist/core-runtime/discovery/plugin-path.js +0 -72
- package/dist/core-runtime/discovery/plugin-path.test.js +0 -95
- package/dist/core-runtime/evolve/adapters/code-product/compile/compile-defense.js +0 -344
- package/dist/core-runtime/evolve/adapters/code-product/compile/compile-defense.test.js +0 -915
- package/dist/core-runtime/evolve/adapters/code-product/compile/compile.js +0 -564
- package/dist/core-runtime/evolve/adapters/code-product/compile/compile.test.js +0 -708
- package/dist/core-runtime/evolve/adapters/code-product/parsers/brief-parser.js +0 -165
- package/dist/core-runtime/evolve/adapters/code-product/parsers/brief-parser.test.js +0 -227
- package/dist/core-runtime/evolve/adapters/code-product/validators/validate.js +0 -59
- package/dist/core-runtime/evolve/adapters/code-product/validators/validate.test.js +0 -205
- package/dist/core-runtime/evolve/adapters/methodology/adapter.js +0 -16
- package/dist/core-runtime/evolve/adapters/methodology/adapter.test.js +0 -9
- package/dist/core-runtime/evolve/adapters/methodology/perspectives/authority-consistency.js +0 -298
- package/dist/core-runtime/evolve/adapters/methodology/perspectives/authority-consistency.test.js +0 -70
- package/dist/core-runtime/evolve/adapters/methodology/scope-types/process.js +0 -46
- package/dist/core-runtime/evolve/adapters/methodology/scope-types/process.test.js +0 -73
- package/dist/core-runtime/evolve/adapters/registry.js +0 -47
- package/dist/core-runtime/evolve/adapters/registry.test.js +0 -67
- package/dist/core-runtime/evolve/cli.js +0 -256
- package/dist/core-runtime/evolve/commands/align.js +0 -194
- package/dist/core-runtime/evolve/commands/align.test.js +0 -82
- package/dist/core-runtime/evolve/commands/apply.js +0 -161
- package/dist/core-runtime/evolve/commands/apply.test.js +0 -138
- package/dist/core-runtime/evolve/commands/close.js +0 -39
- package/dist/core-runtime/evolve/commands/close.test.js +0 -99
- package/dist/core-runtime/evolve/commands/defer.js +0 -40
- package/dist/core-runtime/evolve/commands/defer.test.js +0 -134
- package/dist/core-runtime/evolve/commands/draft.js +0 -323
- package/dist/core-runtime/evolve/commands/draft.test.js +0 -178
- package/dist/core-runtime/evolve/commands/e2e-evolve-full-cycle.test.js +0 -208
- package/dist/core-runtime/evolve/commands/error-messages.js +0 -125
- package/dist/core-runtime/evolve/commands/error-messages.test.js +0 -167
- package/dist/core-runtime/evolve/commands/propose-align.js +0 -222
- package/dist/core-runtime/evolve/commands/propose-align.test.js +0 -136
- package/dist/core-runtime/evolve/commands/reconstruct.js +0 -330
- package/dist/core-runtime/evolve/commands/reconstruct.test.js +0 -278
- package/dist/core-runtime/evolve/commands/shared.js +0 -22
- package/dist/core-runtime/evolve/commands/stale-check.js +0 -103
- package/dist/core-runtime/evolve/commands/stale-check.test.js +0 -84
- package/dist/core-runtime/evolve/commands/start.js +0 -887
- package/dist/core-runtime/evolve/commands/start.test.js +0 -396
- package/dist/core-runtime/evolve/config/project-config.js +0 -99
- package/dist/core-runtime/evolve/config/project-config.test.js +0 -170
- package/dist/core-runtime/evolve/renderers/align-packet.js +0 -280
- package/dist/core-runtime/evolve/renderers/align-packet.test.js +0 -332
- package/dist/core-runtime/evolve/renderers/draft-packet.js +0 -303
- package/dist/core-runtime/evolve/renderers/draft-packet.test.js +0 -377
- package/dist/core-runtime/evolve/renderers/format.js +0 -5
- package/dist/core-runtime/evolve/renderers/scope-md.js +0 -237
- package/dist/core-runtime/evolve/renderers/scope-md.test.js +0 -306
- package/dist/core-runtime/govern/cli.js +0 -369
- package/dist/core-runtime/govern/cli.test.js +0 -314
- package/dist/core-runtime/govern/drift-engine.js +0 -103
- package/dist/core-runtime/govern/drift-engine.test.js +0 -319
- package/dist/core-runtime/govern/promote-principle.js +0 -206
- package/dist/core-runtime/govern/promote-principle.test.js +0 -368
- package/dist/core-runtime/govern/queue.js +0 -81
- package/dist/core-runtime/govern/types.js +0 -16
- package/dist/core-runtime/install/cli.js +0 -530
- package/dist/core-runtime/install/detect.js +0 -128
- package/dist/core-runtime/install/detect.test.js +0 -155
- package/dist/core-runtime/install/gitignore-update.js +0 -74
- package/dist/core-runtime/install/gitignore-update.test.js +0 -64
- package/dist/core-runtime/install/install-integration.test.js +0 -373
- package/dist/core-runtime/install/prompts.js +0 -389
- package/dist/core-runtime/install/prompts.test.js +0 -293
- package/dist/core-runtime/install/types.js +0 -26
- package/dist/core-runtime/install/validation.js +0 -295
- package/dist/core-runtime/install/validation.test.js +0 -313
- package/dist/core-runtime/install/writer.js +0 -254
- package/dist/core-runtime/install/writer.test.js +0 -218
- package/dist/core-runtime/learning/extractor.js +0 -461
- package/dist/core-runtime/learning/feedback.js +0 -179
- package/dist/core-runtime/learning/health-report.js +0 -165
- package/dist/core-runtime/learning/health-report.test.js +0 -169
- package/dist/core-runtime/learning/loader.js +0 -388
- package/dist/core-runtime/learning/loader.test.js +0 -102
- package/dist/core-runtime/learning/promote/apply-state.js +0 -240
- package/dist/core-runtime/learning/promote/audit-obligation.js +0 -195
- package/dist/core-runtime/learning/promote/collector.js +0 -432
- package/dist/core-runtime/learning/promote/degraded-state.js +0 -125
- package/dist/core-runtime/learning/promote/domain-doc-proposer.js +0 -166
- package/dist/core-runtime/learning/promote/e2e-promote.test.js +0 -6385
- package/dist/core-runtime/learning/promote/health-snapshot.js +0 -150
- package/dist/core-runtime/learning/promote/insight-reclassifier.js +0 -544
- package/dist/core-runtime/learning/promote/judgment-auditor.js +0 -517
- package/dist/core-runtime/learning/promote/panel-reviewer.js +0 -1158
- package/dist/core-runtime/learning/promote/promote-executor.js +0 -1675
- package/dist/core-runtime/learning/promote/promoter.js +0 -307
- package/dist/core-runtime/learning/promote/retirement.js +0 -122
- package/dist/core-runtime/learning/promote/types.js +0 -23
- package/dist/core-runtime/learning/prompt-sections.js +0 -51
- package/dist/core-runtime/learning/shared/artifact-registry-init.js +0 -45
- package/dist/core-runtime/learning/shared/artifact-registry.js +0 -254
- package/dist/core-runtime/learning/shared/audit-obligation-kernel.js +0 -73
- package/dist/core-runtime/learning/shared/audit-state.js +0 -99
- package/dist/core-runtime/learning/shared/duplicate-check.js +0 -28
- package/dist/core-runtime/learning/shared/llm-caller.js +0 -831
- package/dist/core-runtime/learning/shared/llm-caller.test.js +0 -601
- package/dist/core-runtime/learning/shared/llm-tool-loop.js +0 -393
- package/dist/core-runtime/learning/shared/mode.js +0 -25
- package/dist/core-runtime/learning/shared/paths.js +0 -84
- package/dist/core-runtime/learning/shared/paths.test.js +0 -79
- package/dist/core-runtime/learning/shared/patterns.js +0 -37
- package/dist/core-runtime/learning/shared/recoverability.js +0 -355
- package/dist/core-runtime/learning/shared/recovery-context.js +0 -374
- package/dist/core-runtime/learning/shared/scope.js +0 -1
- package/dist/core-runtime/learning/shared/semantic-classifier.js +0 -94
- package/dist/core-runtime/learning/shared/specs/apply-execution-state-spec.js +0 -42
- package/dist/core-runtime/learning/shared/specs/audit-state-spec.js +0 -37
- package/dist/core-runtime/learning/shared/specs/backup-metadata-spec.js +0 -39
- package/dist/core-runtime/learning/shared/specs/emergency-log-spec.js +0 -41
- package/dist/core-runtime/learning/shared/specs/layout-version-spec.js +0 -38
- package/dist/core-runtime/learning/shared/specs/promote-decisions-spec.js +0 -43
- package/dist/core-runtime/learning/shared/specs/promote-report-spec.js +0 -113
- package/dist/core-runtime/learning/shared/specs/prune-log-spec.js +0 -36
- package/dist/core-runtime/learning/shared/specs/recovery-resolution-spec.js +0 -48
- package/dist/core-runtime/learning/shared/specs/restore-manifest-spec.js +0 -43
- package/dist/core-runtime/learning/shared/specs/spec-helpers.js +0 -64
- package/dist/core-runtime/learning/usage-tracker.js +0 -190
- package/dist/core-runtime/learning/usage-tracker.test.js +0 -176
- package/dist/core-runtime/onboard/detect-review-axes.js +0 -122
- package/dist/core-runtime/onboard/detect-review-axes.test.js +0 -127
- package/dist/core-runtime/onboard/write-review-block.js +0 -188
- package/dist/core-runtime/onboard/write-review-block.test.js +0 -240
- package/dist/core-runtime/readers/brownfield-builder.js +0 -150
- package/dist/core-runtime/readers/brownfield-builder.test.js +0 -136
- package/dist/core-runtime/readers/code-chunk-collector.js +0 -53
- package/dist/core-runtime/readers/code-chunk-collector.test.js +0 -136
- package/dist/core-runtime/readers/file-utils.js +0 -240
- package/dist/core-runtime/readers/file-utils.test.js +0 -146
- package/dist/core-runtime/readers/lexicon-citation-check.js +0 -93
- package/dist/core-runtime/readers/lexicon-citation-check.test.js +0 -77
- package/dist/core-runtime/readers/mcp-figma.js +0 -30
- package/dist/core-runtime/readers/mcp-figma.test.js +0 -82
- package/dist/core-runtime/readers/mcp-generic.js +0 -31
- package/dist/core-runtime/readers/mcp-generic.test.js +0 -76
- package/dist/core-runtime/readers/ontology-index.js +0 -148
- package/dist/core-runtime/readers/ontology-index.test.js +0 -245
- package/dist/core-runtime/readers/ontology-query.js +0 -168
- package/dist/core-runtime/readers/ontology-query.test.js +0 -311
- package/dist/core-runtime/readers/ontology-resolve.js +0 -48
- package/dist/core-runtime/readers/ontology-resolve.test.js +0 -48
- package/dist/core-runtime/readers/patterns/index.js +0 -7
- package/dist/core-runtime/readers/review-log.js +0 -213
- package/dist/core-runtime/readers/review-log.test.js +0 -313
- package/dist/core-runtime/readers/scan-local.js +0 -102
- package/dist/core-runtime/readers/scan-local.test.js +0 -102
- package/dist/core-runtime/readers/scan-tarball.js +0 -121
- package/dist/core-runtime/readers/scan-tarball.test.js +0 -283
- package/dist/core-runtime/readers/scan-vault.js +0 -34
- package/dist/core-runtime/readers/scan-vault.test.js +0 -81
- package/dist/core-runtime/readers/types.js +0 -42
- package/dist/core-runtime/readers/types.test.js +0 -94
- package/dist/core-runtime/readers/viewpoint-collectors.js +0 -229
- package/dist/core-runtime/reconstruct/seed-candidate-validation.js +0 -385
- package/dist/core-runtime/review/citation-audit.test.js +0 -165
- package/dist/core-runtime/review/execution-plan-resolver.js +0 -247
- package/dist/core-runtime/review/execution-plan-resolver.test.js +0 -243
- package/dist/core-runtime/review/execution-topology-resolver-axis-first.test.js +0 -246
- package/dist/core-runtime/review/execution-topology-resolver.js +0 -401
- package/dist/core-runtime/review/execution-topology-resolver.test.js +0 -315
- package/dist/core-runtime/review/inline-context-embedder.test.js +0 -154
- package/dist/core-runtime/review/legacy-mode-policy.js +0 -88
- package/dist/core-runtime/review/materializers-effort-persist.test.js +0 -79
- package/dist/core-runtime/review/ontology-path-classifier.js +0 -179
- package/dist/core-runtime/review/ontology-path-classifier.test.js +0 -216
- package/dist/core-runtime/review/packet-boundary-policy.test.js +0 -107
- package/dist/core-runtime/review/participating-lens-paths.test.js +0 -73
- package/dist/core-runtime/review/review-config-legacy-translate.js +0 -244
- package/dist/core-runtime/review/review-config-legacy-translate.test.js +0 -161
- package/dist/core-runtime/review/review-config-validator.js +0 -289
- package/dist/core-runtime/review/review-config-validator.test.js +0 -236
- package/dist/core-runtime/review/shape-pipeline-audit.test.js +0 -311
- package/dist/core-runtime/review/shape-to-topology-id.js +0 -117
- package/dist/core-runtime/review/shape-to-topology-id.test.js +0 -132
- package/dist/core-runtime/review/topology-shape-derivation.js +0 -155
- package/dist/core-runtime/review/topology-shape-derivation.test.js +0 -195
- package/dist/core-runtime/scope-runtime/constants.js +0 -12
- package/dist/core-runtime/scope-runtime/constraint-pool.js +0 -166
- package/dist/core-runtime/scope-runtime/constraint-pool.test.js +0 -674
- package/dist/core-runtime/scope-runtime/domain-validation-log.js +0 -135
- package/dist/core-runtime/scope-runtime/domain-validation-log.test.js +0 -156
- package/dist/core-runtime/scope-runtime/eval-persistence.js +0 -65
- package/dist/core-runtime/scope-runtime/eval-persistence.test.js +0 -84
- package/dist/core-runtime/scope-runtime/event-pipeline.js +0 -64
- package/dist/core-runtime/scope-runtime/event-pipeline.test.js +0 -450
- package/dist/core-runtime/scope-runtime/event-store.js +0 -39
- package/dist/core-runtime/scope-runtime/event-store.test.js +0 -95
- package/dist/core-runtime/scope-runtime/gate-guard.js +0 -348
- package/dist/core-runtime/scope-runtime/gate-guard.test.js +0 -1047
- package/dist/core-runtime/scope-runtime/hash.js +0 -4
- package/dist/core-runtime/scope-runtime/hash.test.js +0 -33
- package/dist/core-runtime/scope-runtime/id.js +0 -4
- package/dist/core-runtime/scope-runtime/id.test.js +0 -17
- package/dist/core-runtime/scope-runtime/reducer.js +0 -297
- package/dist/core-runtime/scope-runtime/reducer.test.js +0 -759
- package/dist/core-runtime/scope-runtime/scope-manager.js +0 -161
- package/dist/core-runtime/scope-runtime/state-machine.js +0 -309
- package/dist/core-runtime/scope-runtime/state-machine.test.js +0 -704
- package/dist/core-runtime/scope-runtime/types.js +0 -116
- package/dist/core-runtime/scope-runtime/types.test.js +0 -69
- package/dist/core-runtime/translate/render-for-user.js +0 -169
- package/dist/core-runtime/translate/render-for-user.test.js +0 -122
- package/dist/providers/capability-contract.js +0 -1
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Brief parser — extracts structured information from a brief.md file.
|
|
3
|
-
*
|
|
4
|
-
* 1. What it is: brief.md 파일의 텍스트 내용을 읽어, 각 섹션별 텍스트와
|
|
5
|
-
* 추가 소스 목록을 구조화된 객체로 변환하는 순수 함수입니다.
|
|
6
|
-
* 2. Why it exists: Path B (brief 작성 완료 후 실행)에서 brief.md의 필수
|
|
7
|
-
* 항목이 채워져 있는지 검증하고, 소스 정보를 추출해야 합니다.
|
|
8
|
-
* 이 파서가 없으면 brief.md의 내용을 프로그램이 해석할 수 없습니다.
|
|
9
|
-
* 3. How it relates: executeStart()의 Path B에서 호출됩니다.
|
|
10
|
-
* 추출된 additionalSources는 config/project-config.ts의 resolveSources()에
|
|
11
|
-
* 전달되어 3-way 소스 병합에 참여합니다.
|
|
12
|
-
*/
|
|
13
|
-
// ─── Section extraction ───
|
|
14
|
-
/**
|
|
15
|
-
* Extract the content between an h2 heading and the next h2 heading (or EOF).
|
|
16
|
-
* Returns the trimmed content with HTML comments removed.
|
|
17
|
-
*/
|
|
18
|
-
function extractSection(content, sectionName) {
|
|
19
|
-
// Match "## sectionName" possibly followed by "(필수)" or other suffixes
|
|
20
|
-
const pattern = new RegExp(`^## ${escapeRegex(sectionName)}[^\\n]*\\n`, "m");
|
|
21
|
-
const match = pattern.exec(content);
|
|
22
|
-
if (!match)
|
|
23
|
-
return "";
|
|
24
|
-
const startIndex = match.index + match[0].length;
|
|
25
|
-
// Find the next h2 heading
|
|
26
|
-
const nextH2 = /^## /m;
|
|
27
|
-
const rest = content.slice(startIndex);
|
|
28
|
-
const nextMatch = nextH2.exec(rest);
|
|
29
|
-
const sectionContent = nextMatch ? rest.slice(0, nextMatch.index) : rest;
|
|
30
|
-
return stripComments(sectionContent).trim();
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Remove HTML comments from text.
|
|
34
|
-
*/
|
|
35
|
-
function stripComments(text) {
|
|
36
|
-
return text.replace(/<!--[\s\S]*?-->/g, "").trim();
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Check whether a section has meaningful (non-empty, non-comment) content.
|
|
40
|
-
*/
|
|
41
|
-
function isSectionFilled(content) {
|
|
42
|
-
const stripped = stripComments(content);
|
|
43
|
-
// Check if there's at least 1 non-empty line
|
|
44
|
-
return stripped.split("\n").some((line) => line.trim().length > 0);
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Escape special regex characters in a string.
|
|
48
|
-
*/
|
|
49
|
-
function escapeRegex(str) {
|
|
50
|
-
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
51
|
-
}
|
|
52
|
-
// ─── Additional source parsing ───
|
|
53
|
-
/**
|
|
54
|
-
* Parse additional sources from the "추가 소스" subsection.
|
|
55
|
-
*
|
|
56
|
-
* Matches checklist items like:
|
|
57
|
-
* - [ ] API 서버 소스 (add-dir: /path/to/api)
|
|
58
|
-
* - [x] 디자인 파일 (figma-mcp: abc123)
|
|
59
|
-
*
|
|
60
|
-
* Ignores placeholder items containing "여기에 추가".
|
|
61
|
-
*/
|
|
62
|
-
function parseAdditionalSources(content) {
|
|
63
|
-
// Find the "### 추가 소스" section
|
|
64
|
-
const sectionPattern = /^### 추가 소스[^\n]*\n/m;
|
|
65
|
-
const sectionMatch = sectionPattern.exec(content);
|
|
66
|
-
if (!sectionMatch)
|
|
67
|
-
return [];
|
|
68
|
-
const startIndex = sectionMatch.index + sectionMatch[0].length;
|
|
69
|
-
// Find the next heading (## or ###) or end
|
|
70
|
-
const rest = content.slice(startIndex);
|
|
71
|
-
const nextHeading = /^#{2,3} /m;
|
|
72
|
-
const nextMatch = nextHeading.exec(rest);
|
|
73
|
-
const sectionContent = nextMatch ? rest.slice(0, nextMatch.index) : rest;
|
|
74
|
-
const sources = [];
|
|
75
|
-
// Match checklist items: - [ ] or - [x] followed by description (type: identifier)
|
|
76
|
-
const itemPattern = /^- \[[ x]\] (.+?) \((\S+?):\s*(.+?)\)\s*$/gm;
|
|
77
|
-
let itemMatch;
|
|
78
|
-
while ((itemMatch = itemPattern.exec(sectionContent)) !== null) {
|
|
79
|
-
const description = itemMatch[1];
|
|
80
|
-
const type = itemMatch[2];
|
|
81
|
-
const identifier = itemMatch[3];
|
|
82
|
-
// Ignore placeholder items
|
|
83
|
-
if (description.includes("여기에 추가"))
|
|
84
|
-
continue;
|
|
85
|
-
const entry = buildSourceEntry(type, identifier, description);
|
|
86
|
-
if (entry) {
|
|
87
|
-
sources.push(entry);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return sources;
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Build a SourceEntry from parsed type/identifier/description.
|
|
94
|
-
*/
|
|
95
|
-
function buildSourceEntry(type, identifier, description) {
|
|
96
|
-
switch (type) {
|
|
97
|
-
case "add-dir":
|
|
98
|
-
return { type: "add-dir", path: identifier, description };
|
|
99
|
-
case "github-tarball":
|
|
100
|
-
return { type: "github-tarball", url: identifier, description };
|
|
101
|
-
case "figma-mcp":
|
|
102
|
-
return { type: "figma-mcp", file_key: identifier, description };
|
|
103
|
-
case "obsidian-vault":
|
|
104
|
-
return { type: "obsidian-vault", path: identifier, description };
|
|
105
|
-
case "mcp":
|
|
106
|
-
return { type: "mcp", provider: identifier, description };
|
|
107
|
-
default:
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
// ─── Main parser ───
|
|
112
|
-
/**
|
|
113
|
-
* Parse a brief.md file content into a structured ParsedBrief.
|
|
114
|
-
*
|
|
115
|
-
* Section extraction rules:
|
|
116
|
-
* - Each section starts with `## {title}` (h2 heading)
|
|
117
|
-
* - Content is everything between the heading and the next h2 heading (or EOF)
|
|
118
|
-
* - HTML comments are ignored
|
|
119
|
-
* - A section is "filled" if it has at least 1 non-empty, non-comment line
|
|
120
|
-
* - Required sections: "변경 목적", "대상 사용자", "기대 결과"
|
|
121
|
-
*/
|
|
122
|
-
export function parseBrief(briefContent) {
|
|
123
|
-
const purpose = extractSection(briefContent, "변경 목적");
|
|
124
|
-
const targetUsers = extractSection(briefContent, "대상 사용자");
|
|
125
|
-
const expectedResult = extractSection(briefContent, "기대 결과");
|
|
126
|
-
const includeScope = extractSection(briefContent, "포함 범위") || undefined;
|
|
127
|
-
const excludeScope = extractSection(briefContent, "제외 범위") || undefined;
|
|
128
|
-
const constraints = extractSection(briefContent, "제약 및 참고사항") || undefined;
|
|
129
|
-
// Validation: check required fields
|
|
130
|
-
const requiredFields = [
|
|
131
|
-
["변경 목적", purpose],
|
|
132
|
-
["대상 사용자", targetUsers],
|
|
133
|
-
["기대 결과", expectedResult],
|
|
134
|
-
];
|
|
135
|
-
const missingFields = [];
|
|
136
|
-
for (const [name, value] of requiredFields) {
|
|
137
|
-
if (!isSectionFilled(value)) {
|
|
138
|
-
missingFields.push(name);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
// Title: first non-empty line from purpose section
|
|
142
|
-
const title = purpose
|
|
143
|
-
.split("\n")
|
|
144
|
-
.map((l) => l.trim())
|
|
145
|
-
.find((l) => l.length > 0) ?? "";
|
|
146
|
-
// Description: purpose + expectedResult combined
|
|
147
|
-
const description = [purpose, expectedResult].filter(Boolean).join("\n\n");
|
|
148
|
-
// Additional sources from "추가 소스" subsection
|
|
149
|
-
const additionalSources = parseAdditionalSources(briefContent);
|
|
150
|
-
return {
|
|
151
|
-
title,
|
|
152
|
-
description,
|
|
153
|
-
purpose,
|
|
154
|
-
targetUsers,
|
|
155
|
-
expectedResult,
|
|
156
|
-
includeScope,
|
|
157
|
-
excludeScope,
|
|
158
|
-
constraints,
|
|
159
|
-
additionalSources,
|
|
160
|
-
validation: {
|
|
161
|
-
isComplete: missingFields.length === 0,
|
|
162
|
-
missingFields,
|
|
163
|
-
},
|
|
164
|
-
};
|
|
165
|
-
}
|
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { parseBrief } from "./brief-parser.js";
|
|
3
|
-
// ─── Test fixtures ───
|
|
4
|
-
const COMPLETE_BRIEF = `# my-project — Brief
|
|
5
|
-
|
|
6
|
-
<!-- 이 문서는 /start 실행 전에 작성하는 프로젝트 준비 문서입니다. -->
|
|
7
|
-
|
|
8
|
-
## 변경 목적 (필수)
|
|
9
|
-
<!-- 왜 이 변경이 필요한가요? -->
|
|
10
|
-
|
|
11
|
-
튜터 차단 기능을 추가해야 합니다.
|
|
12
|
-
학생이 부적절한 튜터를 신고하면 매칭에서 제외되어야 합니다.
|
|
13
|
-
|
|
14
|
-
## 대상 사용자 (필수)
|
|
15
|
-
<!-- 이 변경이 영향을 미치는 사용자는 누구인가요? -->
|
|
16
|
-
|
|
17
|
-
학생 사용자 (초등~고등학생)
|
|
18
|
-
|
|
19
|
-
## 기대 결과 (필수)
|
|
20
|
-
<!-- 이 변경이 성공하면 어떤 상태가 되나요? -->
|
|
21
|
-
|
|
22
|
-
차단된 튜터가 매칭 후보에서 제외됩니다.
|
|
23
|
-
학생이 차단 목록을 관리할 수 있습니다.
|
|
24
|
-
|
|
25
|
-
## 포함 범위
|
|
26
|
-
차단 API 엔드포인트
|
|
27
|
-
매칭 로직 수정
|
|
28
|
-
|
|
29
|
-
## 제외 범위
|
|
30
|
-
관리자 대시보드 변경
|
|
31
|
-
튜터 측 알림
|
|
32
|
-
|
|
33
|
-
## 제약 및 참고사항
|
|
34
|
-
기존 매칭 알고리즘 성능에 영향 최소화
|
|
35
|
-
|
|
36
|
-
## 소스
|
|
37
|
-
### 자동 로드 (환경설정)
|
|
38
|
-
- [x] 백엔드 소스 (add-dir: ./src/backend)
|
|
39
|
-
|
|
40
|
-
### 추가 소스
|
|
41
|
-
- [x] API 서버 (add-dir: /projects/api)
|
|
42
|
-
- [ ] 디자인 파일 (figma-mcp: abc123)
|
|
43
|
-
`;
|
|
44
|
-
const EMPTY_BRIEF = `# my-project — Brief
|
|
45
|
-
|
|
46
|
-
## 변경 목적 (필수)
|
|
47
|
-
<!-- 왜 이 변경이 필요한가요? -->
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
## 대상 사용자 (필수)
|
|
51
|
-
<!-- 이 변경이 영향을 미치는 사용자는 누구인가요? -->
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
## 기대 결과 (필수)
|
|
55
|
-
<!-- 이 변경이 성공하면 어떤 상태가 되나요? -->
|
|
56
|
-
|
|
57
|
-
`;
|
|
58
|
-
const PARTIAL_BRIEF = `# my-project — Brief
|
|
59
|
-
|
|
60
|
-
## 변경 목적 (필수)
|
|
61
|
-
<!-- 왜 이 변경이 필요한가요? -->
|
|
62
|
-
|
|
63
|
-
결제 시스템 개선
|
|
64
|
-
|
|
65
|
-
## 대상 사용자 (필수)
|
|
66
|
-
<!-- 이 변경이 영향을 미치는 사용자는 누구인가요? -->
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
## 기대 결과 (필수)
|
|
70
|
-
<!-- 이 변경이 성공하면 어떤 상태가 되나요? -->
|
|
71
|
-
|
|
72
|
-
결제 실패율 50% 감소
|
|
73
|
-
`;
|
|
74
|
-
const SOURCES_BRIEF = `# my-project — Brief
|
|
75
|
-
|
|
76
|
-
## 변경 목적 (필수)
|
|
77
|
-
소스 파싱 테스트
|
|
78
|
-
|
|
79
|
-
## 대상 사용자 (필수)
|
|
80
|
-
개발자
|
|
81
|
-
|
|
82
|
-
## 기대 결과 (필수)
|
|
83
|
-
소스가 올바르게 파싱됩니다.
|
|
84
|
-
|
|
85
|
-
## 소스
|
|
86
|
-
### 자동 로드 (환경설정)
|
|
87
|
-
- [x] 기본 소스 (add-dir: ./src)
|
|
88
|
-
|
|
89
|
-
### 추가 소스
|
|
90
|
-
- [x] API 서버 (add-dir: /projects/api)
|
|
91
|
-
- [ ] 디자인 시스템 (figma-mcp: figma-key-123)
|
|
92
|
-
- [x] 온톨로지 (github-tarball: https://github.com/org/ontology)
|
|
93
|
-
- [ ] 회사 문서 (obsidian-vault: /vaults/docs)
|
|
94
|
-
- [ ] (여기에 추가 소스를 기입하세요)
|
|
95
|
-
`;
|
|
96
|
-
const NO_SOURCES_BRIEF = `# my-project — Brief
|
|
97
|
-
|
|
98
|
-
## 변경 목적 (필수)
|
|
99
|
-
기능 추가
|
|
100
|
-
|
|
101
|
-
## 대상 사용자 (필수)
|
|
102
|
-
모든 사용자
|
|
103
|
-
|
|
104
|
-
## 기대 결과 (필수)
|
|
105
|
-
기능이 동작합니다.
|
|
106
|
-
|
|
107
|
-
## 소스
|
|
108
|
-
### 자동 로드 (환경설정)
|
|
109
|
-
- 환경설정 파일(.sprint-kit.yaml)이 없거나 소스가 정의되지 않았습니다.
|
|
110
|
-
|
|
111
|
-
### 추가 소스
|
|
112
|
-
- [ ] (여기에 추가 소스를 기입하세요)
|
|
113
|
-
`;
|
|
114
|
-
// ─── Tests ───
|
|
115
|
-
describe("parseBrief", () => {
|
|
116
|
-
it("extracts all fields from a complete brief", () => {
|
|
117
|
-
const result = parseBrief(COMPLETE_BRIEF);
|
|
118
|
-
expect(result.title).toBe("튜터 차단 기능을 추가해야 합니다.");
|
|
119
|
-
expect(result.purpose).toContain("튜터 차단 기능을 추가해야 합니다.");
|
|
120
|
-
expect(result.purpose).toContain("학생이 부적절한 튜터를 신고하면");
|
|
121
|
-
expect(result.targetUsers).toBe("학생 사용자 (초등~고등학생)");
|
|
122
|
-
expect(result.expectedResult).toContain("차단된 튜터가 매칭 후보에서 제외됩니다.");
|
|
123
|
-
expect(result.includeScope).toContain("차단 API 엔드포인트");
|
|
124
|
-
expect(result.excludeScope).toContain("관리자 대시보드 변경");
|
|
125
|
-
expect(result.constraints).toContain("기존 매칭 알고리즘 성능에 영향 최소화");
|
|
126
|
-
// Description = purpose + expectedResult
|
|
127
|
-
expect(result.description).toContain("튜터 차단 기능을 추가해야 합니다.");
|
|
128
|
-
expect(result.description).toContain("차단된 튜터가 매칭 후보에서 제외됩니다.");
|
|
129
|
-
// Validation
|
|
130
|
-
expect(result.validation.isComplete).toBe(true);
|
|
131
|
-
expect(result.validation.missingFields).toEqual([]);
|
|
132
|
-
});
|
|
133
|
-
it("reports missing required fields when brief is empty", () => {
|
|
134
|
-
const result = parseBrief(EMPTY_BRIEF);
|
|
135
|
-
expect(result.validation.isComplete).toBe(false);
|
|
136
|
-
expect(result.validation.missingFields).toEqual([
|
|
137
|
-
"변경 목적",
|
|
138
|
-
"대상 사용자",
|
|
139
|
-
"기대 결과",
|
|
140
|
-
]);
|
|
141
|
-
expect(result.title).toBe("");
|
|
142
|
-
});
|
|
143
|
-
it("reports partially missing required fields", () => {
|
|
144
|
-
const result = parseBrief(PARTIAL_BRIEF);
|
|
145
|
-
expect(result.validation.isComplete).toBe(false);
|
|
146
|
-
expect(result.validation.missingFields).toEqual(["대상 사용자"]);
|
|
147
|
-
expect(result.title).toBe("결제 시스템 개선");
|
|
148
|
-
expect(result.purpose).toBe("결제 시스템 개선");
|
|
149
|
-
expect(result.expectedResult).toBe("결제 실패율 50% 감소");
|
|
150
|
-
});
|
|
151
|
-
it("parses additional sources into SourceEntry[]", () => {
|
|
152
|
-
const result = parseBrief(SOURCES_BRIEF);
|
|
153
|
-
expect(result.additionalSources).toHaveLength(4);
|
|
154
|
-
// add-dir
|
|
155
|
-
expect(result.additionalSources[0]).toEqual({
|
|
156
|
-
type: "add-dir",
|
|
157
|
-
path: "/projects/api",
|
|
158
|
-
description: "API 서버",
|
|
159
|
-
});
|
|
160
|
-
// figma-mcp
|
|
161
|
-
expect(result.additionalSources[1]).toEqual({
|
|
162
|
-
type: "figma-mcp",
|
|
163
|
-
file_key: "figma-key-123",
|
|
164
|
-
description: "디자인 시스템",
|
|
165
|
-
});
|
|
166
|
-
// github-tarball
|
|
167
|
-
expect(result.additionalSources[2]).toEqual({
|
|
168
|
-
type: "github-tarball",
|
|
169
|
-
url: "https://github.com/org/ontology",
|
|
170
|
-
description: "온톨로지",
|
|
171
|
-
});
|
|
172
|
-
// obsidian-vault
|
|
173
|
-
expect(result.additionalSources[3]).toEqual({
|
|
174
|
-
type: "obsidian-vault",
|
|
175
|
-
path: "/vaults/docs",
|
|
176
|
-
description: "회사 문서",
|
|
177
|
-
});
|
|
178
|
-
});
|
|
179
|
-
it("returns empty array when no additional sources", () => {
|
|
180
|
-
const result = parseBrief(NO_SOURCES_BRIEF);
|
|
181
|
-
expect(result.additionalSources).toEqual([]);
|
|
182
|
-
expect(result.validation.isComplete).toBe(true);
|
|
183
|
-
});
|
|
184
|
-
it("ignores placeholder items containing '여기에 추가'", () => {
|
|
185
|
-
const result = parseBrief(SOURCES_BRIEF);
|
|
186
|
-
// Should not include the placeholder item
|
|
187
|
-
const descriptions = result.additionalSources.map((s) => "description" in s ? s.description : "");
|
|
188
|
-
expect(descriptions).not.toContain("여기에 추가 소스를 기입하세요");
|
|
189
|
-
});
|
|
190
|
-
it("handles brief with only HTML comments in sections", () => {
|
|
191
|
-
const brief = `# test — Brief
|
|
192
|
-
|
|
193
|
-
## 변경 목적 (필수)
|
|
194
|
-
<!-- 왜 이 변경이 필요한가요? 해결하려는 문제를 설명해 주세요. -->
|
|
195
|
-
|
|
196
|
-
## 대상 사용자 (필수)
|
|
197
|
-
<!-- 이 변경이 영향을 미치는 사용자는 누구인가요? -->
|
|
198
|
-
|
|
199
|
-
## 기대 결과 (필수)
|
|
200
|
-
<!-- 이 변경이 성공하면 어떤 상태가 되나요? -->
|
|
201
|
-
`;
|
|
202
|
-
const result = parseBrief(brief);
|
|
203
|
-
expect(result.validation.isComplete).toBe(false);
|
|
204
|
-
expect(result.validation.missingFields).toEqual([
|
|
205
|
-
"변경 목적",
|
|
206
|
-
"대상 사용자",
|
|
207
|
-
"기대 결과",
|
|
208
|
-
]);
|
|
209
|
-
});
|
|
210
|
-
it("returns undefined for optional sections when not present", () => {
|
|
211
|
-
const brief = `# test — Brief
|
|
212
|
-
|
|
213
|
-
## 변경 목적 (필수)
|
|
214
|
-
기능 추가
|
|
215
|
-
|
|
216
|
-
## 대상 사용자 (필수)
|
|
217
|
-
사용자
|
|
218
|
-
|
|
219
|
-
## 기대 결과 (필수)
|
|
220
|
-
성공
|
|
221
|
-
`;
|
|
222
|
-
const result = parseBrief(brief);
|
|
223
|
-
expect(result.includeScope).toBeUndefined();
|
|
224
|
-
expect(result.excludeScope).toBeUndefined();
|
|
225
|
-
expect(result.constraints).toBeUndefined();
|
|
226
|
-
});
|
|
227
|
-
});
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
// ─── Main ───
|
|
2
|
-
/**
|
|
3
|
-
* Aggregate validation results into a ValidationCompletedPayload-compatible output.
|
|
4
|
-
*
|
|
5
|
-
* Pure function: no side effects, no file I/O, no event recording.
|
|
6
|
-
* The caller (agent protocol) is responsible for:
|
|
7
|
-
* 1. Recording validation.started event before calling this function.
|
|
8
|
-
* 2. Executing each VAL item and collecting results.
|
|
9
|
-
* 3. Recording validation.completed event with this function's output.
|
|
10
|
-
*/
|
|
11
|
-
export function validate(input) {
|
|
12
|
-
const error = validateInput(input);
|
|
13
|
-
if (error) {
|
|
14
|
-
return { success: false, reason: error };
|
|
15
|
-
}
|
|
16
|
-
const { results } = input;
|
|
17
|
-
let pass_count = 0;
|
|
18
|
-
let fail_count = 0;
|
|
19
|
-
for (const r of results) {
|
|
20
|
-
if (r.result === "pass")
|
|
21
|
-
pass_count++;
|
|
22
|
-
else
|
|
23
|
-
fail_count++;
|
|
24
|
-
}
|
|
25
|
-
const result = fail_count === 0 ? "pass" : "fail";
|
|
26
|
-
return {
|
|
27
|
-
success: true,
|
|
28
|
-
result,
|
|
29
|
-
pass_count,
|
|
30
|
-
fail_count,
|
|
31
|
-
items: results,
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
// ─── Validation ───
|
|
35
|
-
function validateInput(input) {
|
|
36
|
-
const { state, plan, results, actualPlanHash } = input;
|
|
37
|
-
if (state.current_state !== "applied") {
|
|
38
|
-
return `state.current_state must be "applied", got "${state.current_state}"`;
|
|
39
|
-
}
|
|
40
|
-
// Hash integrity check
|
|
41
|
-
if (state.validation_plan_hash && state.validation_plan_hash !== actualPlanHash) {
|
|
42
|
-
return `validation_plan_hash mismatch: expected "${state.validation_plan_hash}", got "${actualPlanHash}". validation-plan.md may have been modified after compile.`;
|
|
43
|
-
}
|
|
44
|
-
// All plan items must have a result
|
|
45
|
-
const resultValIds = new Set(results.map((r) => r.val_id));
|
|
46
|
-
for (const item of plan) {
|
|
47
|
-
if (!resultValIds.has(item.val_id)) {
|
|
48
|
-
return `${item.val_id} has no result in the provided results`;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
// All results must reference a valid plan item
|
|
52
|
-
const planValIds = new Set(plan.map((p) => p.val_id));
|
|
53
|
-
for (const r of results) {
|
|
54
|
-
if (!planValIds.has(r.val_id)) {
|
|
55
|
-
return `result references ${r.val_id} which does not exist in the validation plan`;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
return null;
|
|
59
|
-
}
|
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { validate } from "./validate.js";
|
|
3
|
-
// ─── Helpers ───
|
|
4
|
-
function makeState(overrides = {}) {
|
|
5
|
-
const emptyPool = {
|
|
6
|
-
constraints: [],
|
|
7
|
-
summary: { total: 0, required: 0, recommended: 0, decided: 0, clarify_pending: 0, invalidated: 0, undecided: 0 },
|
|
8
|
-
};
|
|
9
|
-
return {
|
|
10
|
-
scope_id: "SC-TEST", title: "T", description: "d", entry_mode: "experience",
|
|
11
|
-
current_state: "applied", constraint_pool: emptyPool,
|
|
12
|
-
stale: false, compile_ready: true, convergence_blocked: false,
|
|
13
|
-
revision_count_align: 0, revision_count_surface: 0, retry_count_compile: 0,
|
|
14
|
-
snapshot_revision: 0, pre_apply_completed: false, prd_review_completed: false,
|
|
15
|
-
validation_plan_hash: "plan_hash_abc",
|
|
16
|
-
verdict_log: [], feedback_history: [], latest_revision: 20,
|
|
17
|
-
...overrides,
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
function makePlan(...items) {
|
|
21
|
-
return items.map((i) => ({
|
|
22
|
-
val_id: i.val_id,
|
|
23
|
-
related_cst: i.cst,
|
|
24
|
-
decision_type: i.type,
|
|
25
|
-
target: `target ${i.val_id}`,
|
|
26
|
-
method: `method ${i.val_id}`,
|
|
27
|
-
pass_criteria: `criteria ${i.val_id}`,
|
|
28
|
-
fail_action: `action ${i.val_id}`,
|
|
29
|
-
}));
|
|
30
|
-
}
|
|
31
|
-
function makeResults(...items) {
|
|
32
|
-
return items.map((i) => ({
|
|
33
|
-
val_id: i.val_id,
|
|
34
|
-
related_cst: i.cst,
|
|
35
|
-
result: i.result,
|
|
36
|
-
detail: i.detail ?? `${i.result} detail`,
|
|
37
|
-
}));
|
|
38
|
-
}
|
|
39
|
-
function makeInput(overrides = {}) {
|
|
40
|
-
return {
|
|
41
|
-
state: makeState(),
|
|
42
|
-
plan: makePlan({ val_id: "VAL-001", cst: "CST-001", type: "inject" }, { val_id: "VAL-002", cst: "CST-002", type: "defer" }),
|
|
43
|
-
results: makeResults({ val_id: "VAL-001", cst: "CST-001", result: "pass" }, { val_id: "VAL-002", cst: "CST-002", result: "pass" }),
|
|
44
|
-
actualPlanHash: "plan_hash_abc",
|
|
45
|
-
...overrides,
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
// ─── Input Validation ───
|
|
49
|
-
describe("validate — input validation", () => {
|
|
50
|
-
it("fails when state is not applied", () => {
|
|
51
|
-
const input = makeInput({ state: makeState({ current_state: "compiled" }) });
|
|
52
|
-
const result = validate(input);
|
|
53
|
-
expect(result.success).toBe(false);
|
|
54
|
-
if (!result.success)
|
|
55
|
-
expect(result.reason).toContain("applied");
|
|
56
|
-
});
|
|
57
|
-
it("fails when validation_plan_hash mismatches", () => {
|
|
58
|
-
const input = makeInput({ actualPlanHash: "wrong_hash" });
|
|
59
|
-
const result = validate(input);
|
|
60
|
-
expect(result.success).toBe(false);
|
|
61
|
-
if (!result.success)
|
|
62
|
-
expect(result.reason).toContain("mismatch");
|
|
63
|
-
});
|
|
64
|
-
it("passes when state has no validation_plan_hash (first compile)", () => {
|
|
65
|
-
const input = makeInput({ state: makeState({ validation_plan_hash: undefined }) });
|
|
66
|
-
const result = validate(input);
|
|
67
|
-
expect(result.success).toBe(true);
|
|
68
|
-
});
|
|
69
|
-
it("fails when a plan item has no result", () => {
|
|
70
|
-
const input = makeInput({
|
|
71
|
-
results: makeResults({ val_id: "VAL-001", cst: "CST-001", result: "pass" }),
|
|
72
|
-
// VAL-002 missing
|
|
73
|
-
});
|
|
74
|
-
const result = validate(input);
|
|
75
|
-
expect(result.success).toBe(false);
|
|
76
|
-
if (!result.success)
|
|
77
|
-
expect(result.reason).toContain("VAL-002");
|
|
78
|
-
});
|
|
79
|
-
it("fails when result references non-existent plan item", () => {
|
|
80
|
-
const input = makeInput({
|
|
81
|
-
results: makeResults({ val_id: "VAL-001", cst: "CST-001", result: "pass" }, { val_id: "VAL-002", cst: "CST-002", result: "pass" }, { val_id: "VAL-999", cst: "CST-999", result: "fail" }),
|
|
82
|
-
});
|
|
83
|
-
const result = validate(input);
|
|
84
|
-
expect(result.success).toBe(false);
|
|
85
|
-
if (!result.success)
|
|
86
|
-
expect(result.reason).toContain("VAL-999");
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
// ─── Aggregation ───
|
|
90
|
-
describe("validate — aggregation", () => {
|
|
91
|
-
it("returns pass when all items pass", () => {
|
|
92
|
-
const result = validate(makeInput());
|
|
93
|
-
expect(result.success).toBe(true);
|
|
94
|
-
if (result.success) {
|
|
95
|
-
expect(result.result).toBe("pass");
|
|
96
|
-
expect(result.pass_count).toBe(2);
|
|
97
|
-
expect(result.fail_count).toBe(0);
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
it("returns fail when any item fails", () => {
|
|
101
|
-
const input = makeInput({
|
|
102
|
-
results: makeResults({ val_id: "VAL-001", cst: "CST-001", result: "pass" }, { val_id: "VAL-002", cst: "CST-002", result: "fail", detail: "간섭 발견" }),
|
|
103
|
-
});
|
|
104
|
-
const result = validate(input);
|
|
105
|
-
expect(result.success).toBe(true);
|
|
106
|
-
if (result.success) {
|
|
107
|
-
expect(result.result).toBe("fail");
|
|
108
|
-
expect(result.pass_count).toBe(1);
|
|
109
|
-
expect(result.fail_count).toBe(1);
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
it("returns fail when all items fail", () => {
|
|
113
|
-
const input = makeInput({
|
|
114
|
-
results: makeResults({ val_id: "VAL-001", cst: "CST-001", result: "fail" }, { val_id: "VAL-002", cst: "CST-002", result: "fail" }),
|
|
115
|
-
});
|
|
116
|
-
const result = validate(input);
|
|
117
|
-
expect(result.success).toBe(true);
|
|
118
|
-
if (result.success) {
|
|
119
|
-
expect(result.result).toBe("fail");
|
|
120
|
-
expect(result.pass_count).toBe(0);
|
|
121
|
-
expect(result.fail_count).toBe(2);
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
it("includes all items in output", () => {
|
|
125
|
-
const result = validate(makeInput());
|
|
126
|
-
expect(result.success).toBe(true);
|
|
127
|
-
if (result.success) {
|
|
128
|
-
expect(result.items).toHaveLength(2);
|
|
129
|
-
expect(result.items[0].val_id).toBe("VAL-001");
|
|
130
|
-
expect(result.items[1].val_id).toBe("VAL-002");
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
// ─── Edge Cases ───
|
|
135
|
-
describe("validate — edge cases", () => {
|
|
136
|
-
it("handles empty plan and results (all-pass)", () => {
|
|
137
|
-
const input = makeInput({ plan: [], results: [] });
|
|
138
|
-
const result = validate(input);
|
|
139
|
-
expect(result.success).toBe(true);
|
|
140
|
-
if (result.success) {
|
|
141
|
-
expect(result.result).toBe("pass");
|
|
142
|
-
expect(result.pass_count).toBe(0);
|
|
143
|
-
expect(result.fail_count).toBe(0);
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
it("is deterministic", () => {
|
|
147
|
-
const input = makeInput();
|
|
148
|
-
const r1 = validate(input);
|
|
149
|
-
const r2 = validate(input);
|
|
150
|
-
expect(r1).toEqual(r2);
|
|
151
|
-
});
|
|
152
|
-
it("handles inject + defer + override mix", () => {
|
|
153
|
-
const plan = makePlan({ val_id: "VAL-001", cst: "CST-001", type: "inject" }, { val_id: "VAL-002", cst: "CST-002", type: "defer" }, { val_id: "VAL-003", cst: "CST-003", type: "override" });
|
|
154
|
-
const results = makeResults({ val_id: "VAL-001", cst: "CST-001", result: "pass" }, { val_id: "VAL-002", cst: "CST-002", result: "pass" }, { val_id: "VAL-003", cst: "CST-003", result: "fail", detail: "override가 반영됨" });
|
|
155
|
-
const input = makeInput({ plan, results });
|
|
156
|
-
const result = validate(input);
|
|
157
|
-
expect(result.success).toBe(true);
|
|
158
|
-
if (result.success) {
|
|
159
|
-
expect(result.result).toBe("fail");
|
|
160
|
-
expect(result.fail_count).toBe(1);
|
|
161
|
-
expect(result.items.find((i) => i.val_id === "VAL-003")?.detail).toBe("override가 반영됨");
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
// ─── Additional Edge Cases ───
|
|
166
|
-
describe("validate — additional edge cases", () => {
|
|
167
|
-
it("plan and results in different order passes", () => {
|
|
168
|
-
const plan = makePlan({ val_id: "VAL-002", cst: "CST-002", type: "defer" }, { val_id: "VAL-001", cst: "CST-001", type: "inject" });
|
|
169
|
-
const results = makeResults({ val_id: "VAL-001", cst: "CST-001", result: "pass" }, { val_id: "VAL-002", cst: "CST-002", result: "pass" });
|
|
170
|
-
const input = makeInput({ plan, results });
|
|
171
|
-
const result = validate(input);
|
|
172
|
-
expect(result.success).toBe(true);
|
|
173
|
-
});
|
|
174
|
-
it("large result set with 1 fail", () => {
|
|
175
|
-
const items = [];
|
|
176
|
-
const resultItems = [];
|
|
177
|
-
for (let i = 1; i <= 20; i++) {
|
|
178
|
-
const valId = `VAL-${String(i).padStart(3, "0")}`;
|
|
179
|
-
const cstId = `CST-${String(i).padStart(3, "0")}`;
|
|
180
|
-
items.push({ val_id: valId, cst: cstId, type: "inject" });
|
|
181
|
-
resultItems.push({ val_id: valId, cst: cstId, result: i === 10 ? "fail" : "pass" });
|
|
182
|
-
}
|
|
183
|
-
const input = makeInput({
|
|
184
|
-
plan: makePlan(...items),
|
|
185
|
-
results: makeResults(...resultItems),
|
|
186
|
-
});
|
|
187
|
-
const result = validate(input);
|
|
188
|
-
expect(result.success).toBe(true);
|
|
189
|
-
if (result.success) {
|
|
190
|
-
expect(result.result).toBe("fail");
|
|
191
|
-
expect(result.pass_count).toBe(19);
|
|
192
|
-
expect(result.fail_count).toBe(1);
|
|
193
|
-
}
|
|
194
|
-
});
|
|
195
|
-
it("state target_locked rejected", () => {
|
|
196
|
-
const input = makeInput({ state: makeState({ current_state: "target_locked" }) });
|
|
197
|
-
const result = validate(input);
|
|
198
|
-
expect(result.success).toBe(false);
|
|
199
|
-
});
|
|
200
|
-
it("state validated rejected", () => {
|
|
201
|
-
const input = makeInput({ state: makeState({ current_state: "validated" }) });
|
|
202
|
-
const result = validate(input);
|
|
203
|
-
expect(result.success).toBe(false);
|
|
204
|
-
});
|
|
205
|
-
});
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Methodology Adapter — registration metadata.
|
|
3
|
-
*
|
|
4
|
-
* This adapter handles design scopes for processes, methodologies,
|
|
5
|
-
* and governance structures (as opposed to code-product).
|
|
6
|
-
*
|
|
7
|
-
* The code-product adapter uses code parsers and brownfield analysis.
|
|
8
|
-
* The methodology adapter uses authority-chain analysis and
|
|
9
|
-
* constraint discovery from document structure.
|
|
10
|
-
*/
|
|
11
|
-
export const methodologyAdapter = {
|
|
12
|
-
name: "methodology",
|
|
13
|
-
version: "0.1.0",
|
|
14
|
-
scope_types: ["process"],
|
|
15
|
-
perspectives: ["authority-consistency"],
|
|
16
|
-
};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { methodologyAdapter } from "./adapter.js";
|
|
3
|
-
describe("methodology adapter — registration", () => {
|
|
4
|
-
it("has correct metadata", () => {
|
|
5
|
-
expect(methodologyAdapter.name).toBe("methodology");
|
|
6
|
-
expect(methodologyAdapter.scope_types).toContain("process");
|
|
7
|
-
expect(methodologyAdapter.perspectives).toContain("authority-consistency");
|
|
8
|
-
});
|
|
9
|
-
});
|