@opengsd/gsd-core 1.13.0 → 1.14.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/agents/gsd-advisor-researcher.compact.md +85 -0
- package/agents/gsd-ai-researcher.compact.md +96 -0
- package/agents/gsd-assumptions-analyzer.compact.md +81 -0
- package/agents/gsd-code-fixer.compact.md +458 -0
- package/agents/gsd-code-fixer.md +5 -5
- package/agents/gsd-code-reviewer.compact.md +269 -0
- package/agents/gsd-code-reviewer.md +15 -3
- package/agents/gsd-codebase-mapper.compact.md +760 -0
- package/agents/gsd-debug-session-manager.compact.md +345 -0
- package/agents/gsd-doc-classifier.compact.md +192 -0
- package/agents/gsd-doc-synthesizer.compact.md +200 -0
- package/agents/gsd-doc-verifier.compact.md +143 -0
- package/agents/gsd-doc-writer.compact.md +440 -0
- package/agents/gsd-dom-verifier.compact.md +138 -0
- package/agents/gsd-domain-researcher.compact.md +141 -0
- package/agents/gsd-eval-auditor.compact.md +160 -0
- package/agents/gsd-eval-planner.compact.md +137 -0
- package/agents/gsd-framework-selector.compact.md +82 -0
- package/agents/gsd-integration-checker.compact.md +245 -0
- package/agents/gsd-intel-updater.compact.md +226 -0
- package/agents/gsd-mempalace-curator.compact.md +45 -0
- package/agents/gsd-nyquist-auditor.compact.md +179 -0
- package/agents/gsd-pattern-mapper.compact.md +275 -0
- package/agents/gsd-project-researcher.compact.md +587 -0
- package/agents/gsd-research-synthesizer.compact.md +212 -0
- package/agents/gsd-roadmapper.compact.md +454 -0
- package/agents/gsd-roadmapper.md +13 -0
- package/agents/gsd-security-auditor.compact.md +162 -0
- package/agents/gsd-ui-auditor.compact.md +404 -0
- package/agents/gsd-ui-checker.compact.md +277 -0
- package/agents/gsd-ui-researcher.compact.md +282 -0
- package/agents/gsd-user-profiler.compact.md +108 -0
- package/bin/install.js +206 -68
- package/commands/gsd/cleanup.md +1 -0
- package/commands/gsd/code-review.md +2 -1
- package/commands/gsd/complete-milestone.md +1 -0
- package/commands/gsd/config.md +1 -0
- package/commands/gsd/debug.md +1 -0
- package/commands/gsd/graphify.md +1 -0
- package/commands/gsd/health.md +1 -0
- package/commands/gsd/mempalace-capture.md +1 -0
- package/commands/gsd/mempalace-recall.md +1 -0
- package/commands/gsd/new-milestone.md +1 -0
- package/commands/gsd/new-project.md +1 -0
- package/commands/gsd/next.md +1 -0
- package/commands/gsd/pause-work.md +1 -0
- package/commands/gsd/phase.md +1 -0
- package/commands/gsd/pr-branch.md +1 -0
- package/commands/gsd/resume-work.md +1 -0
- package/commands/gsd/review-backlog.md +1 -0
- package/commands/gsd/settings.md +2 -1
- package/commands/gsd/stats.md +1 -0
- package/commands/gsd/thread.md +1 -0
- package/commands/gsd/workspace.md +1 -0
- package/commands/gsd/workstreams.md +1 -0
- package/gsd-core/bin/check-latest-version.cjs +8 -3
- package/gsd-core/bin/gsd-tools.cjs +338 -125
- package/gsd-core/bin/lib/adr-parser.cjs +1 -1
- package/gsd-core/bin/lib/artifacts.cjs +2 -1
- package/gsd-core/bin/lib/audit.cjs +39 -22
- package/gsd-core/bin/lib/broken-windows.cjs +168 -49
- package/gsd-core/bin/lib/capability-lifecycle.cjs +10 -6
- package/gsd-core/bin/lib/capability-loader.cjs +135 -1
- package/gsd-core/bin/lib/capability-registry.cjs +79 -67
- package/gsd-core/bin/lib/capability-source.cjs +19 -2
- package/gsd-core/bin/lib/capability-validator.cjs +14 -1
- package/gsd-core/bin/lib/check-command-router.cjs +113 -36
- package/gsd-core/bin/lib/code-review-depth.cjs +2 -2
- package/gsd-core/bin/lib/commands.cjs +650 -72
- package/gsd-core/bin/lib/config-loader.cjs +1 -0
- package/gsd-core/bin/lib/config.cjs +153 -38
- package/gsd-core/bin/lib/coverage.cjs +1 -1
- package/gsd-core/bin/lib/decisions.cjs +137 -34
- package/gsd-core/bin/lib/external-descriptor-trust.cjs +29 -14
- package/gsd-core/bin/lib/gsd2-import.cjs +1 -2
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +12 -1
- package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +1 -1
- package/gsd-core/bin/lib/init.cjs +409 -47
- package/gsd-core/bin/lib/install-engine.cjs +16 -3
- package/gsd-core/bin/lib/install-profiles.cjs +14 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +33 -4
- package/gsd-core/bin/lib/loop-resolver.cjs +50 -31
- package/gsd-core/bin/lib/mcp-catalog.cjs +2 -2
- package/gsd-core/bin/lib/milestone.cjs +19 -8
- package/gsd-core/bin/lib/model-resolver.cjs +101 -10
- package/gsd-core/bin/lib/phase-command-router.cjs +7 -1
- package/gsd-core/bin/lib/phase-id.cjs +161 -22
- package/gsd-core/bin/lib/phase-lifecycle.cjs +61 -0
- package/gsd-core/bin/lib/phase.cjs +167 -63
- package/gsd-core/bin/lib/planning-inspect.cjs +34 -18
- package/gsd-core/bin/lib/planning-snapshot.cjs +61 -12
- package/gsd-core/bin/lib/planning-workspace.cjs +50 -1
- package/gsd-core/bin/lib/pristine-baseline.cjs +182 -0
- package/gsd-core/bin/lib/prohibition-enforcement.cjs +91 -4
- package/gsd-core/bin/lib/quick-batch.cjs +1 -1
- package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +61 -2
- package/gsd-core/bin/lib/research-store.cjs +11 -12
- package/gsd-core/bin/lib/review-lane-invocation.cjs +23 -0
- package/gsd-core/bin/lib/reviewer-step-dispatch.cjs +337 -0
- package/gsd-core/bin/lib/roadmap-parser.cjs +56 -15
- package/gsd-core/bin/lib/roadmap.cjs +108 -14
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +27 -10
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +12 -3
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +13 -5
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +193 -4
- package/gsd-core/bin/lib/security.cjs +126 -7
- package/gsd-core/bin/lib/state-document.cjs +130 -28
- package/gsd-core/bin/lib/state-md-schema.cjs +21 -14
- package/gsd-core/bin/lib/state-transition.cjs +142 -28
- package/gsd-core/bin/lib/state.cjs +223 -27
- package/gsd-core/bin/lib/surface.cjs +60 -2
- package/gsd-core/bin/lib/task-command-router.cjs +12 -6
- package/gsd-core/bin/lib/uat.cjs +1 -1
- package/gsd-core/bin/lib/update-context.cjs +30 -24
- package/gsd-core/bin/lib/vendor/js-yaml.cjs +11 -3
- package/gsd-core/bin/lib/verification.cjs +47 -15
- package/gsd-core/bin/lib/verify-command-grounding.cjs +1 -1
- package/gsd-core/bin/lib/verify.cjs +188 -23
- package/gsd-core/bin/lib/workstream-inventory.cjs +1 -0
- package/gsd-core/bin/lib/worktree-safety.cjs +13 -7
- package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +5 -0
- package/gsd-core/bin/verify-reapply-patches.cjs +439 -80
- package/gsd-core/references/compact-content-gate.md +66 -0
- package/gsd-core/references/loop-hook-dispatch.md +18 -0
- package/gsd-core/references/model-profiles.md +12 -3
- package/gsd-core/references/planning-config.md +3 -0
- package/gsd-core/references/tdd.md +5 -2
- package/gsd-core/references/thinking-models-planning.md +18 -2
- package/gsd-core/references/verification-patterns.md +17 -4
- package/gsd-core/references/worktree-path-safety.md +112 -2
- package/gsd-core/templates/README.md +7 -1
- package/gsd-core/templates/state.md +6 -3
- package/gsd-core/templates/summary.compact.md +212 -0
- package/gsd-core/templates/user-setup.compact.md +199 -0
- package/gsd-core/templates/user-setup.md +0 -9
- package/gsd-core/workflows/add-todo.md +3 -2
- package/gsd-core/workflows/autonomous.md +13 -10
- package/gsd-core/workflows/check-todos.md +4 -2
- package/gsd-core/workflows/cleanup.md +3 -1
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +7 -0
- package/gsd-core/workflows/code-review-fix.md +3 -3
- package/gsd-core/workflows/code-review.md +156 -30
- package/gsd-core/workflows/complete-milestone/detail/elaboration.md +274 -0
- package/gsd-core/workflows/complete-milestone.md +39 -262
- package/gsd-core/workflows/docs-update/detail/elaboration.md +179 -0
- package/gsd-core/workflows/docs-update.md +14 -155
- package/gsd-core/workflows/execute-phase/detail/elaboration.md +124 -0
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +18 -3
- package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +56 -0
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +7 -2
- package/gsd-core/workflows/execute-phase/steps/executor-progress-policy.md +43 -0
- package/gsd-core/workflows/execute-phase/steps/sequential-root-pin.md +35 -0
- package/gsd-core/workflows/execute-phase.md +53 -152
- package/gsd-core/workflows/execute-plan.md +20 -7
- package/gsd-core/workflows/help/modes/full.compact.md +398 -0
- package/gsd-core/workflows/help.md +1 -1
- package/gsd-core/workflows/map-codebase.md +50 -3
- package/gsd-core/workflows/new-milestone.md +54 -12
- package/gsd-core/workflows/new-project/detail/elaboration.md +216 -0
- package/gsd-core/workflows/new-project.md +32 -202
- package/gsd-core/workflows/plan-phase/detail/elaboration.md +209 -0
- package/gsd-core/workflows/plan-phase.md +22 -181
- package/gsd-core/workflows/pr-branch.md +19 -7
- package/gsd-core/workflows/quick.md +8 -1
- package/gsd-core/workflows/reapply-patches.md +77 -3
- package/gsd-core/workflows/settings.md +18 -5
- package/gsd-core/workflows/update.md +7 -5
- package/gsd-core/workflows/verify-work/detail/elaboration.md +230 -0
- package/gsd-core/workflows/verify-work.md +20 -180
- package/hooks/dist/gsd-agent-isolation-guard.js +42 -16
- package/hooks/dist/gsd-context-monitor.js +88 -15
- package/hooks/dist/gsd-cursor-subagent-start.js +34 -14
- package/hooks/dist/gsd-secret-read-guard.js +44 -18
- package/hooks/dist/gsd-statusline.js +11 -7
- package/hooks/dist/gsd-validate-commit.sh +34 -4
- package/hooks/dist/gsd-worktree-path-guard.js +25 -14
- package/hooks/dist/gsd-write-guard.js +46 -1
- package/hooks/dist/lib/dispatch-identity.js +187 -0
- package/hooks/dist/lib/filename-classification.js +64 -0
- package/hooks/dist/lib/isolation-deny-reason.js +53 -1
- package/hooks/dist/lib/isolation-sentinel.js +58 -19
- package/hooks/gsd-agent-isolation-guard.js +42 -16
- package/hooks/gsd-context-monitor.js +88 -15
- package/hooks/gsd-cursor-subagent-start.js +34 -14
- package/hooks/gsd-secret-read-guard.js +44 -18
- package/hooks/gsd-statusline.js +11 -7
- package/hooks/gsd-validate-commit.sh +34 -4
- package/hooks/gsd-worktree-path-guard.js +25 -14
- package/hooks/gsd-write-guard.js +46 -1
- package/hooks/lib/dispatch-identity.js +187 -0
- package/hooks/lib/filename-classification.js +64 -0
- package/hooks/lib/isolation-deny-reason.js +53 -1
- package/hooks/lib/isolation-sentinel.js +58 -19
- package/package.json +10 -6
- package/scripts/benchmark-compact-content-variants.cjs +298 -0
- package/scripts/benchmark-compact-content.cjs +368 -0
- package/scripts/check-contract-drift.cjs +4 -1
- package/scripts/check-env.cjs +36 -8
- package/scripts/check-glossary-refs.cjs +25 -21
- package/scripts/ci-next-health.cjs +271 -0
- package/scripts/ci-prepare-test-scope.cjs +7 -7
- package/scripts/ci-test-scope.cjs +126 -20
- package/scripts/ci-timeout-report.cjs +1 -1
- package/scripts/diff-touches-shipped-paths.cjs +1 -1
- package/scripts/docs-guard-registry.cjs +7 -2
- package/scripts/gen-adr-index.cjs +8 -2
- package/scripts/gen-inventory-manifest.cjs +12 -0
- package/scripts/gen-platform-conformance-tier.cjs +557 -0
- package/scripts/lib/drift-scan.cjs +1 -1
- package/scripts/lib/macos-conformance-tier.generated.cjs +210 -0
- package/scripts/lib/npm-version-check-diagnosis.cjs +59 -0
- package/scripts/lib/platform-conformance-tier.generated.cjs +276 -0
- package/scripts/lib/suite-detection.cjs +32 -0
- package/scripts/lint-allowed-tools-parity.cjs +221 -0
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +19 -2
- package/scripts/lint-phase-id-drift.cjs +338 -13
- package/scripts/lint-response-language-coverage.cjs +9 -3
- package/scripts/lint-source-test-name-collision.cjs +1 -1
- package/scripts/lint-test-file-count.allowlist.json +1 -0
- package/scripts/lint-vendored-deps.cjs +128 -17
- package/scripts/lint-workflow-shellcheck-baseline.json +85 -0
- package/scripts/prompt-injection-scan.sh +14 -0
- package/scripts/workflow-size.cjs +139 -0
- package/skills/gsd-cleanup/SKILL.md +1 -0
- package/skills/gsd-code-review/SKILL.md +2 -1
- package/skills/gsd-complete-milestone/SKILL.md +1 -0
- package/skills/gsd-config/SKILL.md +1 -0
- package/skills/gsd-debug/SKILL.md +1 -0
- package/skills/gsd-graphify/SKILL.md +1 -0
- package/skills/gsd-health/SKILL.md +1 -0
- package/skills/gsd-mempalace-capture/SKILL.md +1 -0
- package/skills/gsd-mempalace-recall/SKILL.md +1 -0
- package/skills/gsd-new-milestone/SKILL.md +1 -0
- package/skills/gsd-new-project/SKILL.md +1 -0
- package/skills/gsd-next/SKILL.md +1 -0
- package/skills/gsd-pause-work/SKILL.md +1 -0
- package/skills/gsd-phase/SKILL.md +1 -0
- package/skills/gsd-pr-branch/SKILL.md +1 -0
- package/skills/gsd-resume-work/SKILL.md +1 -0
- package/skills/gsd-review-backlog/SKILL.md +1 -0
- package/skills/gsd-settings/SKILL.md +2 -1
- package/skills/gsd-stats/SKILL.md +1 -0
- package/skills/gsd-thread/SKILL.md +1 -0
- package/skills/gsd-workspace/SKILL.md +1 -0
- package/skills/gsd-workstreams/SKILL.md +1 -0
- package/vscode/package.json +1 -1
- package/gsd-core/templates/claude-md.md +0 -145
- package/gsd-core/templates/codebase/concerns.md +0 -310
- package/gsd-core/templates/codebase/conventions.md +0 -307
- package/gsd-core/templates/codebase/integrations.md +0 -280
- package/gsd-core/templates/codebase/structure.md +0 -285
- package/gsd-core/templates/codebase/testing.md +0 -480
- package/gsd-core/templates/debug-subagent-prompt.md +0 -91
- package/gsd-core/templates/discovery.md +0 -146
|
@@ -43,24 +43,31 @@ exports.STATE_FIELD_SCHEMA = exports.STATUS_LIFECYCLE_ENUM = void 0;
|
|
|
43
43
|
/**
|
|
44
44
|
* The seven CANONICAL values `normalizeStateStatus` (`src/state-document.cts`)
|
|
45
45
|
* maps recognized raw status prose TO — the function's default fallback plus
|
|
46
|
-
* each
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
46
|
+
* each vocabulary entry's literal output. This is NOT the raw body prose
|
|
47
|
+
* vocabulary `CONTEXT.md`'s "STATE.md Status Lifecycle (ADR-2207)" entry
|
|
48
|
+
* documents (`Ready to plan` → `All phases complete` → `<version> milestone
|
|
49
|
+
* complete` → `Awaiting next milestone`, plus the handler-authored strings
|
|
50
|
+
* in `KNOWN_TEMPLATE_DEFAULTS['Status']`) — that is free-form prose
|
|
51
|
+
* `normalizeStateStatus` READS.
|
|
52
52
|
*
|
|
53
53
|
* CORRECTED (#3873 phase-3 test-matrix row 26 — verified by executing
|
|
54
54
|
* `normalizeStateStatus`, not by reading this docstring's prior claim):
|
|
55
55
|
* this is NOT a closed set the `status` frontmatter key is restricted to at
|
|
56
|
-
* runtime. `normalizeStateStatus` is deliberately LENIENT: its fallback
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
56
|
+
* runtime. `normalizeStateStatus` is deliberately LENIENT: its fallback
|
|
57
|
+
* returns the caller's raw, UNRECOGNIZED prose unchanged — when none of its
|
|
58
|
+
* vocabulary entries recognize the whole-field input, that raw value is what
|
|
59
|
+
* the function returns. A status value outside this seven-member set is not
|
|
60
|
+
* rejected, coerced, or normalized; it passes straight through into the
|
|
61
|
+
* frontmatter. `STATUS_LIFECYCLE_ENUM` is therefore the set of values the
|
|
62
|
+
* normalizer maps recognized input ONTO, not a runtime-enforced closed
|
|
63
|
+
* vocabulary for the field.
|
|
64
|
+
*
|
|
65
|
+
* #4186: recognition is ANCHORED (whole-field match against the declared
|
|
66
|
+
* `STATUS_EXACT_TOKENS` / `STATUS_ANCHORED_PATTERNS` tables in
|
|
67
|
+
* `src/state-document.cts`), never a substring scan of the prose — prose
|
|
68
|
+
* merely CONTAINING a status word (a `.planning/` path, `verifica*`,
|
|
69
|
+
* `completezza`) passes through verbatim instead of being rewritten to a
|
|
70
|
+
* credible wrong token.
|
|
64
71
|
*/
|
|
65
72
|
exports.STATUS_LIFECYCLE_ENUM = Object.freeze([
|
|
66
73
|
'unknown',
|
|
@@ -36,6 +36,11 @@ const state_document_cjs_2 = require("./state-document.cjs");
|
|
|
36
36
|
const markdown_sectionizer_cjs_1 = require("./markdown-sectionizer.cjs");
|
|
37
37
|
const phase_lifecycle_cjs_1 = require("./phase-lifecycle.cjs");
|
|
38
38
|
const pattern_cjs_1 = require("./pattern.cjs");
|
|
39
|
+
// #4129: the completion-ratio kernel for the resync-arm ratchet's percent
|
|
40
|
+
// (planning-scope's SCOPE — state-document's own dependency, no cycle here:
|
|
41
|
+
// state-document never imports this module).
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
43
|
+
const planningScopeMod = require("./planning-scope.cjs");
|
|
39
44
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
40
45
|
const stateMdSchemaMod = require("./state-md-schema.cjs");
|
|
41
46
|
const { STATE_FIELD_SCHEMA } = stateMdSchemaMod;
|
|
@@ -44,12 +49,13 @@ function formatProgressMachineSegment(percent) {
|
|
|
44
49
|
// ADR-3180 Decision 7: rounding and the 100 ceiling belong to the
|
|
45
50
|
// completion-ratio kernel. The floor is added here because this helper is
|
|
46
51
|
// also fed persisted frontmatter values (hand-editable, unlike the
|
|
47
|
-
// count-shaped entries into that kernel)
|
|
48
|
-
//
|
|
49
|
-
//
|
|
52
|
+
// count-shaped entries into that kernel). Bar and printed percent use the
|
|
53
|
+
// clamped value so the two halves of the segment can never disagree.
|
|
54
|
+
// #4294: the CELL count is the render kernel's — `renderProgressBar` holds a
|
|
55
|
+
// sub-100 percent one cell short of full, so `[██████████]` beside `95%`
|
|
56
|
+
// cannot recur here as a seventh inline copy of the rounding.
|
|
50
57
|
const clamped = Math.max(0, (0, phase_lifecycle_cjs_1.clampPercentFromFraction)(percent / 100));
|
|
51
|
-
|
|
52
|
-
return `[${'█'.repeat(filled)}${'░'.repeat(10 - filled)}] ${clamped}%`;
|
|
58
|
+
return `[${(0, phase_lifecycle_cjs_1.renderProgressBar)(clamped, 10)}] ${clamped}%`;
|
|
53
59
|
}
|
|
54
60
|
// Consumers (a future STATE.md writer that bypasses all three reintroduces the
|
|
55
61
|
// #4213 divergence class): `cmdStateUpdateProgress` and `syncCore`'s progress
|
|
@@ -60,11 +66,29 @@ function formatProgressMachineSegment(percent) {
|
|
|
60
66
|
// `syncCore`'s call here.
|
|
61
67
|
function stateReplaceProgressPercent(content, percent) {
|
|
62
68
|
const body = stripFrontmatter(content);
|
|
63
|
-
// #2177: bold `**Progress:**`
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
//
|
|
67
|
-
|
|
69
|
+
// #2177: bold `**Progress:**` takes priority over the plain `^Progress:`
|
|
70
|
+
// form, so an earlier free-text line starting with `Progress:` cannot
|
|
71
|
+
// capture the rewrite ahead of the real status line.
|
|
72
|
+
//
|
|
73
|
+
// #4243 (follow-up to #4453, maintainer ruling 2026-09-07): the bold form
|
|
74
|
+
// is also ANCHORED to line start, with same-line leading whitespace only —
|
|
75
|
+
// the exact idiom #4453 applied to stateReplaceField's bold branch. The
|
|
76
|
+
// pre-fix pattern carried no `^` and no `m` flag, so a bold percent-ish
|
|
77
|
+
// label quoted MID-SENTENCE inside prose (an Accumulated Context bullet
|
|
78
|
+
// mentioning `**Progress:**`) captured the machine-segment rewrite and
|
|
79
|
+
// destroyed the rest of its line, silently, while the real Progress line
|
|
80
|
+
// stayed stale — every caller (cmdStateUpdateProgress, syncCore's percent
|
|
81
|
+
// arm, applyPostSyncPreservation) feeds the whole document. #2177's own
|
|
82
|
+
// recorded requirements are unaffected: the frontmatter is stripped before
|
|
83
|
+
// matching (its defect was the YAML `progress:` key shadowing the body
|
|
84
|
+
// line), the suffix-preserving machine-segment swap is untouched, and the
|
|
85
|
+
// bold-beats-plain priority now governs LINE-START forms. The leading class
|
|
86
|
+
// is `[ \t]*`, deliberately NOT `\s*` — `^\s*\*\*` can consume the newlines
|
|
87
|
+
// before the label into the match and drop them on rebuild (#4010's
|
|
88
|
+
// same-line confinement hazard). `$` is explicit-and-inert (`[^\r\n]*`
|
|
89
|
+
// never crosses line terminators) and documents that the match ends at
|
|
90
|
+
// end-of-line.
|
|
91
|
+
const boldProgressPattern = /^([ \t]*\*\*Progress:\*\*[ \t]*)([^\r\n]*)$/im;
|
|
68
92
|
const plainProgressPattern = /^(Progress:[ \t]*)([^\r\n]*)/im;
|
|
69
93
|
const pattern = boldProgressPattern.test(body)
|
|
70
94
|
? boldProgressPattern
|
|
@@ -508,6 +532,72 @@ function preservedValuesEqual(a, b) {
|
|
|
508
532
|
}
|
|
509
533
|
return a === b;
|
|
510
534
|
}
|
|
535
|
+
/**
|
|
536
|
+
* #4129: the resync-arm progress merge. A resyncing write whose scan MEASURED
|
|
537
|
+
* something no longer wholesale-replaces the curated block — the declared
|
|
538
|
+
* `progress-ratchet` mergeStrategy ("completed_plans/completed_phases only ever
|
|
539
|
+
* ratchet UP toward the derived value (#2969)", state-md-schema.cts) now holds
|
|
540
|
+
* on the write path too, matching what the read path (`shouldPreserveExistingProgress`)
|
|
541
|
+
* has always enforced. Rules, mirroring the `deriveProgressKeys` branch above:
|
|
542
|
+
*
|
|
543
|
+
* - total_plans / total_phases always take the derived value (#2440 — totals
|
|
544
|
+
* correct in BOTH directions).
|
|
545
|
+
* - completed_plans / completed_phases take the derived value only when it is
|
|
546
|
+
* strictly GREATER (#2969's `>` not `>=`); else the curated value survives
|
|
547
|
+
* (a hand-corrected or previously-correct counter can never be re-derived
|
|
548
|
+
* downward — the #4129 clobber).
|
|
549
|
+
* - any other key keeps the curated value (the existing branch's convention).
|
|
550
|
+
* - percent is RECOMPUTED from the merged counters through the single kernel
|
|
551
|
+
* (`computeProgressPercent`), because either side's stored percent was
|
|
552
|
+
* computed against that side's counters and the merged block may mix them
|
|
553
|
+
* (curated completed, derived totals). Recomputation runs ONLY when the
|
|
554
|
+
* derived block itself carried a percent — an upstream withhold
|
|
555
|
+
* (#1761 milestone-unbounded, #3217 scope) nulled percent deliberately and
|
|
556
|
+
* this merge must not resurrect it.
|
|
557
|
+
*
|
|
558
|
+
* Frontmatter scalars arrive as STRINGS ("2", not 2), so every comparison
|
|
559
|
+
* coerces through `toFiniteNumber` — never a `typeof === 'number'` test
|
|
560
|
+
* (scanMeasuredSomething's own convention).
|
|
561
|
+
*/
|
|
562
|
+
function mergeResyncProgressRatchet(curatedRecord, derivedRecord) {
|
|
563
|
+
const merged = { ...derivedRecord };
|
|
564
|
+
for (const [key, value] of Object.entries(curatedRecord)) {
|
|
565
|
+
if (key === 'total_plans' || key === 'total_phases' || key === 'percent')
|
|
566
|
+
continue;
|
|
567
|
+
if (key === 'completed_plans' || key === 'completed_phases') {
|
|
568
|
+
const derivedNum = (0, state_document_cjs_2.toFiniteNumber)(derivedRecord[key]) ?? -Infinity;
|
|
569
|
+
const curatedNum = (0, state_document_cjs_2.toFiniteNumber)(value) ?? -Infinity;
|
|
570
|
+
// Ratchet up only (strictly greater, #2969); else keep curated.
|
|
571
|
+
if (derivedNum > curatedNum)
|
|
572
|
+
continue;
|
|
573
|
+
// Numerically EQUAL keeps the derived value VERBATIM. The two sides
|
|
574
|
+
// arrive in different scalar shapes (the re-parsed derived block
|
|
575
|
+
// carries string totals "2" while the curated snapshot carries numbers
|
|
576
|
+
// 2), and substituting the curated spelling over an equal derived one
|
|
577
|
+
// is a no-op in substance but a shape churn the §8.7 reporting loop
|
|
578
|
+
// would surface as a phantom `preserved-over-disagreeing-derived`
|
|
579
|
+
// warning (it diffs structurally). Only a curated counter that is
|
|
580
|
+
// STRICTLY greater replaces the derived value.
|
|
581
|
+
if (derivedNum === curatedNum)
|
|
582
|
+
continue;
|
|
583
|
+
merged[key] = value;
|
|
584
|
+
}
|
|
585
|
+
else {
|
|
586
|
+
merged[key] = value;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
if ((0, state_document_cjs_2.toFiniteNumber)(derivedRecord.percent) !== null) {
|
|
590
|
+
const recomputed = (0, state_document_cjs_2.computeProgressPercent)((0, state_document_cjs_2.toFiniteNumber)(merged.completed_plans), (0, state_document_cjs_2.toFiniteNumber)(merged.total_plans), (0, state_document_cjs_2.toFiniteNumber)(merged.completed_phases), (0, state_document_cjs_2.toFiniteNumber)(merged.total_phases), planningScopeMod.SCOPE.COMPLETE);
|
|
591
|
+
// Same verbatim rule for percent: assign only when the recomputed value
|
|
592
|
+
// numerically differs, so a string-spelled derived percent ("67") is not
|
|
593
|
+
// churned into a number-spelled 67 (phantom-divergence noise, not a
|
|
594
|
+
// change).
|
|
595
|
+
if (recomputed !== null && recomputed !== (0, state_document_cjs_2.toFiniteNumber)(merged.percent)) {
|
|
596
|
+
merged.percent = recomputed;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
return merged;
|
|
600
|
+
}
|
|
511
601
|
/**
|
|
512
602
|
* Executor for `preservation: 'preserve-always'` (ADR-3408 §8.1). Only
|
|
513
603
|
* `progress` carries this policy today. Preserves #3242/#1446/#2440/#2969
|
|
@@ -523,25 +613,39 @@ function applyPreserveAlways(field, cls, ctx) {
|
|
|
523
613
|
const derived = ctx.postFm[field];
|
|
524
614
|
const derivedMeasured = scanMeasuredSomething(cls, derived);
|
|
525
615
|
const curatedMeasured = scanMeasuredSomething(cls, curated);
|
|
526
|
-
// On a resyncing write the fresh derivation is authoritative
|
|
527
|
-
//
|
|
528
|
-
//
|
|
529
|
-
//
|
|
530
|
-
//
|
|
531
|
-
//
|
|
532
|
-
//
|
|
533
|
-
//
|
|
534
|
-
//
|
|
535
|
-
//
|
|
536
|
-
//
|
|
537
|
-
//
|
|
538
|
-
//
|
|
539
|
-
//
|
|
540
|
-
//
|
|
541
|
-
|
|
616
|
+
// On a resyncing write the fresh derivation is authoritative in two cases
|
|
617
|
+
// (#3756 / ADR-3473 §8.6, unchanged): when the caller EXPLICITLY named a
|
|
618
|
+
// progress-affecting field (`preserve-always`'s contract is "never
|
|
619
|
+
// overwrite unless the caller explicitly names this field" — `state update
|
|
620
|
+
// Progress` is exactly that naming, pre-existing #3242 behavior), and when
|
|
621
|
+
// the derivation measured something the curated block did not (an
|
|
622
|
+
// unmeasured CURATED block is not worth protecting). The unmeasured-DERIVED
|
|
623
|
+
// guard also stands: an incidental resync (e.g. `state add-decision`, whose
|
|
624
|
+
// `resync` defaults true for reasons that have nothing to do with
|
|
625
|
+
// `progress`) that measured nothing must not drop a real curated block
|
|
626
|
+
// (#3756's archived-milestone case) — that falls through to the wholesale
|
|
627
|
+
// restore below.
|
|
628
|
+
//
|
|
629
|
+
// #4129 narrows the remaining arm. A resyncing write whose scan MEASURED
|
|
630
|
+
// something while the curated block is also real previously wholesale-
|
|
631
|
+
// replaced the curated block with the derived one — no monotonic guard, so
|
|
632
|
+
// any under-counting derivation (a stale-dated verification, #2348) silently
|
|
633
|
+
// reverted every hand-correction and every correct value an earlier write
|
|
634
|
+
// had persisted, while the read path (`shouldPreserveExistingProgress`)
|
|
635
|
+
// kept reporting the higher stored counters. That arm now falls through to
|
|
636
|
+
// `mergeResyncProgressRatchet` — the declared `progress-ratchet`
|
|
637
|
+
// mergeStrategy, finally enforced on the write path: totals derived both
|
|
638
|
+
// directions (#2440), completed counters up-only (#2969), percent
|
|
639
|
+
// recomputed from the merged counters.
|
|
640
|
+
if (ctx.resync && (ctx.explicitProgressField || (derivedMeasured && !curatedMeasured)))
|
|
542
641
|
return;
|
|
543
642
|
let next;
|
|
544
|
-
if (cls.mergeStrategy === 'progress-ratchet' && ctx.
|
|
643
|
+
if (cls.mergeStrategy === 'progress-ratchet' && ctx.resync && derived && derivedMeasured && curatedMeasured) {
|
|
644
|
+
// #4129 resync arm — see mergeResyncProgressRatchet's doc. Reached only
|
|
645
|
+
// after the early-out above, so curatedMeasured is guaranteed true here.
|
|
646
|
+
next = mergeResyncProgressRatchet(curated, (derived ?? {}));
|
|
647
|
+
}
|
|
648
|
+
else if (cls.mergeStrategy === 'progress-ratchet' && ctx.deriveProgressKeys && derived && derivedMeasured) {
|
|
545
649
|
// #2440: total_plans and total_phases always take the derived (post-sync)
|
|
546
650
|
// value even under !resync. This is used by cmdStatePlannedPhase where
|
|
547
651
|
// total_plans must correct upward after plans are added. For body-only
|
|
@@ -824,7 +928,17 @@ function beginPhaseCore(content, intent, deps) {
|
|
|
824
928
|
const focusLabel = intent.phaseName
|
|
825
929
|
? `Phase ${intent.phaseNumber} — ${intent.phaseName}`
|
|
826
930
|
: `Phase ${intent.phaseNumber}`;
|
|
827
|
-
|
|
931
|
+
// #4469: anchored to line start with same-line whitespace only, mirroring
|
|
932
|
+
// #4243/PR #4453's fix to stateReplaceField's bold branch. The pre-fix
|
|
933
|
+
// pattern carried no `^`/`m` and used `\s*` (crosses newlines), so a bold
|
|
934
|
+
// `**Current focus:**` quoted mid-sentence elsewhere in the body (e.g. an
|
|
935
|
+
// Accumulated Context bullet) matched first and had the rest of its line
|
|
936
|
+
// silently overwritten with the new focus label -- the same #4010
|
|
937
|
+
// data-loss class. `[ \t]*` (not `\s*`) avoids consuming the newlines
|
|
938
|
+
// before the label into the match; `$` documents the match ends at
|
|
939
|
+
// end-of-line (inert here since `.` never crosses line terminators
|
|
940
|
+
// without `/s`, which is not set).
|
|
941
|
+
const focusPattern = /^([ \t]*\*\*Current focus:\*\*[ \t]*)(.*)$/im;
|
|
828
942
|
if (focusPattern.test(body)) {
|
|
829
943
|
body = body.replace(focusPattern, (_match, prefix) => `${prefix}${focusLabel}`);
|
|
830
944
|
updated.push('Current focus');
|