openxiangda-devkit-core 2.0.0-alpha.115 → 2.0.0-alpha.118
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/dist/app-spec.d.ts +23 -11
- package/dist/app-spec.d.ts.map +1 -1
- package/dist/app-spec.js +171 -52
- package/dist/app-spec.js.map +1 -1
- package/dist/application-services.d.ts +290 -23
- package/dist/application-services.d.ts.map +1 -1
- package/dist/application-services.js +174 -79
- package/dist/application-services.js.map +1 -1
- package/dist/backend-image-build.js +6 -11
- package/dist/backend-image-build.js.map +1 -1
- package/dist/command-process.d.ts +14 -0
- package/dist/command-process.d.ts.map +1 -0
- package/dist/command-process.js +51 -0
- package/dist/command-process.js.map +1 -0
- package/dist/command-registry.d.ts +2 -2
- package/dist/command-registry.js +1 -1
- package/dist/command-registry.js.map +1 -1
- package/dist/compiler/ai-catalog.d.ts.map +1 -1
- package/dist/compiler/ai-catalog.js +2 -1
- package/dist/compiler/ai-catalog.js.map +1 -1
- package/dist/compiler/bundle.d.ts.map +1 -1
- package/dist/compiler/bundle.js +2 -1
- package/dist/compiler/bundle.js.map +1 -1
- package/dist/compiler/config.d.ts.map +1 -1
- package/dist/compiler/config.js +14 -7
- package/dist/compiler/config.js.map +1 -1
- package/dist/compiler/permission-review.d.ts.map +1 -1
- package/dist/configuration-preflight.d.ts +7 -0
- package/dist/configuration-preflight.d.ts.map +1 -0
- package/dist/configuration-preflight.js +13 -0
- package/dist/configuration-preflight.js.map +1 -0
- package/dist/control-plane-client.d.ts +8 -1
- package/dist/control-plane-client.d.ts.map +1 -1
- package/dist/control-plane-client.js +13 -0
- package/dist/control-plane-client.js.map +1 -1
- package/dist/delivery-cache.d.ts +34 -0
- package/dist/delivery-cache.d.ts.map +1 -0
- package/dist/delivery-cache.js +186 -0
- package/dist/delivery-cache.js.map +1 -0
- package/dist/delivery-source.d.ts +17 -0
- package/dist/delivery-source.d.ts.map +1 -0
- package/dist/delivery-source.js +85 -0
- package/dist/delivery-source.js.map +1 -0
- package/dist/deployment-observer.d.ts +14 -0
- package/dist/deployment-observer.d.ts.map +1 -0
- package/dist/deployment-observer.js +68 -0
- package/dist/deployment-observer.js.map +1 -0
- package/dist/deployment.d.ts +13 -0
- package/dist/deployment.d.ts.map +1 -1
- package/dist/deployment.js +34 -7
- package/dist/deployment.js.map +1 -1
- package/dist/developer-operations.d.ts +147 -43
- package/dist/developer-operations.d.ts.map +1 -1
- package/dist/developer-operations.js +22 -3
- package/dist/developer-operations.js.map +1 -1
- package/dist/development-lifecycle.d.ts +48 -0
- package/dist/development-lifecycle.d.ts.map +1 -0
- package/dist/development-lifecycle.js +180 -0
- package/dist/development-lifecycle.js.map +1 -0
- package/dist/documentation.d.ts +4 -4
- package/dist/documentation.d.ts.map +1 -1
- package/dist/documentation.js +4 -5
- package/dist/documentation.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/operation-progress.d.ts +26 -0
- package/dist/operation-progress.d.ts.map +1 -0
- package/dist/operation-progress.js +92 -0
- package/dist/operation-progress.js.map +1 -0
- package/package.json +2 -2
package/dist/app-spec.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export declare const APP_SPEC_SCHEMAS: {
|
|
|
4
4
|
readonly capability: "openxiangda.appspec/capability/v1";
|
|
5
5
|
readonly change: "openxiangda.appspec/change/v1";
|
|
6
6
|
readonly decision: "openxiangda.appspec/decision/v1";
|
|
7
|
-
readonly context: "openxiangda.appspec/context/
|
|
7
|
+
readonly context: "openxiangda.appspec/context/v3";
|
|
8
8
|
};
|
|
9
9
|
export declare const APP_SPEC_LIMITS: {
|
|
10
10
|
readonly maximumFiles: 128;
|
|
@@ -57,8 +57,8 @@ export interface AppSpecDocumentSummary {
|
|
|
57
57
|
export interface AppSpecContext {
|
|
58
58
|
schemaVersion: typeof APP_SPEC_SCHEMAS.context;
|
|
59
59
|
enabled: boolean;
|
|
60
|
-
mode: "
|
|
61
|
-
releaseGate:
|
|
60
|
+
mode: "guided";
|
|
61
|
+
releaseGate: true;
|
|
62
62
|
root: "appspec";
|
|
63
63
|
selector: string | null;
|
|
64
64
|
contract: AppSpecContractIndex;
|
|
@@ -74,6 +74,12 @@ export interface AppSpecContext {
|
|
|
74
74
|
activeChanges: AppSpecDocument[];
|
|
75
75
|
archivedChanges: AppSpecDocument[];
|
|
76
76
|
decisions: AppSpecDocument[];
|
|
77
|
+
historyPage: {
|
|
78
|
+
offset: number;
|
|
79
|
+
limit: number;
|
|
80
|
+
total: number;
|
|
81
|
+
nextOffset: number | null;
|
|
82
|
+
};
|
|
77
83
|
contextBudget: {
|
|
78
84
|
maximumBytes: number;
|
|
79
85
|
contentBytes: number;
|
|
@@ -123,7 +129,7 @@ export interface CloseAppSpecChangeInput {
|
|
|
123
129
|
contract: AppSpecContractIndex;
|
|
124
130
|
}
|
|
125
131
|
export declare function initializeAppSpec(input: InitializeAppSpecInput): {
|
|
126
|
-
schemaVersion: "openxiangda.appspec/context/
|
|
132
|
+
schemaVersion: "openxiangda.appspec/context/v3";
|
|
127
133
|
enabled: boolean;
|
|
128
134
|
advisory: boolean;
|
|
129
135
|
releaseGate: boolean;
|
|
@@ -131,14 +137,14 @@ export declare function initializeAppSpec(input: InitializeAppSpecInput): {
|
|
|
131
137
|
existing: string[];
|
|
132
138
|
};
|
|
133
139
|
export declare function createAppSpecCapability(input: CreateAppSpecCapabilityInput): {
|
|
134
|
-
schemaVersion: "openxiangda.appspec/context/
|
|
140
|
+
schemaVersion: "openxiangda.appspec/context/v3";
|
|
135
141
|
enabled: boolean;
|
|
136
142
|
advisory: boolean;
|
|
137
143
|
releaseGate: boolean;
|
|
138
144
|
created: string;
|
|
139
145
|
};
|
|
140
146
|
export declare function createAppSpecChange(input: CreateAppSpecChangeInput): {
|
|
141
|
-
schemaVersion: "openxiangda.appspec/context/
|
|
147
|
+
schemaVersion: "openxiangda.appspec/context/v3";
|
|
142
148
|
enabled: boolean;
|
|
143
149
|
advisory: boolean;
|
|
144
150
|
releaseGate: boolean;
|
|
@@ -147,7 +153,7 @@ export declare function createAppSpecChange(input: CreateAppSpecChangeInput): {
|
|
|
147
153
|
status: string;
|
|
148
154
|
};
|
|
149
155
|
export declare function closeAppSpecChange(input: CloseAppSpecChangeInput): {
|
|
150
|
-
schemaVersion: "openxiangda.appspec/context/
|
|
156
|
+
schemaVersion: "openxiangda.appspec/context/v3";
|
|
151
157
|
enabled: boolean;
|
|
152
158
|
advisory: boolean;
|
|
153
159
|
releaseGate: boolean;
|
|
@@ -156,7 +162,7 @@ export declare function closeAppSpecChange(input: CloseAppSpecChangeInput): {
|
|
|
156
162
|
converged: boolean;
|
|
157
163
|
diagnostics: Diagnostic[];
|
|
158
164
|
} | {
|
|
159
|
-
schemaVersion: "openxiangda.appspec/context/
|
|
165
|
+
schemaVersion: "openxiangda.appspec/context/v3";
|
|
160
166
|
enabled: boolean;
|
|
161
167
|
advisory: boolean;
|
|
162
168
|
releaseGate: boolean;
|
|
@@ -165,7 +171,7 @@ export declare function closeAppSpecChange(input: CloseAppSpecChangeInput): {
|
|
|
165
171
|
converged: boolean;
|
|
166
172
|
diagnostics: Diagnostic[];
|
|
167
173
|
};
|
|
168
|
-
export declare function inspectAppSpec(root: string, contract: AppSpecContractIndex, selector?: string): AppSpecContext;
|
|
174
|
+
export declare function inspectAppSpec(root: string, contract: AppSpecContractIndex, selector?: string, historyOffset?: number): AppSpecContext;
|
|
169
175
|
export declare function advisoryAppSpecDiagnostics(diagnostics: Diagnostic[]): {
|
|
170
176
|
severity: "info" | "warning";
|
|
171
177
|
remediation: string;
|
|
@@ -179,10 +185,16 @@ export declare function advisoryAppSpecDiagnostics(diagnostics: Diagnostic[]): {
|
|
|
179
185
|
}[];
|
|
180
186
|
export declare function summarizeAppSpecContext(context: AppSpecContext): {
|
|
181
187
|
enabled: boolean;
|
|
182
|
-
mode: "
|
|
183
|
-
releaseGate:
|
|
188
|
+
mode: "guided";
|
|
189
|
+
releaseGate: true;
|
|
184
190
|
workspaceDigest: string | null;
|
|
185
191
|
selectionDigest: string | null;
|
|
192
|
+
historyPage: {
|
|
193
|
+
offset: number;
|
|
194
|
+
limit: number;
|
|
195
|
+
total: number;
|
|
196
|
+
nextOffset: number | null;
|
|
197
|
+
};
|
|
186
198
|
contextBudget: {
|
|
187
199
|
maximumBytes: number;
|
|
188
200
|
contentBytes: number;
|
package/dist/app-spec.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-spec.d.ts","sourceRoot":"","sources":["../src/app-spec.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"app-spec.d.ts","sourceRoot":"","sources":["../src/app-spec.ts"],"names":[],"mappings":"AAcA,OAAO,EACL,eAAe,EACf,KAAK,UAAU,EAChB,MAAM,uBAAuB,CAAC;AAE/B,eAAO,MAAM,gBAAgB;;;;;;CAMnB,CAAC;AAEX,eAAO,MAAM,eAAe;;;;;;;CAOlB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAC7C,MAAM,MAAM,wBAAwB,GAAG,SAAS,GAAG,QAAQ,GAAG,gBAAgB,CAAC;AAC/E,MAAM,MAAM,mBAAmB,GAAG,KAAK,GAAG,YAAY,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE/E,KAAK,aAAa,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC;AAEjD,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,mBAAmB,CAAC;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACxC,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,EAAE;QACV,YAAY,EAAE,MAAM,EAAE,CAAC;QACvB,YAAY,EAAE,MAAM,EAAE,CAAC;QACvB,SAAS,EAAE,MAAM,EAAE,CAAC;QACpB,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,SAAS,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;IACF,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,mBAAmB,CAAC;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,uBAAuB,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,cAAc;IAC7B,aAAa,EAAE,OAAO,gBAAgB,CAAC,OAAO,CAAC;IAC/C,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,QAAQ,CAAC;IACf,WAAW,EAAE,IAAI,CAAC;IAClB,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,KAAK,EAAE;QACL,WAAW,EAAE,sBAAsB,GAAG,IAAI,CAAC;QAC3C,YAAY,EAAE,sBAAsB,EAAE,CAAC;QACvC,aAAa,EAAE,sBAAsB,EAAE,CAAC;QACxC,SAAS,EAAE,sBAAsB,EAAE,CAAC;QACpC,OAAO,EAAE,sBAAsB,EAAE,CAAC;KACnC,CAAC;IACF,WAAW,EAAE,eAAe,GAAG,IAAI,CAAC;IACpC,YAAY,EAAE,eAAe,EAAE,CAAC;IAChC,aAAa,EAAE,eAAe,EAAE,CAAC;IACjC,eAAe,EAAE,eAAe,EAAE,CAAC;IACnC,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,WAAW,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IACzF,aAAa,EAAE;QACb,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,OAAO,CAAC;QACnB,OAAO,EAAE,sBAAsB,EAAE,CAAC;KACnC,CAAC;IACF,KAAK,EAAE;QACL,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;QACtB,cAAc,EAAE,MAAM,CAAC;QACvB,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;QACrB,mBAAmB,EAAE,MAAM,CAAC;KAC7B,CAAC;IACF,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,WAAW,EAAE,UAAU,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,4BAA6B,SAAQ,sBAAsB;IAC1E,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,wBAAyB,SAAQ,sBAAsB;IACtE,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC,wBAAwB,EAAE,SAAS,CAAC,CAAC;IAC3D,QAAQ,EAAE,oBAAoB,CAAC;CAChC;AASD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB;;;;;;;EA8B9D;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,4BAA4B;;;;;;EA0B1E;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB;;;;;;;;EAoClE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB;;;;;;;;;;;;;;;;;;EA2GhE;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,oBAAoB,EAC9B,QAAQ,CAAC,EAAE,MAAM,EACjB,aAAa,SAAI,GAChB,cAAc,CAmFhB;AAED,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,UAAU,EAAE;;;;;;;;;;IASnE;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,cAAc;;;;;;;gBAjXtC,MAAM;eAAS,MAAM;eAAS,MAAM;oBAAc,MAAM,GAAG,IAAI;;;sBAEtE,MAAM;sBACN,MAAM;mBACT,OAAO;iBACT,sBAAsB,EAAE;;;eAG1B,MAAM;eACN,MAAM;sBACC,MAAM;uBACL,MAAM;wBACL,MAAM;mBACX,MAAM;sBACH,MAAM;6BACC,MAAM;;;;;;;;EAqX9B"}
|
package/dist/app-spec.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, renameSync, writeFileSync, } from "node:fs";
|
|
2
|
+
import { existsSync, openSync, readSync, closeSync, lstatSync, mkdirSync, readFileSync, readdirSync, renameSync, writeFileSync, } from "node:fs";
|
|
3
3
|
import { basename, dirname, join, relative, resolve } from "node:path";
|
|
4
4
|
import { SCHEMA_VERSIONS, } from "openxiangda-contracts";
|
|
5
5
|
export const APP_SPEC_SCHEMAS = {
|
|
@@ -7,7 +7,7 @@ export const APP_SPEC_SCHEMAS = {
|
|
|
7
7
|
capability: "openxiangda.appspec/capability/v1",
|
|
8
8
|
change: "openxiangda.appspec/change/v1",
|
|
9
9
|
decision: "openxiangda.appspec/decision/v1",
|
|
10
|
-
context: "openxiangda.appspec/context/
|
|
10
|
+
context: "openxiangda.appspec/context/v3",
|
|
11
11
|
};
|
|
12
12
|
export const APP_SPEC_LIMITS = {
|
|
13
13
|
maximumFiles: 128,
|
|
@@ -49,8 +49,8 @@ export function initializeAppSpec(input) {
|
|
|
49
49
|
return {
|
|
50
50
|
schemaVersion: APP_SPEC_SCHEMAS.context,
|
|
51
51
|
enabled: true,
|
|
52
|
-
advisory:
|
|
53
|
-
releaseGate:
|
|
52
|
+
advisory: false,
|
|
53
|
+
releaseGate: true,
|
|
54
54
|
created,
|
|
55
55
|
existing,
|
|
56
56
|
};
|
|
@@ -72,8 +72,8 @@ export function createAppSpecCapability(input) {
|
|
|
72
72
|
return {
|
|
73
73
|
schemaVersion: APP_SPEC_SCHEMAS.context,
|
|
74
74
|
enabled: true,
|
|
75
|
-
advisory:
|
|
76
|
-
releaseGate:
|
|
75
|
+
advisory: false,
|
|
76
|
+
releaseGate: true,
|
|
77
77
|
created: relativePath(input.root, path),
|
|
78
78
|
};
|
|
79
79
|
}
|
|
@@ -82,6 +82,9 @@ export function createAppSpecChange(input) {
|
|
|
82
82
|
if (!CHANGE_ID.test(input.id)) {
|
|
83
83
|
throw stableError("APPSPEC_CHANGE_ID_INVALID", input.id);
|
|
84
84
|
}
|
|
85
|
+
if (historyCandidates(input.root, input.id, 0, []).paths.some(path => basename(path) === `${input.id}.md`)) {
|
|
86
|
+
throw stableError('APPSPEC_HISTORY_CHANGE_EXISTS', input.id);
|
|
87
|
+
}
|
|
85
88
|
if (!input.title.trim())
|
|
86
89
|
throw stableError("APPSPEC_TITLE_REQUIRED", input.id);
|
|
87
90
|
const risk = input.risk || "L1";
|
|
@@ -102,8 +105,8 @@ export function createAppSpecChange(input) {
|
|
|
102
105
|
return {
|
|
103
106
|
schemaVersion: APP_SPEC_SCHEMAS.context,
|
|
104
107
|
enabled: true,
|
|
105
|
-
advisory:
|
|
106
|
-
releaseGate:
|
|
108
|
+
advisory: false,
|
|
109
|
+
releaseGate: true,
|
|
107
110
|
created: relativePath(input.root, path),
|
|
108
111
|
risk,
|
|
109
112
|
status: "draft",
|
|
@@ -171,8 +174,8 @@ export function closeAppSpecChange(input) {
|
|
|
171
174
|
return {
|
|
172
175
|
schemaVersion: APP_SPEC_SCHEMAS.context,
|
|
173
176
|
enabled: true,
|
|
174
|
-
advisory:
|
|
175
|
-
releaseGate:
|
|
177
|
+
advisory: false,
|
|
178
|
+
releaseGate: true,
|
|
176
179
|
archived: null,
|
|
177
180
|
status: document.status,
|
|
178
181
|
converged: false,
|
|
@@ -186,15 +189,15 @@ export function closeAppSpecChange(input) {
|
|
|
186
189
|
return {
|
|
187
190
|
schemaVersion: APP_SPEC_SCHEMAS.context,
|
|
188
191
|
enabled: true,
|
|
189
|
-
advisory:
|
|
190
|
-
releaseGate:
|
|
192
|
+
advisory: false,
|
|
193
|
+
releaseGate: true,
|
|
191
194
|
archived: relativePath(input.root, target),
|
|
192
195
|
status: "archived",
|
|
193
196
|
converged: true,
|
|
194
197
|
diagnostics,
|
|
195
198
|
};
|
|
196
199
|
}
|
|
197
|
-
export function inspectAppSpec(root, contract, selector) {
|
|
200
|
+
export function inspectAppSpec(root, contract, selector, historyOffset = 0) {
|
|
198
201
|
const paths = appSpecPaths(root);
|
|
199
202
|
if (!existsSync(paths.root))
|
|
200
203
|
return emptyContext(contract, selector);
|
|
@@ -203,7 +206,7 @@ export function inspectAppSpec(root, contract, selector) {
|
|
|
203
206
|
diagnostics.push(issue("error", "APPSPEC_ROOT_INVALID", "appspec 必须是普通目录,不能是符号链接", "appspec"));
|
|
204
207
|
return emptyContext(contract, selector, diagnostics, true);
|
|
205
208
|
}
|
|
206
|
-
const collection = collectDocuments(root, diagnostics);
|
|
209
|
+
const collection = collectDocuments(root, diagnostics, selector, historyOffset);
|
|
207
210
|
const application = collection.app[0] || null;
|
|
208
211
|
validateDocuments(collection, contract, diagnostics);
|
|
209
212
|
const selected = selectContext(collection, selector, diagnostics);
|
|
@@ -215,7 +218,7 @@ export function inspectAppSpec(root, contract, selector) {
|
|
|
215
218
|
...collection.decisions,
|
|
216
219
|
];
|
|
217
220
|
const index = summarizeCollection(collection);
|
|
218
|
-
const workspaceDigest = digestDocuments(allDocuments, contract);
|
|
221
|
+
const workspaceDigest = digestDocuments(allDocuments.filter(document => !document.path.startsWith("appspec/changes/history/")), contract);
|
|
219
222
|
const selectionDocuments = selectedDocuments(application, selected);
|
|
220
223
|
const selectionDigest = allDocuments.length === 0
|
|
221
224
|
? null
|
|
@@ -227,8 +230,8 @@ export function inspectAppSpec(root, contract, selector) {
|
|
|
227
230
|
return {
|
|
228
231
|
schemaVersion: APP_SPEC_SCHEMAS.context,
|
|
229
232
|
enabled: true,
|
|
230
|
-
mode: "
|
|
231
|
-
releaseGate:
|
|
233
|
+
mode: "guided",
|
|
234
|
+
releaseGate: true,
|
|
232
235
|
root: "appspec",
|
|
233
236
|
selector: selector || null,
|
|
234
237
|
contract,
|
|
@@ -238,16 +241,17 @@ export function inspectAppSpec(root, contract, selector) {
|
|
|
238
241
|
activeChanges: budgeted.activeChanges,
|
|
239
242
|
archivedChanges: budgeted.archivedChanges,
|
|
240
243
|
decisions: budgeted.decisions,
|
|
244
|
+
historyPage: collection.historyPage,
|
|
241
245
|
contextBudget: budgeted.contextBudget,
|
|
242
246
|
stats: {
|
|
243
247
|
files: allDocuments.length,
|
|
244
248
|
bytes: collection.bytes,
|
|
245
249
|
capabilities: collection.capabilities.length,
|
|
246
250
|
activeChanges: collection.activeChanges.length,
|
|
247
|
-
historyChanges: collection.
|
|
251
|
+
historyChanges: collection.historyPage.total,
|
|
248
252
|
decisions: collection.decisions.length,
|
|
249
|
-
requirements: unique(collection.capabilities.flatMap(document => document.requirementIds)).length,
|
|
250
|
-
acceptanceScenarios: unique(collection.capabilities.flatMap(document => document.acceptanceIds)).length,
|
|
253
|
+
requirements: unique([...collection.app, ...collection.capabilities].flatMap(document => document.requirementIds)).length,
|
|
254
|
+
acceptanceScenarios: unique([...collection.app, ...collection.capabilities].flatMap(document => document.acceptanceIds)).length,
|
|
251
255
|
},
|
|
252
256
|
workspaceDigest,
|
|
253
257
|
selectionDigest,
|
|
@@ -259,7 +263,7 @@ export function advisoryAppSpecDiagnostics(diagnostics) {
|
|
|
259
263
|
...diagnostic,
|
|
260
264
|
severity: diagnostic.severity === "error" ? "warning" : diagnostic.severity,
|
|
261
265
|
remediation: diagnostic.remediation ||
|
|
262
|
-
"
|
|
266
|
+
"运行 openxiangda spec check 查看文档诊断;普通 check 可以继续,正式发布按阶段核对需求与验收",
|
|
263
267
|
}));
|
|
264
268
|
}
|
|
265
269
|
export function summarizeAppSpecContext(context) {
|
|
@@ -269,6 +273,7 @@ export function summarizeAppSpecContext(context) {
|
|
|
269
273
|
releaseGate: context.releaseGate,
|
|
270
274
|
workspaceDigest: context.workspaceDigest,
|
|
271
275
|
selectionDigest: context.selectionDigest,
|
|
276
|
+
historyPage: context.historyPage,
|
|
272
277
|
contextBudget: context.contextBudget,
|
|
273
278
|
stats: context.stats,
|
|
274
279
|
diagnostics: {
|
|
@@ -285,8 +290,8 @@ function emptyContext(contract, selector, diagnostics = [], enabled = false) {
|
|
|
285
290
|
return {
|
|
286
291
|
schemaVersion: APP_SPEC_SCHEMAS.context,
|
|
287
292
|
enabled,
|
|
288
|
-
mode: "
|
|
289
|
-
releaseGate:
|
|
293
|
+
mode: "guided",
|
|
294
|
+
releaseGate: true,
|
|
290
295
|
root: "appspec",
|
|
291
296
|
selector: selector || null,
|
|
292
297
|
contract,
|
|
@@ -302,6 +307,7 @@ function emptyContext(contract, selector, diagnostics = [], enabled = false) {
|
|
|
302
307
|
activeChanges: [],
|
|
303
308
|
archivedChanges: [],
|
|
304
309
|
decisions: [],
|
|
310
|
+
historyPage: { offset: 0, limit: 50, total: 0, nextOffset: null },
|
|
305
311
|
contextBudget: {
|
|
306
312
|
maximumBytes: APP_SPEC_LIMITS.maximumContextBytes,
|
|
307
313
|
contentBytes: 0,
|
|
@@ -323,7 +329,55 @@ function emptyContext(contract, selector, diagnostics = [], enabled = false) {
|
|
|
323
329
|
diagnostics,
|
|
324
330
|
};
|
|
325
331
|
}
|
|
326
|
-
function
|
|
332
|
+
function historyCandidates(root, selector, offset, diagnostics) {
|
|
333
|
+
if (!Number.isSafeInteger(offset) || offset < 0)
|
|
334
|
+
throw stableError('APPSPEC_HISTORY_OFFSET_INVALID', String(offset));
|
|
335
|
+
const directory = appSpecPaths(root).history;
|
|
336
|
+
const all = [];
|
|
337
|
+
let selected;
|
|
338
|
+
const started = Date.now();
|
|
339
|
+
if (existsSync(directory)) {
|
|
340
|
+
if (!isRegularDirectory(directory))
|
|
341
|
+
diagnostics.push(issue('error', 'APPSPEC_DIRECTORY_INVALID', '历史目录必须是普通目录', 'appspec/changes/history'));
|
|
342
|
+
else {
|
|
343
|
+
const years = readdirSync(directory, { withFileTypes: true }).sort((a, b) => b.name.localeCompare(a.name));
|
|
344
|
+
for (const year of years.slice(0, 256)) {
|
|
345
|
+
const path = join(directory, year.name);
|
|
346
|
+
if (year.isSymbolicLink()) {
|
|
347
|
+
diagnostics.push(issue('error', 'APPSPEC_SYMLINK_FORBIDDEN', '历史记录不能使用符号链接', relativePath(root, path)));
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
if (year.isFile() && year.name.endsWith('.md'))
|
|
351
|
+
all.push(path);
|
|
352
|
+
else if (year.isDirectory()) {
|
|
353
|
+
// 稳定 ID 的读取不依赖当前索引页;正文仍受单文件与上下文预算约束。
|
|
354
|
+
const direct = selector && CHANGE_ID.test(selector) ? join(path, `${selector}.md`) : undefined;
|
|
355
|
+
if (direct && existsSync(direct))
|
|
356
|
+
selected = direct;
|
|
357
|
+
if (all.length >= 100_000 || Date.now() - started > 5_000)
|
|
358
|
+
continue;
|
|
359
|
+
for (const entry of readdirSync(path, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
360
|
+
if (all.length >= 100_000)
|
|
361
|
+
break;
|
|
362
|
+
const file = join(path, entry.name);
|
|
363
|
+
if (entry.isFile() && entry.name.endsWith('.md'))
|
|
364
|
+
all.push(file);
|
|
365
|
+
else if (entry.isSymbolicLink() || entry.isDirectory())
|
|
366
|
+
diagnostics.push(issue('warning', 'APPSPEC_HISTORY_ENTRY_INVALID', '历史只索引 history/<year>/*.md 普通文件', relativePath(root, file)));
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
if (years.length > 256 || all.length >= 100_000 || Date.now() - started > 5_000)
|
|
371
|
+
diagnostics.push(issue('warning', 'APPSPEC_HISTORY_INDEX_LIMIT', '历史索引达到读取预算;记录仍保留,可用稳定变更 ID 读取正文', 'appspec/changes/history'));
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
const paths = all.slice(offset, offset + 50);
|
|
375
|
+
const match = selected || (selector ? all.find(path => basename(path) === `${selector}.md`) : undefined);
|
|
376
|
+
if (match && !paths.includes(match))
|
|
377
|
+
paths.push(match);
|
|
378
|
+
return { paths, page: { offset, limit: 50, total: all.length, nextOffset: offset + 50 < all.length ? offset + 50 : null } };
|
|
379
|
+
}
|
|
380
|
+
function collectDocuments(root, diagnostics, selector, historyOffset = 0) {
|
|
327
381
|
const paths = appSpecPaths(root);
|
|
328
382
|
const result = {
|
|
329
383
|
app: [],
|
|
@@ -332,6 +386,7 @@ function collectDocuments(root, diagnostics) {
|
|
|
332
386
|
history: [],
|
|
333
387
|
decisions: [],
|
|
334
388
|
bytes: 0,
|
|
389
|
+
historyPage: { offset: historyOffset, limit: 50, total: 0, nextOffset: null },
|
|
335
390
|
};
|
|
336
391
|
const candidates = [];
|
|
337
392
|
if (existsSync(paths.app))
|
|
@@ -342,10 +397,6 @@ function collectDocuments(root, diagnostics) {
|
|
|
342
397
|
})), ...markdownFiles(paths.activeChanges, false, diagnostics, root).map(path => ({
|
|
343
398
|
path,
|
|
344
399
|
kind: "change",
|
|
345
|
-
})), ...markdownFiles(paths.history, true, diagnostics, root).map(path => ({
|
|
346
|
-
path,
|
|
347
|
-
kind: "change",
|
|
348
|
-
history: true,
|
|
349
400
|
})), ...markdownFiles(paths.decisions, false, diagnostics, root).map(path => ({
|
|
350
401
|
path,
|
|
351
402
|
kind: "decision",
|
|
@@ -354,7 +405,11 @@ function collectDocuments(root, diagnostics) {
|
|
|
354
405
|
diagnostics.push(issue("error", "APPSPEC_FILE_LIMIT_EXCEEDED", `AppSpec 文件数 ${candidates.length} 超过上限 ${APP_SPEC_LIMITS.maximumFiles}`, "appspec"));
|
|
355
406
|
candidates.splice(APP_SPEC_LIMITS.maximumFiles);
|
|
356
407
|
}
|
|
357
|
-
|
|
408
|
+
const history = historyCandidates(root, selector, historyOffset, diagnostics);
|
|
409
|
+
result.historyPage = history.page;
|
|
410
|
+
candidates.push(...history.paths.map(path => ({ path, kind: "change", history: true })));
|
|
411
|
+
let historyBytes = 0;
|
|
412
|
+
for (const candidate of candidates.sort((left, right) => Number(!!left.history) - Number(!!right.history) || left.path.localeCompare(right.path))) {
|
|
358
413
|
let stat;
|
|
359
414
|
try {
|
|
360
415
|
stat = lstatSync(candidate.path);
|
|
@@ -371,12 +426,30 @@ function collectDocuments(root, diagnostics) {
|
|
|
371
426
|
diagnostics.push(issue("error", "APPSPEC_FILE_SIZE_EXCEEDED", `AppSpec 单文件超过 ${APP_SPEC_LIMITS.maximumFileBytes} 字节上限`, relativePath(root, candidate.path)));
|
|
372
427
|
continue;
|
|
373
428
|
}
|
|
374
|
-
|
|
429
|
+
const indexOnly = candidate.history && basename(candidate.path) !== `${selector}.md`;
|
|
430
|
+
const readBytes = indexOnly ? Math.min(stat.size, 8192) : stat.size;
|
|
431
|
+
if ((candidate.history ? historyBytes : result.bytes) + readBytes > APP_SPEC_LIMITS.maximumTotalBytes) {
|
|
375
432
|
diagnostics.push(issue("error", "APPSPEC_TOTAL_SIZE_EXCEEDED", `AppSpec 总大小超过 ${APP_SPEC_LIMITS.maximumTotalBytes} 字节上限`, "appspec"));
|
|
376
433
|
break;
|
|
377
434
|
}
|
|
378
|
-
|
|
379
|
-
|
|
435
|
+
if (candidate.history)
|
|
436
|
+
historyBytes += readBytes;
|
|
437
|
+
else
|
|
438
|
+
result.bytes += readBytes;
|
|
439
|
+
let content;
|
|
440
|
+
if (indexOnly) {
|
|
441
|
+
const descriptor = openSync(candidate.path, 'r');
|
|
442
|
+
try {
|
|
443
|
+
const buffer = Buffer.alloc(readBytes);
|
|
444
|
+
const bytes = readSync(descriptor, buffer, 0, readBytes, 0);
|
|
445
|
+
content = buffer.subarray(0, bytes).toString('utf8').match(/^---\r?\n[\s\S]*?\r?\n---/)?.[0] || '';
|
|
446
|
+
}
|
|
447
|
+
finally {
|
|
448
|
+
closeSync(descriptor);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
else
|
|
452
|
+
content = readFileSync(candidate.path, "utf8");
|
|
380
453
|
const document = parseAppSpecDocument(root, candidate.path, candidate.kind, content, diagnostics);
|
|
381
454
|
if (!document)
|
|
382
455
|
continue;
|
|
@@ -412,11 +485,11 @@ function validateDocuments(collection, contract, diagnostics) {
|
|
|
412
485
|
}
|
|
413
486
|
}
|
|
414
487
|
duplicateDiagnostics([...collection.capabilities, ...collection.activeChanges, ...collection.history, ...collection.decisions], document => document.id, "APPSPEC_DOCUMENT_ID_DUPLICATED", diagnostics);
|
|
415
|
-
duplicateDiagnostics(collection.capabilities.flatMap(document => document.requirementIds.map(id => ({ ...document, id }))), document => document.id, "APPSPEC_REQUIREMENT_ID_DUPLICATED", diagnostics);
|
|
416
|
-
duplicateDiagnostics(collection.capabilities.flatMap(document => document.acceptanceIds.map(id => ({ ...document, id }))), document => document.id, "APPSPEC_ACCEPTANCE_ID_DUPLICATED", diagnostics);
|
|
488
|
+
duplicateDiagnostics([...collection.app, ...collection.capabilities].flatMap(document => document.requirementIds.map(id => ({ ...document, id }))), document => document.id, "APPSPEC_REQUIREMENT_ID_DUPLICATED", diagnostics);
|
|
489
|
+
duplicateDiagnostics([...collection.app, ...collection.capabilities].flatMap(document => document.acceptanceIds.map(id => ({ ...document, id }))), document => document.id, "APPSPEC_ACCEPTANCE_ID_DUPLICATED", diagnostics);
|
|
417
490
|
const capabilityIds = new Set(collection.capabilities.map(document => document.id));
|
|
418
|
-
const requirementIds = new Set(collection.capabilities.flatMap(document => document.requirementIds));
|
|
419
|
-
const acceptanceIds = new Set(collection.capabilities.flatMap(document => document.acceptanceIds));
|
|
491
|
+
const requirementIds = new Set([...collection.app, ...collection.capabilities].flatMap(document => document.requirementIds));
|
|
492
|
+
const acceptanceIds = new Set([...collection.app, ...collection.capabilities].flatMap(document => document.acceptanceIds));
|
|
420
493
|
const resourceCodes = new Set(contract.resourceCodes);
|
|
421
494
|
const actionCodes = new Set(contract.actionCodes);
|
|
422
495
|
const decisionIds = new Set(collection.decisions.map(document => document.id));
|
|
@@ -436,7 +509,7 @@ function validateDocuments(collection, contract, diagnostics) {
|
|
|
436
509
|
}
|
|
437
510
|
for (const id of document.references.requirements) {
|
|
438
511
|
if (!requirementIds.has(id)) {
|
|
439
|
-
diagnostics.push(issue(referenceSeverity, "APPSPEC_CHANGE_REQUIREMENT_UNKNOWN", `ChangeSpec 引用的需求 ${id}
|
|
512
|
+
diagnostics.push(issue(referenceSeverity, "APPSPEC_CHANGE_REQUIREMENT_UNKNOWN", `ChangeSpec 引用的需求 ${id} 尚未进入当前总纲或能力规格`, document.path));
|
|
440
513
|
}
|
|
441
514
|
}
|
|
442
515
|
for (const id of document.references.decisions) {
|
|
@@ -460,13 +533,17 @@ function validateDocuments(collection, contract, diagnostics) {
|
|
|
460
533
|
}
|
|
461
534
|
}
|
|
462
535
|
function validateCloseConvergence(document, collection, contract, diagnostics) {
|
|
536
|
+
for (const title of ['验证与发布', '交接']) {
|
|
537
|
+
if (!hasMeaningfulSection(document.content, [title], []))
|
|
538
|
+
diagnostics.push(issue('error', 'APPSPEC_HANDOFF_INCOMPLETE', `关闭前补齐“${title}”的实际结果;未发布或取消时明确原因`, `${document.path}#${title}`));
|
|
539
|
+
}
|
|
463
540
|
const currentSpec = currentSpecStatus(document);
|
|
464
541
|
if (currentSpec === "pending") {
|
|
465
542
|
diagnostics.push(issue("error", "APPSPEC_CURRENT_SPEC_NOT_CONVERGED", "关闭前必须确认 currentSpec=merged 或 not-applicable;该检查只约束 spec close", document.path));
|
|
466
543
|
}
|
|
467
544
|
const capabilityIds = new Set(collection.capabilities.map(item => item.id));
|
|
468
|
-
const requirementIds = new Set(collection.capabilities.flatMap(item => item.requirementIds));
|
|
469
|
-
const acceptanceIds = new Set(collection.capabilities.flatMap(item => item.acceptanceIds));
|
|
545
|
+
const requirementIds = new Set([...collection.app, ...collection.capabilities].flatMap(item => item.requirementIds));
|
|
546
|
+
const acceptanceIds = new Set([...collection.app, ...collection.capabilities].flatMap(item => item.acceptanceIds));
|
|
470
547
|
const decisionIds = new Set(collection.decisions.map(item => item.id));
|
|
471
548
|
for (const id of document.references.capabilities) {
|
|
472
549
|
const matches = collection.capabilities.filter(item => item.id === id);
|
|
@@ -478,9 +555,9 @@ function validateCloseConvergence(document, collection, contract, diagnostics) {
|
|
|
478
555
|
}
|
|
479
556
|
}
|
|
480
557
|
for (const id of document.references.requirements) {
|
|
481
|
-
const matches = collection.capabilities.filter(item => item.requirementIds.includes(id));
|
|
558
|
+
const matches = [...collection.app, ...collection.capabilities].filter(item => item.requirementIds.includes(id));
|
|
482
559
|
if (!requirementIds.has(id)) {
|
|
483
|
-
diagnostics.push(issue("error", "APPSPEC_CHANGE_REQUIREMENT_UNKNOWN", `关闭前必须把需求 ${id}
|
|
560
|
+
diagnostics.push(issue("error", "APPSPEC_CHANGE_REQUIREMENT_UNKNOWN", `关闭前必须把需求 ${id} 合入当前总纲或能力规格`, document.path));
|
|
484
561
|
}
|
|
485
562
|
else if (matches.length > 1) {
|
|
486
563
|
diagnostics.push(issue("error", "APPSPEC_REQUIREMENT_ID_DUPLICATED", `关闭前必须消除需求 ${id} 的重复定义`, document.path));
|
|
@@ -496,13 +573,13 @@ function validateCloseConvergence(document, collection, contract, diagnostics) {
|
|
|
496
573
|
}
|
|
497
574
|
}
|
|
498
575
|
for (const id of document.requirementIds) {
|
|
499
|
-
const matches = collection.capabilities.filter(item => item.requirementIds.includes(id));
|
|
576
|
+
const matches = [...collection.app, ...collection.capabilities].filter(item => item.requirementIds.includes(id));
|
|
500
577
|
if (matches.length > 1) {
|
|
501
578
|
diagnostics.push(issue("error", "APPSPEC_REQUIREMENT_ID_DUPLICATED", `关闭前必须消除需求 ${id} 的重复定义`, document.path));
|
|
502
579
|
}
|
|
503
580
|
}
|
|
504
581
|
for (const id of document.acceptanceIds) {
|
|
505
|
-
const matches = collection.capabilities.filter(item => item.acceptanceIds.includes(id));
|
|
582
|
+
const matches = [...collection.app, ...collection.capabilities].filter(item => item.acceptanceIds.includes(id));
|
|
506
583
|
if (matches.length > 1) {
|
|
507
584
|
diagnostics.push(issue("error", "APPSPEC_ACCEPTANCE_ID_DUPLICATED", `关闭前必须消除验收场景 ${id} 的重复定义`, document.path));
|
|
508
585
|
}
|
|
@@ -514,12 +591,12 @@ function validateCloseConvergence(document, collection, contract, diagnostics) {
|
|
|
514
591
|
function validateEmbeddedCurrentSpecIds(document, currentRequirementIds, currentAcceptanceIds, diagnostics) {
|
|
515
592
|
for (const id of document.requirementIds) {
|
|
516
593
|
if (!currentRequirementIds.has(id)) {
|
|
517
|
-
diagnostics.push(issue("error", "APPSPEC_CHANGE_REQUIREMENT_NOT_CURRENT", `ChangeSpec 中的长期需求 ${id}
|
|
594
|
+
diagnostics.push(issue("error", "APPSPEC_CHANGE_REQUIREMENT_NOT_CURRENT", `ChangeSpec 中的长期需求 ${id} 尚未进入当前总纲或能力规格`, document.path));
|
|
518
595
|
}
|
|
519
596
|
}
|
|
520
597
|
for (const id of document.acceptanceIds) {
|
|
521
598
|
if (!currentAcceptanceIds.has(id)) {
|
|
522
|
-
diagnostics.push(issue("error", "APPSPEC_CHANGE_ACCEPTANCE_NOT_CURRENT", `ChangeSpec 中的验收场景 ${id}
|
|
599
|
+
diagnostics.push(issue("error", "APPSPEC_CHANGE_ACCEPTANCE_NOT_CURRENT", `ChangeSpec 中的验收场景 ${id} 尚未进入当前总纲或能力规格`, document.path));
|
|
523
600
|
}
|
|
524
601
|
}
|
|
525
602
|
}
|
|
@@ -984,7 +1061,7 @@ status: active
|
|
|
984
1061
|
---
|
|
985
1062
|
# ${appName}
|
|
986
1063
|
|
|
987
|
-
|
|
1064
|
+
本文件保存当前有效目标与设计约束。正式变更关联 ChangeSpec;测试发布前核对设计与验收计划,生产晋级前核对实际验收。资源、字段、权限和动作的实现以
|
|
988
1065
|
\`openxiangda.config.ts\` 与实时编译合同为准。
|
|
989
1066
|
|
|
990
1067
|
## 业务目标
|
|
@@ -1003,12 +1080,28 @@ AppSpec 是可选的业务意图辅助层,不是发布门禁。资源、字段
|
|
|
1003
1080
|
|
|
1004
1081
|
## 能力目录
|
|
1005
1082
|
|
|
1006
|
-
<!-- 复杂业务再在 capabilities/ 下增加 CAP
|
|
1083
|
+
<!-- 复杂业务再在 capabilities/ 下增加 CAP-*;简单应用的稳定规则直接写在本文件。 -->
|
|
1007
1084
|
|
|
1008
1085
|
## 术语
|
|
1009
1086
|
|
|
1010
1087
|
## 跨能力约束
|
|
1011
1088
|
|
|
1089
|
+
## 架构与数据关系
|
|
1090
|
+
|
|
1091
|
+
<!-- 写明领域边界、核心模型关系、平台能力与自定义动作的归属、状态转换与不变量。 -->
|
|
1092
|
+
|
|
1093
|
+
## 业务任务与页面
|
|
1094
|
+
|
|
1095
|
+
<!-- 按用户任务规划管理端、PC、移动入口与数据关系;辅助表不必有页面。 -->
|
|
1096
|
+
|
|
1097
|
+
## 权限矩阵与确认
|
|
1098
|
+
|
|
1099
|
+
<!-- 记录角色、页面、操作、行范围、字段和多角色组合;写明需求依据与未明确的边界。 -->
|
|
1100
|
+
|
|
1101
|
+
## 性能与容量预算
|
|
1102
|
+
|
|
1103
|
+
<!-- 记录数据量及增长、并发、分页与索引、请求次数、延迟目标和测量口径;区分估算、目标与实测。 -->
|
|
1104
|
+
|
|
1012
1105
|
## 未确认问题
|
|
1013
1106
|
|
|
1014
1107
|
- 无。
|
|
@@ -1040,9 +1133,9 @@ actions: ${JSON.stringify(input.actions)}
|
|
|
1040
1133
|
|
|
1041
1134
|
#### AC-DOMAIN-001-01 正向或反向场景
|
|
1042
1135
|
|
|
1043
|
-
-
|
|
1044
|
-
-
|
|
1045
|
-
-
|
|
1136
|
+
- 前置:已知条件
|
|
1137
|
+
- 操作:用户或系统执行动作
|
|
1138
|
+
- 预期:观察到明确结果
|
|
1046
1139
|
-->
|
|
1047
1140
|
|
|
1048
1141
|
## 状态与异常
|
|
@@ -1072,6 +1165,22 @@ decisions: []
|
|
|
1072
1165
|
|
|
1073
1166
|
${input.summary || "<!-- 一两句话说明问题、证据和期望结果。 -->"}
|
|
1074
1167
|
|
|
1168
|
+
## 需求依据
|
|
1169
|
+
|
|
1170
|
+
<!-- 记录用户原始需求或当前规格引用、已明确规则与假设;不代替用户编造确认。 -->
|
|
1171
|
+
|
|
1172
|
+
## 方案与影响
|
|
1173
|
+
|
|
1174
|
+
<!-- 说明能力所有者、模型/页面/权限/状态影响,引用已有架构决定。 -->
|
|
1175
|
+
|
|
1176
|
+
## 任务与实现
|
|
1177
|
+
|
|
1178
|
+
<!-- 用稳定需求 ID 关联实施任务、源码/声明路径与验收场景;实施后更新实际结果。 -->
|
|
1179
|
+
|
|
1180
|
+
## 性能与容量预算
|
|
1181
|
+
|
|
1182
|
+
<!-- 引用总纲默认预算,或记录本次数据规模、查询/分页/批量/超时/并发和延迟目标。 -->
|
|
1183
|
+
|
|
1075
1184
|
## 变更
|
|
1076
1185
|
|
|
1077
1186
|
- ADDED:
|
|
@@ -1084,6 +1193,8 @@ ${input.summary || "<!-- 一两句话说明问题、证据和期望结果。 -->
|
|
|
1084
1193
|
- [ ] 一个可观察的正向结果
|
|
1085
1194
|
- [ ] 需要时补充拒绝、异常或权限反例
|
|
1086
1195
|
|
|
1196
|
+
<!-- 使用 #### AC-领域-编号 给场景稳定 ID;写明角色、前置、操作、预期和拒绝路径。测试部署后再记录实际观察。 -->
|
|
1197
|
+
|
|
1087
1198
|
## 数据与权限
|
|
1088
1199
|
|
|
1089
1200
|
- 无,或说明资源、字段、角色和数据范围变化。
|
|
@@ -1100,6 +1211,14 @@ ${input.summary || "<!-- 一两句话说明问题、证据和期望结果。 -->
|
|
|
1100
1211
|
|
|
1101
1212
|
- L3 如涉及 ADR,在 front matter 的 decisions 中引用。
|
|
1102
1213
|
|
|
1214
|
+
## 验证与发布
|
|
1215
|
+
|
|
1216
|
+
<!-- 记录检查结果、源码提交、测试/生产运行 ID、包摘要、验收报告路径、未覆盖项和恢复入口。区分本地通过、部署成功与业务验收。 -->
|
|
1217
|
+
|
|
1218
|
+
## 交接
|
|
1219
|
+
|
|
1220
|
+
<!-- 写明持续有效规则已更新的位置、剩余问题与下一步;无需复制当前规格全文。 -->
|
|
1221
|
+
|
|
1103
1222
|
## 未确认问题
|
|
1104
1223
|
|
|
1105
1224
|
- 无。
|
|
@@ -1170,8 +1289,8 @@ function issue(severity, code, message, path) {
|
|
|
1170
1289
|
path,
|
|
1171
1290
|
retryable: false,
|
|
1172
1291
|
remediation: severity === "error"
|
|
1173
|
-
? "
|
|
1174
|
-
: "
|
|
1292
|
+
? "修正记录后运行 openxiangda spec check;普通 check 可继续,正式发布按阶段核对"
|
|
1293
|
+
: "按实际变化范围补充;确定性缺口会在相应发布阶段核对",
|
|
1175
1294
|
};
|
|
1176
1295
|
}
|
|
1177
1296
|
function summarize(document) {
|