backend-skeleton 1.0.0-beta.7 → 1.0.0-beta.8
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.
|
@@ -104,6 +104,22 @@ function writeUnit(target, content) {
|
|
|
104
104
|
fs.writeFileSync(target, content);
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
// O3 follow-up (D-handle-registry-enforcement, "Continued"): a coarse, per-resource, emit-time,
|
|
108
|
+
// source-only proxy for "has this resource's own create-flow ever been wired to register a
|
|
109
|
+
// HandleRegistry row" -- see DECISIONS.md for why this stays static and never queries a live
|
|
110
|
+
// target-app database (that's a separate, harder, still-open gap, not this). Requires the opening
|
|
111
|
+
// "(" so a bare comment/javadoc mention of the annotation's name (RecordHandleSnapshot.java.tmpl's
|
|
112
|
+
// own javadoc has one) doesn't count as "found". Deliberately biased toward a false-positive
|
|
113
|
+
// WARNING (nagging a resource that's actually registered some other way, e.g. a hand-written
|
|
114
|
+
// HandleService.register() call with no annotation) over a false-negative SILENCE (saying nothing
|
|
115
|
+
// about a resource that really can never bootstrap its first PATCH) -- see DECISIONS.md.
|
|
116
|
+
const RECORD_HANDLE_SNAPSHOT_RE = /@RecordHandleSnapshot\s*\(/;
|
|
117
|
+
|
|
118
|
+
function hasRecordHandleSnapshot(serviceFilePath) {
|
|
119
|
+
if (!serviceFilePath || !fs.existsSync(serviceFilePath)) return false;
|
|
120
|
+
return RECORD_HANDLE_SNAPSHOT_RE.test(fs.readFileSync(serviceFilePath, 'utf8'));
|
|
121
|
+
}
|
|
122
|
+
|
|
107
123
|
// See DECISIONS.md D-handles-ownership for the full design; the conflict/manifest/force/orphan
|
|
108
124
|
// logic itself now lives in handles/_engine.mjs (D-handles-providers, G4) -- this function's job
|
|
109
125
|
// is purely to compute java-spring's own render/paths and hand them to emitUnits(). `force`/
|
|
@@ -249,15 +265,26 @@ export function emitJavaSpring({ repoRoot, featureId, plan, basePackage, resourc
|
|
|
249
265
|
if (computeDiff && migrationAction === 'update') migrationActionEntry.diff = unifiedDiff(migrationRelPath, migrationDiskContent, migrationContent);
|
|
250
266
|
result.actions.push(migrationActionEntry);
|
|
251
267
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
268
|
+
const postEmitNotes = [
|
|
269
|
+
'NOT done automatically: applying specs/<id>/handles/migration.sql to any database. Review it and apply yourself.',
|
|
270
|
+
// O4 (D-handle-lifecycle): HandleAspect.java only actually intercepts anything once a
|
|
271
|
+
// human applies @RecordHandleSnapshot to a real service method AND the target repo has
|
|
272
|
+
// this dependency -- never auto-added to build.gradle, same "review and apply yourself"
|
|
273
|
+
// boundary as the migration note above.
|
|
274
|
+
'NOT done automatically: HandleAspect.java requires spring-boot-starter-aop on your own build.gradle classpath (Spring AOP is not enabled by any other starter). Add it yourself before applying @RecordHandleSnapshot to any service method.',
|
|
275
|
+
];
|
|
276
|
+
// O3 follow-up (D-handle-registry-enforcement, "Continued"): per-resource, conditional on
|
|
277
|
+
// enforceRegistry actually being on -- see hasRecordHandleSnapshot() above.
|
|
278
|
+
if (enforceRegistry) {
|
|
279
|
+
for (const resource of plan.resources) {
|
|
280
|
+
if (!resource.willGenerateResolver) continue;
|
|
281
|
+
if (hasRecordHandleSnapshot(resource.service.file)) continue;
|
|
282
|
+
const relServiceFile = path.relative(repoRoot, resource.service.file);
|
|
283
|
+
postEmitNotes.push(
|
|
284
|
+
`${resource.type}: --enforce-registry is on, but no @RecordHandleSnapshot(...) was found anywhere in ${relServiceFile} -- this resource may never get its first HandleRegistry row, and every fetch()/patch() call against it will 404 until something registers it. Apply @RecordHandleSnapshot to ${resource.service.serviceType}'s own create-flow method (or call HandleService.register() by hand at least once per resource), then re-emit. See D-handle-registry-enforcement in DECISIONS.md for the full bootstrapping explanation.`,
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return { ...result, postEmitNotes };
|
|
263
290
|
}
|
|
@@ -40,6 +40,16 @@ function dottedModulePath(file, importRoot) {
|
|
|
40
40
|
return rel.split(path.sep).join('.');
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
// O3 follow-up (D-handle-registry-enforcement, "Continued"): same static, coarse, per-resource
|
|
44
|
+
// presence check as java-spring's own -- see that file's identical comment for the false-
|
|
45
|
+
// positive/false-negative bias reasoning (unchanged here).
|
|
46
|
+
const RECORD_SNAPSHOT_RE = /@record_snapshot\s*\(/;
|
|
47
|
+
|
|
48
|
+
function hasRecordSnapshot(routeFilePath) {
|
|
49
|
+
if (!routeFilePath || !fs.existsSync(routeFilePath)) return false;
|
|
50
|
+
return RECORD_SNAPSHOT_RE.test(fs.readFileSync(routeFilePath, 'utf8'));
|
|
51
|
+
}
|
|
52
|
+
|
|
43
53
|
// See DECISIONS.md D-handles-providers. G4 follow-up: migration.sql + a real recover() lifecycle
|
|
44
54
|
// (tables.py/handle_service.py/record_snapshot.py) are now generated, mirroring java-spring's own
|
|
45
55
|
// O4 work -- the EXCLUDED section's original "even Java hasn't got O4" reasoning is stale, see
|
|
@@ -197,5 +207,18 @@ export function emitPythonFastApi({ repoRoot, featureId, plan, resourceFilter =
|
|
|
197
207
|
// and apply yourself" boundary as the migration note above.
|
|
198
208
|
postEmitNotes.push('NOT done automatically: applying @record_snapshot (handles/record_snapshot.py) to any of your own service functions. Codegen never touches existing business logic files.');
|
|
199
209
|
|
|
210
|
+
// O3 follow-up (D-handle-registry-enforcement, "Continued"): per-resource, conditional on
|
|
211
|
+
// enforceRegistry.
|
|
212
|
+
if (enforceRegistry) {
|
|
213
|
+
for (const resource of plan.resources) {
|
|
214
|
+
if (!resource.willGenerateResolver) continue;
|
|
215
|
+
if (hasRecordSnapshot(resource.fetchRoute.file)) continue;
|
|
216
|
+
const relRouteFile = path.relative(repoRoot, resource.fetchRoute.file);
|
|
217
|
+
postEmitNotes.push(
|
|
218
|
+
`${resource.type}: --enforce-registry is on, but no @record_snapshot(...) was found anywhere in ${relRouteFile} -- this resource may never get its first registry row, and every fetch/patch call against it will 404 until something registers it. Apply @record_snapshot to its own create-flow route function (or call handle_service.register() by hand at least once per resource), then re-emit. See D-handle-registry-enforcement in DECISIONS.md for the full bootstrapping explanation.`,
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
200
223
|
return { ...result, postEmitNotes };
|
|
201
224
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "backend-skeleton",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Deterministic gate layer for AI-assisted backend changes -- blocks brownfield collisions and contract/handle drift via disk-hash checks before code ships. Scaffolding codegen included (Java/Spring, Python/FastAPI, TypeScript/Express).",
|
|
6
6
|
"license": "AGPL-3.0-or-later",
|