mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-05 00:03:15 +01:00
autoplan: run-state fields, plan-text hashing, version migration and admission modules
RunState gains gstack_version, plan_input/heading, scope_flags, plan_revision, amendments and plan_reality; voices record receipt kind and reviewed hash. New pure modules: Implementation-plan review hash, scaffold and drift lines (B1c); gstack_version stamp and legacy decision-id migration (B1a); install-verdict and Bun-minimum admission with a local verdict shim until lane A's lib/install-verdict.ts lands. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> bin/gstack-autoplan-snapshot.ts exports its section scanner and review projection, and initializes only a plan with no section headings by wrapping it. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
4128ba751b
commit
ee7b341e5d
5 files changed
+241
-4
No files matched your search
@@ -66,7 +66,8 @@ reviewing this plan. You have NOT seen any prior review. Evaluate:
|
||||
For each finding: what's wrong, severity, and the fix.`
|
||||
};
|
||||
|
||||
function implementationBounds(plan: string) {
|
||||
/** The section headings outside code fences, in order (the runner's PLAN_SECTIONS_INVALID diagnosis reads these). */
|
||||
export function sectionHeadings(plan: string) {
|
||||
const boundaries: Array<{ name: string; start: number; end: number }> = [];
|
||||
let offset = 0;
|
||||
let fence: { char: string; length: number } | null = null;
|
||||
@@ -86,6 +87,11 @@ function implementationBounds(plan: string) {
|
||||
}
|
||||
offset += raw.length;
|
||||
}
|
||||
return boundaries;
|
||||
}
|
||||
|
||||
function implementationBounds(plan: string) {
|
||||
const boundaries = sectionHeadings(plan);
|
||||
if (boundaries.length !== 2 || boundaries[0]!.name !== 'Implementation plan' || boundaries[1]!.name !== 'Review record') {
|
||||
throw new Error('Expected one Implementation plan section followed by one Review record section outside Markdown code/quotes');
|
||||
}
|
||||
@@ -149,7 +155,7 @@ export function acceptedBlocks(text: string): Map<string, AcceptedBlock> {
|
||||
|
||||
// Marker lines belong to the author's retention record, not blind review data.
|
||||
// Keep every requirement-body byte, including line endings and literal examples.
|
||||
function implementationForReview(source: string): string {
|
||||
export function implementationForReview(source: string): string {
|
||||
let result = ''; let offset = 0;
|
||||
for (const block of acceptedBlocks(source).values()) {
|
||||
if (block.none) throw new Error('No-change record does not belong in Implementation plan');
|
||||
@@ -411,7 +417,9 @@ export function initializePlan(sourcePlan: string, activePlan: string, restorePa
|
||||
if (!text.trim() || !Buffer.from(text).equals(original)) throw new Error('Initialization source must be nonempty UTF-8 text');
|
||||
let plan = text;
|
||||
try { extractImplementationPlan(plan); }
|
||||
catch {
|
||||
catch (error) {
|
||||
// Only a plan with no section headings is wrapped; a present-but-wrong or empty section reports its own error.
|
||||
if (sectionHeadings(text).length) throw error;
|
||||
plan = `## Implementation plan\n${text}${text.endsWith('\n') ? '' : '\n'}## Review record\n`;
|
||||
// Partial/duplicate boundaries and unclosed fences remain errors, not raw-plan fallbacks.
|
||||
extractImplementationPlan(plan);
|
||||
|
||||
Reference in new issue
Block a user