@cat-factory/server 0.256.0 → 0.258.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/dist/app.d.ts.map +1 -1
- package/dist/app.js +13 -0
- package/dist/app.js.map +1 -1
- package/dist/modules/notifications/notificationActions.d.ts +27 -3
- package/dist/modules/notifications/notificationActions.d.ts.map +1 -1
- package/dist/modules/notifications/notificationActions.js +36 -7
- package/dist/modules/notifications/notificationActions.js.map +1 -1
- package/dist/modules/publicApi/PublicApiController.d.ts.map +1 -1
- package/dist/modules/publicApi/PublicApiController.js +16 -4
- package/dist/modules/publicApi/PublicApiController.js.map +1 -1
- package/dist/modules/publicApi/PublicEvidenceController.d.ts.map +1 -1
- package/dist/modules/publicApi/PublicEvidenceController.js +5 -16
- package/dist/modules/publicApi/PublicEvidenceController.js.map +1 -1
- package/dist/modules/publicApi/PublicMergeEvidenceController.d.ts +4 -0
- package/dist/modules/publicApi/PublicMergeEvidenceController.d.ts.map +1 -0
- package/dist/modules/publicApi/PublicMergeEvidenceController.js +158 -0
- package/dist/modules/publicApi/PublicMergeEvidenceController.js.map +1 -0
- package/dist/modules/publicApi/PublicSpecController.d.ts +4 -0
- package/dist/modules/publicApi/PublicSpecController.d.ts.map +1 -0
- package/dist/modules/publicApi/PublicSpecController.js +169 -0
- package/dist/modules/publicApi/PublicSpecController.js.map +1 -0
- package/dist/modules/publicApi/decisions/scope.d.ts +21 -0
- package/dist/modules/publicApi/decisions/scope.d.ts.map +1 -1
- package/dist/modules/publicApi/decisions/scope.js +26 -0
- package/dist/modules/publicApi/decisions/scope.js.map +1 -1
- package/dist/modules/publicApi/openapiDocument.generated.d.ts +1 -1
- package/dist/modules/publicApi/openapiDocument.generated.d.ts.map +1 -1
- package/dist/modules/publicApi/openapiDocument.generated.js +1 -1
- package/dist/modules/publicApi/openapiDocument.generated.js.map +1 -1
- package/dist/modules/publicApi/specProjection.d.ts +11 -0
- package/dist/modules/publicApi/specProjection.d.ts.map +1 -0
- package/dist/modules/publicApi/specProjection.js +189 -0
- package/dist/modules/publicApi/specProjection.js.map +1 -0
- package/package.json +8 -8
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PublicMergeEvidenceController.d.ts","sourceRoot":"","sources":["../../../src/modules/publicApi/PublicMergeEvidenceController.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAuG/C,wBAAgB,6BAA6B,IAAI,IAAI,CAAC,MAAM,CAAC,CAgE5D"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { getPublicMergeRecordContract, getPublicRunMergeRecordContract, listPublicMergeClassRollupsContract, MERGE_RECORD_NOT_FOUND_REASON, tagPublicMergeReviewEffortContract, } from '@cat-factory/contracts';
|
|
2
|
+
import { NotFoundError } from '@cat-factory/kernel';
|
|
3
|
+
import { buildHonoRoute } from '@toad-contracts/hono';
|
|
4
|
+
import { Hono } from 'hono';
|
|
5
|
+
import { requireCapability } from '../../http/guards.js';
|
|
6
|
+
import { requireScopedRun } from './decisions/scope.js';
|
|
7
|
+
import { authorize, refuse } from './publicApiAuth.js';
|
|
8
|
+
// The public MERGE-EVIDENCE surface: the merge decision a run left behind, the workspace's
|
|
9
|
+
// per-change-class rollups, and the reviewer-effort tag a human leaves on a landed pull request
|
|
10
|
+
// (ADR 0046).
|
|
11
|
+
//
|
|
12
|
+
// The gap this closes is a split one, not a missing read. An integration could already start a
|
|
13
|
+
// run through `/api/v1` and merge its pull request through `POST /notifications/:id/act`; what it
|
|
14
|
+
// could not do was record how much review that merge actually took, nor read back what the
|
|
15
|
+
// workspace has accumulated per class. So the evidence the auto-merge policy is meant to
|
|
16
|
+
// eventually stand on was collectable only by people driving the app, and never by the harness
|
|
17
|
+
// driving the runs.
|
|
18
|
+
//
|
|
19
|
+
// Four rules shape this controller:
|
|
20
|
+
//
|
|
21
|
+
// 1. **Tagging is `write`, not `admin`.** `act` sits at the top of the ladder because it MERGES
|
|
22
|
+
// a pull request for real; recording how much review an already-landed one needed performs
|
|
23
|
+
// no external side-effect and can merge nothing. Gating the tag at `admin` too would mean an
|
|
24
|
+
// integration whose whole job is recording evidence had to hold a key that also deletes
|
|
25
|
+
// tasks and merges pull requests, which is the opposite of what the ladder is for.
|
|
26
|
+
// 2. **The run-scoped read carries the `/api/v1/runs/:runId/*` access semantic**, resolved
|
|
27
|
+
// through `requireScopedRun` like every other route under that prefix, while the two
|
|
28
|
+
// record-addressed routes re-apply the key's workspace to the row they load, the rule every
|
|
29
|
+
// point read on this API follows. One prefix, one access model: the trap `debug-api.md`
|
|
30
|
+
// records.
|
|
31
|
+
//
|
|
32
|
+
// The two therefore DIVERGE on a record whose run row is gone (a re-run, a cancel), and that
|
|
33
|
+
// divergence is the feature rather than a hole in it. A track record deliberately carries no
|
|
34
|
+
// foreign key to its execution: it is the evidence a merge decision LEFT BEHIND, and the
|
|
35
|
+
// rollups aggregate exactly those rows, so a record that stopped being readable the moment its
|
|
36
|
+
// run was re-run would erase the history the surface exists to serve. Nothing widens: both
|
|
37
|
+
// doors re-apply the key's workspace, and the rollups already publish every record in it at
|
|
38
|
+
// `read`. What the run-scoped read narrows is which RUN a key may address, not which record
|
|
39
|
+
// exists. A record id is derivable (`mtr_<executionId>`), so treating that read as a second
|
|
40
|
+
// confidentiality boundary would be a fiction anyway; the workspace is the boundary, once.
|
|
41
|
+
// 3. **A missing record is a 404, never an empty body.** A run whose pipeline had no `merger`
|
|
42
|
+
// step made no merge decision, and that is a fact about the run; answering with a nulled-out
|
|
43
|
+
// record would read as a decision nobody made.
|
|
44
|
+
// 4. **Refusals THROW**, so this surface answers with the one `handleError` envelope (which
|
|
45
|
+
// carries `details.reason`, the request id and the error-code metric). The exception is the
|
|
46
|
+
// AUTH gate, whose failure is shared DATA produced by `publicApiAuth`. Each refusal is built
|
|
47
|
+
// by ONE named factory below, so no two routes answer the same condition with different words
|
|
48
|
+
// and the reason a caller branches on is decided once per condition rather than per route.
|
|
49
|
+
/** The merge track-record module, or a 503 naming what this deployment has not wired. */
|
|
50
|
+
function requireTrackRecords(c) {
|
|
51
|
+
return requireCapability(c.get('container').mergeTrackRecords, 'Merge track records are not configured');
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The 404 the RUN-scoped read answers for a run it CAN see that left no merge decision behind.
|
|
55
|
+
*
|
|
56
|
+
* It names the run as the run it is, not as a record id: record ids are minted inside the merge
|
|
57
|
+
* path and a caller holding only a run id has never seen one, so rendering `MergeTrackRecord
|
|
58
|
+
* '<runId>' not found` would tell it an id it never supplied is missing. Only `details.reason`
|
|
59
|
+
* is machine-readable, but the prose is what a person reads out of a log.
|
|
60
|
+
*/
|
|
61
|
+
const noMergeRecord = (runId) => new NotFoundError('Merge record for run', runId, { reason: 'no_merge_record' });
|
|
62
|
+
/**
|
|
63
|
+
* The 404 the RECORD-addressed read answers, sharing its reason with the one
|
|
64
|
+
* `MergeTrackRecordService.tag` raises for the same condition on the same id. Two routes, one
|
|
65
|
+
* fact: the id names no record this workspace holds.
|
|
66
|
+
*/
|
|
67
|
+
const mergeRecordNotFound = (recordId) => new NotFoundError('MergeTrackRecord', recordId, { reason: MERGE_RECORD_NOT_FOUND_REASON });
|
|
68
|
+
/**
|
|
69
|
+
* Project a stored record onto the public id vocabulary: `/api/v1` addresses a task as `taskId`
|
|
70
|
+
* and a run as `runId`, so publishing the row's own `blockId`/`executionId` would hand a caller
|
|
71
|
+
* two ids it can address nothing with, beside the ones it can. Nothing is dropped.
|
|
72
|
+
*/
|
|
73
|
+
function recordToWire(record) {
|
|
74
|
+
return {
|
|
75
|
+
recordId: record.id,
|
|
76
|
+
taskId: record.blockId,
|
|
77
|
+
runId: record.executionId,
|
|
78
|
+
changeClass: record.changeClass,
|
|
79
|
+
changedFileCount: record.changedFileCount,
|
|
80
|
+
complexity: record.complexity,
|
|
81
|
+
risk: record.risk,
|
|
82
|
+
impact: record.impact,
|
|
83
|
+
mergePresetId: record.riskPolicyId,
|
|
84
|
+
mergePresetName: record.riskPolicyName,
|
|
85
|
+
decision: record.decision,
|
|
86
|
+
reviewEffort: record.reviewEffort,
|
|
87
|
+
prNumber: record.prNumber,
|
|
88
|
+
prUrl: record.prUrl,
|
|
89
|
+
repoId: record.repoId,
|
|
90
|
+
provider: record.provider,
|
|
91
|
+
createdAt: record.createdAt,
|
|
92
|
+
resolvedAt: record.resolvedAt,
|
|
93
|
+
taggedAt: record.taggedAt,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
export function publicMergeEvidenceController() {
|
|
97
|
+
const app = new Hono();
|
|
98
|
+
// The workspace's per-class rollups, as ONE aggregate. Registered ahead of the point read
|
|
99
|
+
// below so `rollups` is matched as itself rather than as a record id.
|
|
100
|
+
buildHonoRoute(app, listPublicMergeClassRollupsContract, async (c) => {
|
|
101
|
+
const gate = await authorize(c, listPublicMergeClassRollupsContract.minScope);
|
|
102
|
+
if ('fail' in gate)
|
|
103
|
+
return refuse(c, gate.fail);
|
|
104
|
+
const records = requireTrackRecords(c);
|
|
105
|
+
return c.json({ rollups: await records.service.rollups(gate.auth.workspaceId) }, 200);
|
|
106
|
+
});
|
|
107
|
+
// The merge decision a RUN left behind: the entry point for a caller holding a run id, and
|
|
108
|
+
// where it picks up the `recordId` the tag route takes.
|
|
109
|
+
buildHonoRoute(app, getPublicRunMergeRecordContract, async (c) => {
|
|
110
|
+
const gate = await authorize(c, getPublicRunMergeRecordContract.minScope);
|
|
111
|
+
if ('fail' in gate)
|
|
112
|
+
return refuse(c, gate.fail);
|
|
113
|
+
const { workspaceId } = gate.auth;
|
|
114
|
+
const runId = c.req.valid('param').runId;
|
|
115
|
+
const records = requireTrackRecords(c);
|
|
116
|
+
// Resolve the run FIRST, so a run this key may not read answers "no such run" rather than
|
|
117
|
+
// "no such record", the latter confirming the run exists to a caller that cannot see it.
|
|
118
|
+
// The same refusal the sibling evidence reads answer, from the same factory.
|
|
119
|
+
await requireScopedRun(c, workspaceId, runId);
|
|
120
|
+
const record = await records.service.getForRun(workspaceId, runId);
|
|
121
|
+
// A distinct reason from the one above: "there is no such run" is a caller's mistake to stop
|
|
122
|
+
// repeating, where "this run made no merge decision" is a fact about a run it may well be
|
|
123
|
+
// watching (its pipeline has no `merger`, or it never reached one). Prose alone leaves a
|
|
124
|
+
// machine unable to tell those apart.
|
|
125
|
+
if (!record)
|
|
126
|
+
throw noMergeRecord(runId);
|
|
127
|
+
return c.json(recordToWire(record), 200);
|
|
128
|
+
});
|
|
129
|
+
// One record by id, so a caller holding a `recordId` (off a `merge_tag_request` card, say) can
|
|
130
|
+
// read what it is about to tag.
|
|
131
|
+
buildHonoRoute(app, getPublicMergeRecordContract, async (c) => {
|
|
132
|
+
const gate = await authorize(c, getPublicMergeRecordContract.minScope);
|
|
133
|
+
if ('fail' in gate)
|
|
134
|
+
return refuse(c, gate.fail);
|
|
135
|
+
const recordId = c.req.valid('param').recordId;
|
|
136
|
+
const records = requireTrackRecords(c);
|
|
137
|
+
const record = await records.service.get(gate.auth.workspaceId, recordId);
|
|
138
|
+
if (!record)
|
|
139
|
+
throw mergeRecordNotFound(recordId);
|
|
140
|
+
return c.json(recordToWire(record), 200);
|
|
141
|
+
});
|
|
142
|
+
// Tag (or clear) the reviewer effort. `service.tag` raises the NotFound for an unknown or
|
|
143
|
+
// foreign id, carrying the SAME `merge_record_not_found` reason the read above answers, so the
|
|
144
|
+
// two routes addressing one id agree about what a missing one is. Refusing inside the service
|
|
145
|
+
// rather than pre-checking here keeps the write a single round-trip and leaves no window
|
|
146
|
+
// between a check and the patch. A deliberate user action gets a real refusal, where the merge
|
|
147
|
+
// path's own writes are best-effort and silent.
|
|
148
|
+
buildHonoRoute(app, tagPublicMergeReviewEffortContract, async (c) => {
|
|
149
|
+
const gate = await authorize(c, tagPublicMergeReviewEffortContract.minScope);
|
|
150
|
+
if ('fail' in gate)
|
|
151
|
+
return refuse(c, gate.fail);
|
|
152
|
+
const records = requireTrackRecords(c);
|
|
153
|
+
const tagged = await records.service.tag(gate.auth.workspaceId, c.req.valid('param').recordId, c.req.valid('json').reviewEffort);
|
|
154
|
+
return c.json(recordToWire(tagged), 200);
|
|
155
|
+
});
|
|
156
|
+
return app;
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=PublicMergeEvidenceController.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PublicMergeEvidenceController.js","sourceRoot":"","sources":["../../../src/modules/publicApi/PublicMergeEvidenceController.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PublicSpecController.d.ts","sourceRoot":"","sources":["../../../src/modules/publicApi/PublicSpecController.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAsJ/C,wBAAgB,oBAAoB,IAAI,IAAI,CAAC,MAAM,CAAC,CAkCnD"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { getPublicServiceSpecContract, } from '@cat-factory/contracts';
|
|
2
|
+
import { readServiceSpec } from '@cat-factory/agents';
|
|
3
|
+
import { NotFoundError, UnavailableError } from '@cat-factory/kernel';
|
|
4
|
+
import { buildHonoRoute } from '@toad-contracts/hono';
|
|
5
|
+
import { Hono } from 'hono';
|
|
6
|
+
import { authorizeOrThrow } from './publicApiAuth.js';
|
|
7
|
+
import { toPublicServiceSpec } from './specProjection.js';
|
|
8
|
+
// The public SPEC read (`GET /api/v1/services/:serviceId/spec`): the service's in-repo prescriptive
|
|
9
|
+
// specification (the structured requirement tree and the Gherkin rendered from it) for a consumer
|
|
10
|
+
// holding only an API key.
|
|
11
|
+
//
|
|
12
|
+
// It exists because the requirement ids on `GET /api/v1/runs/:runId/report` and `…/outcome` were a
|
|
13
|
+
// join key onto a document no headless caller could fetch. With this, reviewing a run's outcome
|
|
14
|
+
// against the criteria it was scored on is two GETs and a map lookup, with no repository clone and
|
|
15
|
+
// no VCS credential.
|
|
16
|
+
//
|
|
17
|
+
// Everything below is one idea applied repeatedly: **a spec read has several outcomes and this
|
|
18
|
+
// controller refuses to fold them**, because the fold is silent and always in the same direction.
|
|
19
|
+
// The internal view the app's requirements window consumes reports `present: false` for both "this
|
|
20
|
+
// branch holds no spec" and "we could not read the repository", which is right for a window that
|
|
21
|
+
// draws an empty state and wrong here: it would tell every integrator that every service is
|
|
22
|
+
// requirement-free for the duration of a VCS incident, and nothing in the payload would say
|
|
23
|
+
// otherwise.
|
|
24
|
+
//
|
|
25
|
+
// 1. **No VCS integration wired** → `503`, `reason: "vcs_not_configured"`. The deployment, not the
|
|
26
|
+
// service.
|
|
27
|
+
// 2. **The repository could not be read** → `503`, `reason: "spec_read_failed"`. Retry; the spec
|
|
28
|
+
// may well be there.
|
|
29
|
+
// 3. **The branch could not be resolved** → `503`, `reason: "spec_ref_unresolved"`. Its own
|
|
30
|
+
// outcome rather than a shade of the last one, because it is the case the provider REFUSES to
|
|
31
|
+
// distinguish: a renamed, transferred or deleted repository, a stale default branch and a lost
|
|
32
|
+
// installation all answer 404 exactly as an absent file does. Distinct because the fix is
|
|
33
|
+
// distinct: the deployment's repo link is wrong, and no amount of retrying repairs it.
|
|
34
|
+
// 4. **No spec on the default branch** → `200`, `anchor: "absent"`. A real, common, final answer,
|
|
35
|
+
// and one only reached with the ref resolved, so it is a statement about the branch rather
|
|
36
|
+
// than about our luck reaching it.
|
|
37
|
+
// 5. **An anchor that is present and unusable** → `200`, `anchor: "unparsed"`, with the file named
|
|
38
|
+
// in `issues`. Its own value, not folded onto `absent`: a corrupt `spec/service.json` is a repo
|
|
39
|
+
// state somebody has to fix, and an integrator reading it as "no requirements" would be
|
|
40
|
+
// reporting a broken file as a service that declares nothing.
|
|
41
|
+
// 6. **A spec that read partially** → `200` with the tree, `issues` naming every file that did not
|
|
42
|
+
// survive and `truncations` naming every cap that bit.
|
|
43
|
+
//
|
|
44
|
+
// One further case is not this controller's to invent: a service frame with no linked repository throws
|
|
45
|
+
// the same `ValidationError` (a `422`) that `resolveRepoTarget` raises everywhere else, because
|
|
46
|
+
// execution refuses that service too and a read that answered "no requirements" would describe a
|
|
47
|
+
// service nothing can run as one that simply has nothing to say.
|
|
48
|
+
//
|
|
49
|
+
// Two further notes on what this is NOT. It is not a subscription: the spec on the default branch
|
|
50
|
+
// is not the spec a run with an open pull request is working against, which is why the response
|
|
51
|
+
// names the commit it describes. And there is no write half, deliberately: the files are the truth
|
|
52
|
+
// and the write path is a reviewed commit (see `../../../../../contracts/src/public-spec.ts`).
|
|
53
|
+
/** The refusal for an id that names no service this key may read. */
|
|
54
|
+
const serviceNotFound = (serviceId) => new NotFoundError('Service', serviceId, { reason: 'service_not_found' });
|
|
55
|
+
/**
|
|
56
|
+
* The run-repo resolver, or the 503 that names what this deployment has not wired.
|
|
57
|
+
*
|
|
58
|
+
* A total accessor rather than a nullable read the route re-refuses, the shape `http/guards.ts`
|
|
59
|
+
* describes. It carries its own `reason` rather than going through `requireCapability`, because on
|
|
60
|
+
* this surface the machine-readable code is the whole remedy: a headless caller has no setup screen
|
|
61
|
+
* to be sent to and branches on the string.
|
|
62
|
+
*/
|
|
63
|
+
function requireRepoResolver(c) {
|
|
64
|
+
const resolve = c.get('container').resolveRunRepoContext;
|
|
65
|
+
if (!resolve) {
|
|
66
|
+
throw new UnavailableError('No version-control integration is configured for this deployment', 'vcs_not_configured');
|
|
67
|
+
}
|
|
68
|
+
return resolve;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The head commit of the branch the spec is read from, or null when it cannot be resolved.
|
|
72
|
+
*
|
|
73
|
+
* Read BEFORE the tree walk, so the commit named is one the tree is at least as new as. It carries
|
|
74
|
+
* two jobs, and the second is why it is not merely decorative: it names the snapshot in
|
|
75
|
+
* `provenance`, and it is the only POSITIVE evidence this endpoint has that the branch is
|
|
76
|
+
* reachable at all. A repository that serves its files but not its ref still answers the spec, with
|
|
77
|
+
* an unnamed commit; a repository that answers neither is refused rather than reported empty (see
|
|
78
|
+
* {@link requireReadableAnchor}). Null is therefore "unproven", not "unimportant".
|
|
79
|
+
*/
|
|
80
|
+
async function resolveCommit(ctx) {
|
|
81
|
+
try {
|
|
82
|
+
return await ctx.repo.headSha(ctx.baseBranch);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/** Where the tree was read from, for a response that has to stand alone. */
|
|
89
|
+
function provenanceOf(ctx, commit) {
|
|
90
|
+
return {
|
|
91
|
+
provider: ctx.provider ?? 'github',
|
|
92
|
+
// The resolver's owner/name are optional for back-compat with older fakes; the real resolvers
|
|
93
|
+
// always set them, and an empty string is the honest stand-in for a binding that did not.
|
|
94
|
+
owner: ctx.owner ?? '',
|
|
95
|
+
repo: ctx.name ?? '',
|
|
96
|
+
ref: ctx.baseBranch,
|
|
97
|
+
commit,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* The state of the branch's presence anchor, or the refusal for an emptiness that is an OUTAGE
|
|
102
|
+
* rather than an answer.
|
|
103
|
+
*
|
|
104
|
+
* The one place the outcomes are separated, and the ONLY producer of the response's `anchor`, so a
|
|
105
|
+
* new state cannot be answered by accident: the `switch` is exhaustive over the reader's own
|
|
106
|
+
* `SpecAnchorState` through a `never`, and a fifth member fails the build here rather than
|
|
107
|
+
* surfacing as an unmapped value on `/api/v1`.
|
|
108
|
+
*
|
|
109
|
+
* `commit` is the second half of the judgement, and the reason this takes it. GitHub answers 404
|
|
110
|
+
* for a file that is absent, a repository that was renamed, transferred or deleted, a `ref` that no
|
|
111
|
+
* longer exists, and an installation that lost access, and the client maps all of them to "no such
|
|
112
|
+
* file". So `absent` alone is not evidence of an empty branch: it is equally the shape of a
|
|
113
|
+
* repository nobody can read. What separates them is whether the ref RESOLVED, which the walk's own
|
|
114
|
+
* provenance read already establishes, and which cannot 404 for the innocent reason a missing file
|
|
115
|
+
* can. Unresolved plus absent is unproven, and unproven is refused rather than served as the
|
|
116
|
+
* confident "this service declares nothing" the whole endpoint exists to avoid emitting.
|
|
117
|
+
*/
|
|
118
|
+
function requireReadableAnchor(view, commit) {
|
|
119
|
+
const anchor = view.diagnostics?.anchor ?? (view.present ? 'present' : 'absent');
|
|
120
|
+
switch (anchor) {
|
|
121
|
+
case 'present':
|
|
122
|
+
case 'unparsed':
|
|
123
|
+
// Both PROVE the branch was read: the anchor's own bytes came back.
|
|
124
|
+
return anchor;
|
|
125
|
+
case 'absent':
|
|
126
|
+
if (commit)
|
|
127
|
+
return 'absent';
|
|
128
|
+
throw new UnavailableError(`The branch the spec is read from could not be resolved, so an absent spec cannot be told apart from an unreachable repository`, 'spec_ref_unresolved');
|
|
129
|
+
case 'read_failed':
|
|
130
|
+
throw new UnavailableError("The service's repository could not be read; the spec may exist but could not be fetched", 'spec_read_failed');
|
|
131
|
+
default:
|
|
132
|
+
return assertNever(anchor);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/** The compile-time half of the exhaustiveness guard above. */
|
|
136
|
+
function assertNever(value) {
|
|
137
|
+
throw new UnavailableError(`Unhandled spec anchor state: ${String(value)}`, 'spec_read_failed');
|
|
138
|
+
}
|
|
139
|
+
export function publicSpecController() {
|
|
140
|
+
const app = new Hono();
|
|
141
|
+
buildHonoRoute(app, getPublicServiceSpecContract, async (c) => {
|
|
142
|
+
const auth = await authorizeOrThrow(c, getPublicServiceSpecContract.minScope);
|
|
143
|
+
const { workspaceId } = auth;
|
|
144
|
+
const { serviceId } = c.req.valid('param');
|
|
145
|
+
const container = c.get('container');
|
|
146
|
+
// Resolve the service before the resolver's 503, so a mistyped id is answered by the 404 it
|
|
147
|
+
// deserves rather than by a report on the deployment's wiring.
|
|
148
|
+
if (!(await container.boardService.getService(workspaceId, serviceId))) {
|
|
149
|
+
throw serviceNotFound(serviceId);
|
|
150
|
+
}
|
|
151
|
+
// The repo resolution walks the block's ancestry to the enclosing service frame and reads that
|
|
152
|
+
// frame's linked repository: the same seam the engine binds a run's pre/post-ops through, and
|
|
153
|
+
// deliberately with no "first repo" fallback. A service under no linked repo THROWS out of
|
|
154
|
+
// here (a 422), which is the answer every other surface gives it.
|
|
155
|
+
const ctx = await requireRepoResolver(c)(workspaceId, serviceId);
|
|
156
|
+
if (!ctx) {
|
|
157
|
+
throw new UnavailableError('No version-control integration is connected for this workspace', 'vcs_not_configured');
|
|
158
|
+
}
|
|
159
|
+
const commit = await resolveCommit(ctx);
|
|
160
|
+
// `readServiceSpec` is the ONE spec reader: the same walk, the same per-node salvage and the
|
|
161
|
+
// same diagnostics the app's window and the run-evidence reductions read through. A second
|
|
162
|
+
// reader here is how two surfaces come to disagree about what a malformed group renders as.
|
|
163
|
+
const view = await readServiceSpec(ctx.repo, ctx.baseBranch);
|
|
164
|
+
const anchor = requireReadableAnchor(view, commit);
|
|
165
|
+
return c.json(toPublicServiceSpec(serviceId, anchor, view, provenanceOf(ctx, commit)), 200);
|
|
166
|
+
});
|
|
167
|
+
return app;
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=PublicSpecController.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PublicSpecController.js","sourceRoot":"","sources":["../../../src/modules/publicApi/PublicSpecController.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { BrainstormSession, BrainstormStage, ClarityReview, ExecutionInstance, RequirementReview } from '@cat-factory/contracts';
|
|
2
2
|
import type { GateActor } from '@cat-factory/kernel';
|
|
3
|
+
import { NotFoundError } from '@cat-factory/kernel';
|
|
3
4
|
import type { PublicApiKeyAuth } from '@cat-factory/integrations';
|
|
4
5
|
import type { Context } from 'hono';
|
|
5
6
|
import type { BrainstormModule, ClarityModule, InterviewGate, RequirementsModule } from '@cat-factory/orchestration';
|
|
@@ -31,6 +32,26 @@ export interface ScopedRun {
|
|
|
31
32
|
* unreachable branch in four published SDK error vocabularies.
|
|
32
33
|
*/
|
|
33
34
|
export declare function loadScopedRun<E extends AppEnv>(c: Context<E>, workspaceId: string, runId: string): Promise<ScopedRun | null>;
|
|
35
|
+
/**
|
|
36
|
+
* The refusal every THROWING route under `/api/v1/runs/:runId/*` shares: the id names no run this
|
|
37
|
+
* key may read.
|
|
38
|
+
*
|
|
39
|
+
* One factory rather than a literal per route so no two routes answer the same condition with
|
|
40
|
+
* different words, and so the reason a caller branches on is decided once for the whole prefix.
|
|
41
|
+
* It lives beside {@link loadScopedRun} because the two are one thought: this is what a null from
|
|
42
|
+
* that loader MEANS on a surface whose refusals throw.
|
|
43
|
+
*/
|
|
44
|
+
export declare const runNotFound: (runId: string) => NotFoundError;
|
|
45
|
+
/**
|
|
46
|
+
* {@link loadScopedRun}'s total twin: resolve the run or THROW {@link runNotFound}.
|
|
47
|
+
*
|
|
48
|
+
* The nullable loader stays exported for the DATA-returning decision surface (which must emit its
|
|
49
|
+
* own typed envelope) and for the two evidence reads that answer the same 404 a second time when
|
|
50
|
+
* the composed report comes back empty. Every other caller wants the run or nothing, and a
|
|
51
|
+
* `require*` accessor is how this codebase spells that. A nullable read plus an `if` at each
|
|
52
|
+
* route is the shape it replaced.
|
|
53
|
+
*/
|
|
54
|
+
export declare function requireScopedRun<E extends AppEnv>(c: Context<E>, workspaceId: string, runId: string): Promise<ScopedRun>;
|
|
34
55
|
/** The error a gate rejected with, kept as DATA so each handler emits its own typed `c.json`. */
|
|
35
56
|
export type GateFailure = {
|
|
36
57
|
fail: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../../../src/modules/publicApi/decisions/scope.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../../../src/modules/publicApi/decisions/scope.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { NotFoundError } from '@cat-factory/kernel';
|
|
1
2
|
import { findParkedInterviewStep } from '@cat-factory/orchestration';
|
|
2
3
|
import { authorize } from '../publicApiAuth.js';
|
|
3
4
|
/**
|
|
@@ -31,6 +32,31 @@ export async function loadScopedRun(c, workspaceId, runId) {
|
|
|
31
32
|
const anchor = await container.boardService.getInternalTask(workspaceId, execution.blockId);
|
|
32
33
|
return anchor ? { execution, blockId: execution.blockId } : null;
|
|
33
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* The refusal every THROWING route under `/api/v1/runs/:runId/*` shares: the id names no run this
|
|
37
|
+
* key may read.
|
|
38
|
+
*
|
|
39
|
+
* One factory rather than a literal per route so no two routes answer the same condition with
|
|
40
|
+
* different words, and so the reason a caller branches on is decided once for the whole prefix.
|
|
41
|
+
* It lives beside {@link loadScopedRun} because the two are one thought: this is what a null from
|
|
42
|
+
* that loader MEANS on a surface whose refusals throw.
|
|
43
|
+
*/
|
|
44
|
+
export const runNotFound = (runId) => new NotFoundError('Run', runId, { reason: 'run_not_found' });
|
|
45
|
+
/**
|
|
46
|
+
* {@link loadScopedRun}'s total twin: resolve the run or THROW {@link runNotFound}.
|
|
47
|
+
*
|
|
48
|
+
* The nullable loader stays exported for the DATA-returning decision surface (which must emit its
|
|
49
|
+
* own typed envelope) and for the two evidence reads that answer the same 404 a second time when
|
|
50
|
+
* the composed report comes back empty. Every other caller wants the run or nothing, and a
|
|
51
|
+
* `require*` accessor is how this codebase spells that. A nullable read plus an `if` at each
|
|
52
|
+
* route is the shape it replaced.
|
|
53
|
+
*/
|
|
54
|
+
export async function requireScopedRun(c, workspaceId, runId) {
|
|
55
|
+
const scoped = await loadScopedRun(c, workspaceId, runId);
|
|
56
|
+
if (!scoped)
|
|
57
|
+
throw runNotFound(runId);
|
|
58
|
+
return scoped;
|
|
59
|
+
}
|
|
34
60
|
/**
|
|
35
61
|
* Emit a gate's rejection as the surface's standard error body.
|
|
36
62
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scope.js","sourceRoot":"","sources":["../../../../src/modules/publicApi/decisions/scope.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"scope.js","sourceRoot":"","sources":["../../../../src/modules/publicApi/decisions/scope.ts"],"names":[],"mappings":"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"}
|