onto-mcp 0.3.2 → 0.4.1
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 +149 -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 +174 -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 +214 -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,388 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Learning consumption loader — Phase 1.5.
|
|
3
|
-
*
|
|
4
|
-
* Phase 1: C-1 (path), C-2 (parse), C-3a/C-3b (applicability filter), C-4 (sort+cap)
|
|
5
|
-
* Phase 1.5: C-3c (cross-domain rule), C-5a (tier), C-5b (token budget)
|
|
6
|
-
* Common: C-6 (render), C-6b (manifest), C-7 (summary)
|
|
7
|
-
*
|
|
8
|
-
* Design reference: .onto/temp/phase-1.5-design-draft.md
|
|
9
|
-
* Reviews: 20260407-4b64681d (R1), 20260407-bc36fb51 (R2)
|
|
10
|
-
*/
|
|
11
|
-
import fs from "node:fs";
|
|
12
|
-
import { ITEM_LINE_RE, APPLICABILITY_RE, ROLE_RE, IMPACT_RE, } from "./shared/patterns.js";
|
|
13
|
-
import { resolveLearningFilePaths } from "./shared/paths.js";
|
|
14
|
-
// ---------------------------------------------------------------------------
|
|
15
|
-
// Constants
|
|
16
|
-
// ---------------------------------------------------------------------------
|
|
17
|
-
const MAX_ITEMS_PER_AGENT = 30; // Phase 1 fallback cap
|
|
18
|
-
const TOKEN_BUDGET_PER_AGENT = 4000; // Phase 1.5 token budget (T2+ only)
|
|
19
|
-
const T1_TOKEN_WARN_RATIO = 0.5; // Warn if T1 tokens exceed 50% of budget
|
|
20
|
-
// ---------------------------------------------------------------------------
|
|
21
|
-
// C-2: Best-effort line parser (patterns from shared/patterns.ts)
|
|
22
|
-
// ---------------------------------------------------------------------------
|
|
23
|
-
function parseLearningLine(line, sourceScope, agentId, orderIndex) {
|
|
24
|
-
const typeMatch = line.match(ITEM_LINE_RE);
|
|
25
|
-
if (!typeMatch)
|
|
26
|
-
return null;
|
|
27
|
-
const type = typeMatch[1];
|
|
28
|
-
const applicability = [];
|
|
29
|
-
const appRegex = new RegExp(APPLICABILITY_RE.source, "g");
|
|
30
|
-
let appMatch;
|
|
31
|
-
while ((appMatch = appRegex.exec(line)) !== null) {
|
|
32
|
-
applicability.push(appMatch[1]);
|
|
33
|
-
}
|
|
34
|
-
const roleMatch = line.match(ROLE_RE);
|
|
35
|
-
// [insight] → null (under-classified, Phase 3 promote will re-classify)
|
|
36
|
-
let role = null;
|
|
37
|
-
if (roleMatch && roleMatch[1] !== "insight") {
|
|
38
|
-
role = roleMatch[1];
|
|
39
|
-
}
|
|
40
|
-
const impactMatch = line.match(IMPACT_RE);
|
|
41
|
-
const impact = impactMatch?.[1] === "high" ? "high" : "normal";
|
|
42
|
-
return { type, applicability, role, impact, raw_line: line, source_scope: sourceScope, agent_id: agentId, order_index: orderIndex, cross_domain: false };
|
|
43
|
-
}
|
|
44
|
-
function parseLearningFile(filePath, sourceScope, agentId, startIndex) {
|
|
45
|
-
const content = fs.readFileSync(filePath, "utf8");
|
|
46
|
-
const lines = content.split("\n");
|
|
47
|
-
const items = [];
|
|
48
|
-
const warnings = [];
|
|
49
|
-
let skipped = 0;
|
|
50
|
-
let orderIndex = startIndex;
|
|
51
|
-
for (let i = 0; i < lines.length; i++) {
|
|
52
|
-
const line = lines[i].trim();
|
|
53
|
-
if (!line || line.startsWith("#") || line.startsWith("<!--"))
|
|
54
|
-
continue;
|
|
55
|
-
if (!/^[-*+]\s+\[/.test(line))
|
|
56
|
-
continue;
|
|
57
|
-
const item = parseLearningLine(line, sourceScope, agentId, orderIndex);
|
|
58
|
-
if (item) {
|
|
59
|
-
items.push(item);
|
|
60
|
-
orderIndex++;
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
skipped++;
|
|
64
|
-
warnings.push(`[learn-loader] skip: ${filePath}:${i + 1} — parse failed`);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
return { items, skipped, warnings };
|
|
68
|
-
}
|
|
69
|
-
// ---------------------------------------------------------------------------
|
|
70
|
-
// C-3a / C-3b: Applicability filter (methodology + current domain)
|
|
71
|
-
// ---------------------------------------------------------------------------
|
|
72
|
-
function filterByApplicability(items, sessionDomain) {
|
|
73
|
-
const isNoDomain = !sessionDomain || sessionDomain === "none" || sessionDomain === "@-";
|
|
74
|
-
return items.filter((item) => {
|
|
75
|
-
if (item.applicability.includes("methodology"))
|
|
76
|
-
return true;
|
|
77
|
-
if (!isNoDomain && item.applicability.includes(`domain/${sessionDomain}`))
|
|
78
|
-
return true;
|
|
79
|
-
return false;
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
function applyCrossDomainFilter(existingItems, allParsedItems, sessionDomain) {
|
|
83
|
-
const isNoDomain = !sessionDomain || sessionDomain === "none" || sessionDomain === "@-";
|
|
84
|
-
if (isNoDomain) {
|
|
85
|
-
return { items: [...existingItems], stats: { included: 0, excluded: 0 } };
|
|
86
|
-
}
|
|
87
|
-
// Build new array — never mutate input (fail-close snapshot integrity)
|
|
88
|
-
const result = [...existingItems];
|
|
89
|
-
const existingSet = new Set(existingItems);
|
|
90
|
-
let included = 0;
|
|
91
|
-
let excluded = 0;
|
|
92
|
-
for (const item of allParsedItems) {
|
|
93
|
-
if (existingSet.has(item))
|
|
94
|
-
continue; // already included by C-3a/C-3b
|
|
95
|
-
if (item.applicability.includes("methodology"))
|
|
96
|
-
continue; // not domain-only
|
|
97
|
-
const hasDomain = item.applicability.some((a) => a.startsWith("domain/"));
|
|
98
|
-
if (!hasDomain)
|
|
99
|
-
continue;
|
|
100
|
-
if (item.applicability.includes(`domain/${sessionDomain}`))
|
|
101
|
-
continue;
|
|
102
|
-
// This is a cross-domain item
|
|
103
|
-
if (item.role === "guardrail" || item.impact === "high") {
|
|
104
|
-
result.push({ ...item, cross_domain: true });
|
|
105
|
-
included++;
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
excluded++;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
return { items: result, stats: { included, excluded } };
|
|
112
|
-
}
|
|
113
|
-
// ---------------------------------------------------------------------------
|
|
114
|
-
// C-5a: Tier assignment + sort (Phase 1.5, supersedes C-4)
|
|
115
|
-
//
|
|
116
|
-
// Tier assignment: first matching from T1 down.
|
|
117
|
-
// Intra-tier sort: current-domain first, then newest first.
|
|
118
|
-
// ---------------------------------------------------------------------------
|
|
119
|
-
function assignTier(item) {
|
|
120
|
-
if (item.role === "guardrail")
|
|
121
|
-
return 1;
|
|
122
|
-
if (item.impact === "high")
|
|
123
|
-
return 2;
|
|
124
|
-
if (item.role === "foundation")
|
|
125
|
-
return 3;
|
|
126
|
-
return 4; // convention, under-classified, or unknown role
|
|
127
|
-
}
|
|
128
|
-
function assignTierAndSort(items) {
|
|
129
|
-
const tiered = items.map((item) => ({
|
|
130
|
-
...item,
|
|
131
|
-
tier: assignTier(item),
|
|
132
|
-
}));
|
|
133
|
-
tiered.sort((a, b) => {
|
|
134
|
-
// 1. tier ascending (T1 first)
|
|
135
|
-
if (a.tier !== b.tier)
|
|
136
|
-
return a.tier - b.tier;
|
|
137
|
-
// 2. current-domain first within tier
|
|
138
|
-
const aCross = a.cross_domain ? 1 : 0;
|
|
139
|
-
const bCross = b.cross_domain ? 1 : 0;
|
|
140
|
-
if (aCross !== bCross)
|
|
141
|
-
return aCross - bCross;
|
|
142
|
-
// 3. newest first
|
|
143
|
-
return b.order_index - a.order_index;
|
|
144
|
-
});
|
|
145
|
-
return tiered;
|
|
146
|
-
}
|
|
147
|
-
// ---------------------------------------------------------------------------
|
|
148
|
-
// C-5b: Token budget (Phase 1.5)
|
|
149
|
-
//
|
|
150
|
-
// T1 items are exempt (always included).
|
|
151
|
-
// T2+ items fill budget in tier order until exhausted.
|
|
152
|
-
// Last item that crosses budget is included (over-budget allowed).
|
|
153
|
-
// ---------------------------------------------------------------------------
|
|
154
|
-
function estimateTokens(text) {
|
|
155
|
-
let tokens = 0;
|
|
156
|
-
for (const char of text) {
|
|
157
|
-
// Non-ASCII (CJK, Korean, etc.): ~1 token per character
|
|
158
|
-
// ASCII/Latin: ~4 characters per token
|
|
159
|
-
tokens += char.charCodeAt(0) > 0x7F ? 1 : 0.25;
|
|
160
|
-
}
|
|
161
|
-
return Math.ceil(tokens);
|
|
162
|
-
}
|
|
163
|
-
function applyTokenBudget(items) {
|
|
164
|
-
const kept = [];
|
|
165
|
-
let budgetUsed = 0;
|
|
166
|
-
let budgetExhausted = false;
|
|
167
|
-
let truncatedCount = 0;
|
|
168
|
-
let t1Tokens = 0;
|
|
169
|
-
for (const item of items) {
|
|
170
|
-
const tokens = estimateTokens(item.raw_line);
|
|
171
|
-
if (item.tier === 1) {
|
|
172
|
-
// T1: always included, budget exempt
|
|
173
|
-
kept.push(item);
|
|
174
|
-
t1Tokens += tokens;
|
|
175
|
-
continue;
|
|
176
|
-
}
|
|
177
|
-
if (budgetExhausted) {
|
|
178
|
-
truncatedCount++;
|
|
179
|
-
continue;
|
|
180
|
-
}
|
|
181
|
-
kept.push(item);
|
|
182
|
-
budgetUsed += tokens;
|
|
183
|
-
// Allow last item to exceed budget (over-budget)
|
|
184
|
-
if (budgetUsed >= TOKEN_BUDGET_PER_AGENT) {
|
|
185
|
-
budgetExhausted = true;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
return { items: kept, tokens_used: budgetUsed + t1Tokens, budget_truncated_count: truncatedCount, t1_tokens: t1Tokens };
|
|
189
|
-
}
|
|
190
|
-
// ---------------------------------------------------------------------------
|
|
191
|
-
// C-4: Phase 1 fallback (sort + cap 30)
|
|
192
|
-
// ---------------------------------------------------------------------------
|
|
193
|
-
function prioritySortAndCap(items) {
|
|
194
|
-
const sorted = [...items].sort((a, b) => {
|
|
195
|
-
const ag = a.role === "guardrail" ? 1 : 0;
|
|
196
|
-
const bg = b.role === "guardrail" ? 1 : 0;
|
|
197
|
-
if (ag !== bg)
|
|
198
|
-
return bg - ag;
|
|
199
|
-
const ah = a.impact === "high" ? 1 : 0;
|
|
200
|
-
const bh = b.impact === "high" ? 1 : 0;
|
|
201
|
-
if (ah !== bh)
|
|
202
|
-
return bh - ah;
|
|
203
|
-
const af = a.role === "foundation" ? 1 : 0;
|
|
204
|
-
const bf = b.role === "foundation" ? 1 : 0;
|
|
205
|
-
if (af !== bf)
|
|
206
|
-
return bf - af;
|
|
207
|
-
return b.order_index - a.order_index;
|
|
208
|
-
});
|
|
209
|
-
const capped = sorted.slice(0, MAX_ITEMS_PER_AGENT);
|
|
210
|
-
return capped.map((item) => ({ ...item, tier: assignTier(item) }));
|
|
211
|
-
}
|
|
212
|
-
// ---------------------------------------------------------------------------
|
|
213
|
-
// C-7: Distribution helpers
|
|
214
|
-
// ---------------------------------------------------------------------------
|
|
215
|
-
function computeRoleDistribution(items) {
|
|
216
|
-
const dist = { guardrail: 0, foundation: 0, convention: 0, unclassified: 0 };
|
|
217
|
-
for (const item of items) {
|
|
218
|
-
const key = item.role ?? "unclassified";
|
|
219
|
-
dist[key] = (dist[key] ?? 0) + 1;
|
|
220
|
-
}
|
|
221
|
-
return dist;
|
|
222
|
-
}
|
|
223
|
-
function computeTierDistribution(items) {
|
|
224
|
-
const dist = { "1": 0, "2": 0, "3": 0, "4": 0 };
|
|
225
|
-
for (const item of items) {
|
|
226
|
-
dist[String(item.tier)] = (dist[String(item.tier)] ?? 0) + 1;
|
|
227
|
-
}
|
|
228
|
-
return dist;
|
|
229
|
-
}
|
|
230
|
-
// ---------------------------------------------------------------------------
|
|
231
|
-
// Public API
|
|
232
|
-
// ---------------------------------------------------------------------------
|
|
233
|
-
/**
|
|
234
|
-
* Load, filter, tier, and budget-truncate learnings for a single agent.
|
|
235
|
-
* Phase 1.5 pipeline: C-3a/C-3b → C-3c → C-5a → C-5b
|
|
236
|
-
* Fail-close: falls back to Phase 1 (C-4) on any error.
|
|
237
|
-
*/
|
|
238
|
-
export function loadLearningsForAgent(agentId, projectRoot, sessionDomain) {
|
|
239
|
-
const paths = resolveLearningFilePaths(agentId, projectRoot);
|
|
240
|
-
const allParsedItems = [];
|
|
241
|
-
let totalSkipped = 0;
|
|
242
|
-
const warnings = [];
|
|
243
|
-
const filePaths = [];
|
|
244
|
-
// C-1/C-2: Load and parse — promoted (global/user) learnings only.
|
|
245
|
-
// Project-level learnings (seed, unpromoted) are excluded from consumption
|
|
246
|
-
// to prevent drift. They serve as input for creation and promotion only.
|
|
247
|
-
// See .onto/principles/product-locality-principle.md §2.2.
|
|
248
|
-
for (const [scope, filePath] of [["methodology", paths.user_path]]) {
|
|
249
|
-
if (!filePath)
|
|
250
|
-
continue;
|
|
251
|
-
filePaths.push(filePath);
|
|
252
|
-
try {
|
|
253
|
-
const r = parseLearningFile(filePath, scope, agentId, allParsedItems.length);
|
|
254
|
-
allParsedItems.push(...r.items);
|
|
255
|
-
totalSkipped += r.skipped;
|
|
256
|
-
warnings.push(...r.warnings);
|
|
257
|
-
}
|
|
258
|
-
catch (error) {
|
|
259
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
260
|
-
warnings.push(`[learn-loader] warn: ${agentId} ${scope} file read failed: ${message}`);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
const totalParsed = allParsedItems.length;
|
|
264
|
-
// C-3a/C-3b: applicability filter
|
|
265
|
-
let items = filterByApplicability(allParsedItems, sessionDomain);
|
|
266
|
-
// Phase 1.5 disabled by env var → use Phase 1 fallback
|
|
267
|
-
if (process.env.ONTO_LEARNING_TIER_DISABLED === "1") {
|
|
268
|
-
const fallback = prioritySortAndCap(items);
|
|
269
|
-
const tokensUsed = fallback.reduce((s, i) => s + estimateTokens(i.raw_line), 0);
|
|
270
|
-
return { agent_id: agentId, items: fallback, total_parsed: totalParsed, skipped_count: totalSkipped, file_paths: filePaths, warnings, degraded: false, cross_domain_included: 0, cross_domain_excluded: 0, budget_truncated_count: 0, tokens_used: tokensUsed };
|
|
271
|
-
}
|
|
272
|
-
// IAR-1: Snapshot pre-C-3c items for fail-close fallback
|
|
273
|
-
const phase1Items = [...items];
|
|
274
|
-
let crossStats = { included: 0, excluded: 0 };
|
|
275
|
-
try {
|
|
276
|
-
// C-3c: cross-domain rule-based inclusion
|
|
277
|
-
if (process.env.ONTO_LEARNING_CROSS_DOMAIN_DISABLED !== "1") {
|
|
278
|
-
const result = applyCrossDomainFilter(items, allParsedItems, sessionDomain);
|
|
279
|
-
items = result.items;
|
|
280
|
-
crossStats = result.stats;
|
|
281
|
-
}
|
|
282
|
-
// C-5a: tier assignment + sort
|
|
283
|
-
const tiered = assignTierAndSort(items);
|
|
284
|
-
// C-5b: token budget
|
|
285
|
-
const budgetResult = applyTokenBudget(tiered);
|
|
286
|
-
// T1 token warning
|
|
287
|
-
if (budgetResult.t1_tokens > TOKEN_BUDGET_PER_AGENT * T1_TOKEN_WARN_RATIO) {
|
|
288
|
-
warnings.push(`[learn-loader] warn: ${agentId} T1 tokens (${budgetResult.t1_tokens}) exceed ${T1_TOKEN_WARN_RATIO * 100}% of budget (${TOKEN_BUDGET_PER_AGENT})`);
|
|
289
|
-
}
|
|
290
|
-
return { agent_id: agentId, items: budgetResult.items, total_parsed: totalParsed, skipped_count: totalSkipped, file_paths: filePaths, warnings, degraded: false, cross_domain_included: crossStats.included, cross_domain_excluded: crossStats.excluded, budget_truncated_count: budgetResult.budget_truncated_count, tokens_used: budgetResult.tokens_used };
|
|
291
|
-
}
|
|
292
|
-
catch (error) {
|
|
293
|
-
// Fail-close: use pre-C-3c snapshot with Phase 1 fallback
|
|
294
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
295
|
-
warnings.push(`[learn-loader] Phase 1.5 degraded: ${message}, falling back to Phase 1`);
|
|
296
|
-
const fallback = prioritySortAndCap(phase1Items);
|
|
297
|
-
const tokensUsed = fallback.reduce((s, i) => s + estimateTokens(i.raw_line), 0);
|
|
298
|
-
return { agent_id: agentId, items: fallback, total_parsed: totalParsed, skipped_count: totalSkipped, file_paths: filePaths, warnings, degraded: true, cross_domain_included: 0, cross_domain_excluded: 0, budget_truncated_count: 0, tokens_used: tokensUsed };
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
/**
|
|
302
|
-
* Load learnings for all agents in a session. Returns per-agent results + manifest.
|
|
303
|
-
*/
|
|
304
|
-
export function loadLearningsForSession(agentIds, projectRoot, sessionDomain) {
|
|
305
|
-
const results = [];
|
|
306
|
-
const allPaths = [];
|
|
307
|
-
let anyDegraded = false;
|
|
308
|
-
let degradationReason = null;
|
|
309
|
-
for (const agentId of agentIds) {
|
|
310
|
-
const result = loadLearningsForAgent(agentId, projectRoot, sessionDomain);
|
|
311
|
-
results.push(result);
|
|
312
|
-
allPaths.push(...result.file_paths);
|
|
313
|
-
if (result.degraded) {
|
|
314
|
-
anyDegraded = true;
|
|
315
|
-
degradationReason = result.warnings.find((w) => w.includes("degraded")) ?? "unknown";
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
// Compute cross-domain stats from results
|
|
319
|
-
const manifest = {
|
|
320
|
-
session_domain: sessionDomain ?? "none",
|
|
321
|
-
agents_loaded: results.length,
|
|
322
|
-
total_items_loaded: results.reduce((sum, r) => sum + r.items.length, 0),
|
|
323
|
-
total_items_parsed: results.reduce((sum, r) => sum + r.total_parsed, 0),
|
|
324
|
-
total_items_skipped: results.reduce((sum, r) => sum + r.skipped_count, 0),
|
|
325
|
-
per_agent: results.map((r) => ({
|
|
326
|
-
agent_id: r.agent_id,
|
|
327
|
-
loaded: r.items.length,
|
|
328
|
-
parsed: r.total_parsed,
|
|
329
|
-
skipped: r.skipped_count,
|
|
330
|
-
truncated: Math.max(0, r.total_parsed - r.items.length),
|
|
331
|
-
role_distribution: computeRoleDistribution(r.items),
|
|
332
|
-
tier_distribution: computeTierDistribution(r.items),
|
|
333
|
-
cross_domain_included: r.cross_domain_included,
|
|
334
|
-
cross_domain_excluded: r.cross_domain_excluded,
|
|
335
|
-
tokens_used: r.tokens_used,
|
|
336
|
-
tokens_budget: TOKEN_BUDGET_PER_AGENT,
|
|
337
|
-
budget_truncated_count: r.budget_truncated_count,
|
|
338
|
-
})),
|
|
339
|
-
learning_file_paths: [...new Set(allPaths)],
|
|
340
|
-
degraded: anyDegraded,
|
|
341
|
-
degradation_reason: degradationReason,
|
|
342
|
-
};
|
|
343
|
-
return { results, manifest };
|
|
344
|
-
}
|
|
345
|
-
/**
|
|
346
|
-
* C-6: Render learning section for insertion into a lens prompt packet.
|
|
347
|
-
*/
|
|
348
|
-
export function renderLearningSection(items) {
|
|
349
|
-
if (items.length === 0)
|
|
350
|
-
return "";
|
|
351
|
-
const lines = [
|
|
352
|
-
"",
|
|
353
|
-
"## Prior Learnings",
|
|
354
|
-
`Items: ${items.length} (priority: T1-guardrail > T2-high-impact > T3-foundation > T4-other)`,
|
|
355
|
-
"Use these learnings as prior knowledge during your review. Report which learnings you applied in your output.",
|
|
356
|
-
"",
|
|
357
|
-
];
|
|
358
|
-
for (const item of items) {
|
|
359
|
-
lines.push(item.raw_line);
|
|
360
|
-
}
|
|
361
|
-
return lines.join("\n");
|
|
362
|
-
}
|
|
363
|
-
/**
|
|
364
|
-
* C-7: Format loading summary for console output.
|
|
365
|
-
*/
|
|
366
|
-
export function formatLoadingSummary(manifest) {
|
|
367
|
-
const lines = [
|
|
368
|
-
`[learn-loader] domain=${manifest.session_domain}, agents=${manifest.agents_loaded}, ` +
|
|
369
|
-
`loaded=${manifest.total_items_loaded}, parsed=${manifest.total_items_parsed}, ` +
|
|
370
|
-
`skipped=${manifest.total_items_skipped}` +
|
|
371
|
-
(manifest.degraded ? ` (degraded: Phase 1 fallback)` : ""),
|
|
372
|
-
];
|
|
373
|
-
for (const agent of manifest.per_agent) {
|
|
374
|
-
const tierParts = Object.entries(agent.tier_distribution)
|
|
375
|
-
.filter(([, count]) => count > 0)
|
|
376
|
-
.map(([tier, count]) => `T${tier}:${count}`)
|
|
377
|
-
.join(" ");
|
|
378
|
-
const crossPart = agent.cross_domain_included > 0 ? ` cross:${agent.cross_domain_included}` : "";
|
|
379
|
-
const tokenPart = ` tok:${agent.tokens_used}/${agent.tokens_budget}`;
|
|
380
|
-
lines.push(` ${agent.agent_id}: ${agent.loaded}/${agent.parsed}` +
|
|
381
|
-
(agent.truncated > 0 ? ` (truncated ${agent.truncated})` : "") +
|
|
382
|
-
(agent.loaded === 0 ? " (filtered to zero)" : "") +
|
|
383
|
-
(tierParts ? ` [${tierParts}]` : "") +
|
|
384
|
-
crossPart +
|
|
385
|
-
tokenPart);
|
|
386
|
-
}
|
|
387
|
-
return lines.join("\n");
|
|
388
|
-
}
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Learning consumption loader tests (W-B-17).
|
|
3
|
-
*
|
|
4
|
-
* 핵심 검증: promoted(user scope) 학습만 consumer 에 노출.
|
|
5
|
-
* project scope(seed/candidate/provisional) 학습은 소비되지 않음.
|
|
6
|
-
* feedback_learning_core_value.md 정책과 implementation 일치 확인.
|
|
7
|
-
*/
|
|
8
|
-
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
9
|
-
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
|
|
10
|
-
import { join } from "node:path";
|
|
11
|
-
import { tmpdir } from "node:os";
|
|
12
|
-
import { loadLearningsForAgent, loadLearningsForSession } from "./loader.js";
|
|
13
|
-
// ─── Test fixtures ───
|
|
14
|
-
const PROMOTED_LEARNING = `# logic learnings
|
|
15
|
-
|
|
16
|
-
- [fact] [methodology] [guardrail] [high] 리뷰 시 모순 검출은 첫 번째 우선순위
|
|
17
|
-
- [judgment] [methodology] [foundation] [normal] 구조 분해 후 의존성 분석이 효율적
|
|
18
|
-
`;
|
|
19
|
-
const UNPROMOTED_LEARNING = `# logic learnings (project scope)
|
|
20
|
-
|
|
21
|
-
- [fact] [methodology] [guardrail] [high] 이 프로젝트에서 인증 모듈은 항상 먼저 검토해야 함
|
|
22
|
-
- [judgment] [domain/se] [convention] [normal] SE 도메인의 CQ 우선순위는 보안 → 성능 → 유지보수
|
|
23
|
-
`;
|
|
24
|
-
let tmpDir;
|
|
25
|
-
let origHome;
|
|
26
|
-
beforeEach(() => {
|
|
27
|
-
tmpDir = mkdtempSync(join(tmpdir(), "loader-test-"));
|
|
28
|
-
origHome = process.env.HOME ?? "";
|
|
29
|
-
// user scope (promoted) 경로 설정
|
|
30
|
-
process.env.HOME = tmpDir;
|
|
31
|
-
});
|
|
32
|
-
afterEach(() => {
|
|
33
|
-
process.env.HOME = origHome;
|
|
34
|
-
rmSync(tmpDir, { recursive: true, force: true });
|
|
35
|
-
});
|
|
36
|
-
function setupPromotedLearning(agentId) {
|
|
37
|
-
const userDir = join(tmpDir, ".onto", "learnings");
|
|
38
|
-
mkdirSync(userDir, { recursive: true });
|
|
39
|
-
writeFileSync(join(userDir, `${agentId}.md`), PROMOTED_LEARNING, "utf-8");
|
|
40
|
-
}
|
|
41
|
-
function setupProjectLearning(projectRoot, agentId) {
|
|
42
|
-
const projectDir = join(projectRoot, ".onto", "learnings");
|
|
43
|
-
mkdirSync(projectDir, { recursive: true });
|
|
44
|
-
writeFileSync(join(projectDir, `${agentId}.md`), UNPROMOTED_LEARNING, "utf-8");
|
|
45
|
-
}
|
|
46
|
-
describe("loader consumption guard (W-B-17)", () => {
|
|
47
|
-
it("promoted(user scope) 학습만 로드한다", () => {
|
|
48
|
-
const projectRoot = join(tmpDir, "project");
|
|
49
|
-
mkdirSync(projectRoot, { recursive: true });
|
|
50
|
-
setupPromotedLearning("logic");
|
|
51
|
-
const result = loadLearningsForAgent("logic", projectRoot, "methodology");
|
|
52
|
-
expect(result.items.length).toBeGreaterThan(0);
|
|
53
|
-
// 모든 item 이 user scope
|
|
54
|
-
for (const item of result.items) {
|
|
55
|
-
expect(item.source_scope).toBe("methodology");
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
it("project scope(unpromoted) 학습은 소비하지 않는다", () => {
|
|
59
|
-
const projectRoot = join(tmpDir, "project");
|
|
60
|
-
mkdirSync(projectRoot, { recursive: true });
|
|
61
|
-
// project scope 만 존재, user scope 없음
|
|
62
|
-
setupProjectLearning(projectRoot, "logic");
|
|
63
|
-
const result = loadLearningsForAgent("logic", projectRoot, "methodology");
|
|
64
|
-
// project scope 학습이 있어도 로드되지 않음
|
|
65
|
-
expect(result.items).toHaveLength(0);
|
|
66
|
-
expect(result.total_parsed).toBe(0);
|
|
67
|
-
});
|
|
68
|
-
it("user + project 모두 존재할 때 user 만 로드한다", () => {
|
|
69
|
-
const projectRoot = join(tmpDir, "project");
|
|
70
|
-
mkdirSync(projectRoot, { recursive: true });
|
|
71
|
-
setupPromotedLearning("logic");
|
|
72
|
-
setupProjectLearning(projectRoot, "logic");
|
|
73
|
-
const result = loadLearningsForAgent("logic", projectRoot, "methodology");
|
|
74
|
-
// user scope 항목만 로드됨
|
|
75
|
-
expect(result.items.length).toBeGreaterThan(0);
|
|
76
|
-
for (const item of result.items) {
|
|
77
|
-
expect(item.source_scope).toBe("methodology");
|
|
78
|
-
}
|
|
79
|
-
// project scope 의 "인증 모듈" 항목은 포함되지 않음
|
|
80
|
-
const hasProjectItem = result.items.some(i => i.raw_line.includes("인증 모듈"));
|
|
81
|
-
expect(hasProjectItem).toBe(false);
|
|
82
|
-
});
|
|
83
|
-
it("loadLearningsForSession 도 동일한 promoted-only 정책을 따른다", () => {
|
|
84
|
-
const projectRoot = join(tmpDir, "project");
|
|
85
|
-
mkdirSync(projectRoot, { recursive: true });
|
|
86
|
-
setupPromotedLearning("logic");
|
|
87
|
-
setupProjectLearning(projectRoot, "logic");
|
|
88
|
-
const { results, manifest } = loadLearningsForSession(["logic"], projectRoot, "methodology");
|
|
89
|
-
expect(results).toHaveLength(1);
|
|
90
|
-
for (const item of results[0].items) {
|
|
91
|
-
expect(item.source_scope).toBe("methodology");
|
|
92
|
-
}
|
|
93
|
-
expect(manifest.total_items_loaded).toBeGreaterThan(0);
|
|
94
|
-
});
|
|
95
|
-
it("학습 파일이 없으면 빈 결과를 반환한다 (에러 아님)", () => {
|
|
96
|
-
const projectRoot = join(tmpDir, "project");
|
|
97
|
-
mkdirSync(projectRoot, { recursive: true });
|
|
98
|
-
const result = loadLearningsForAgent("logic", projectRoot, "methodology");
|
|
99
|
-
expect(result.items).toHaveLength(0);
|
|
100
|
-
expect(result.degraded).toBe(false);
|
|
101
|
-
});
|
|
102
|
-
});
|