@aiaiai-pt/frankctl 0.7.2 → 0.8.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/CHANGELOG.md +17 -0
- package/dist/index.js +223 -222
- package/dist/template-packs/cira/11_stop_time.yaml +109 -0
- package/dist/template-packs/cira/template-pack.yaml +10 -0
- package/package.json +1 -1
- package/skills/frank-cli/SKILL.md +65 -5
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Stage 11: all 237,808 regional schedule rows projected to the existing B3
|
|
2
|
+
# stop_time type. The source _record_id is generated once from the declared
|
|
3
|
+
# composite stream key (trip_id, Ordem, IdParagem), persisted in Bronze, and
|
|
4
|
+
# passed through unchanged here. Point-in-time profile: 237,808 non-null and
|
|
5
|
+
# distinct _record_id values, 8,964 trip keys, 2,411 stop keys, and zero
|
|
6
|
+
# relationship misses. These counts are evidence, never row limits.
|
|
7
|
+
|
|
8
|
+
apiVersion: frank.platform/v1
|
|
9
|
+
kind: IdentityPolicy
|
|
10
|
+
metadata:
|
|
11
|
+
name: cira-stop-time-external-id
|
|
12
|
+
spec:
|
|
13
|
+
name: cira-stop-time-external-id
|
|
14
|
+
strategy: passthrough
|
|
15
|
+
source_fields:
|
|
16
|
+
- _record_id
|
|
17
|
+
normalizers: []
|
|
18
|
+
emit_format: "cira:bdtransportes:stop_time:{resolved_key}"
|
|
19
|
+
collision_policy: error
|
|
20
|
+
---
|
|
21
|
+
apiVersion: frank.platform/v1
|
|
22
|
+
kind: Pipeline
|
|
23
|
+
metadata:
|
|
24
|
+
name: cira_transport_stop_times
|
|
25
|
+
spec:
|
|
26
|
+
name: cira_transport_stop_times
|
|
27
|
+
description: Complete CIRA regional stop times with stable source identity and existing trip/stop links.
|
|
28
|
+
source_ids:
|
|
29
|
+
- cira-bdtransportes-horarios
|
|
30
|
+
schedule_config:
|
|
31
|
+
type: manual
|
|
32
|
+
steps:
|
|
33
|
+
- name: stop_time_rows
|
|
34
|
+
kind: field_mapping
|
|
35
|
+
params:
|
|
36
|
+
field_mappings:
|
|
37
|
+
- target_column: external_id
|
|
38
|
+
mapping_kind: identity
|
|
39
|
+
identity_policy:
|
|
40
|
+
name: cira-stop-time-external-id
|
|
41
|
+
field_order: 0
|
|
42
|
+
- source_column: schedule
|
|
43
|
+
target_column: arrival_time
|
|
44
|
+
mapping_kind: source_expression
|
|
45
|
+
field_order: 1
|
|
46
|
+
- source_column: schedule
|
|
47
|
+
target_column: departure_time
|
|
48
|
+
mapping_kind: source_expression
|
|
49
|
+
field_order: 2
|
|
50
|
+
- source_column: ordem
|
|
51
|
+
target_column: stop_sequence
|
|
52
|
+
mapping_kind: source_expression
|
|
53
|
+
custom_sql: "try_cast(${source} AS integer)"
|
|
54
|
+
field_order: 3
|
|
55
|
+
- source_column: trip_id
|
|
56
|
+
target_column: trip_id
|
|
57
|
+
mapping_kind: source_expression
|
|
58
|
+
field_order: 4
|
|
59
|
+
- source_column: id_paragem
|
|
60
|
+
target_column: stop_key
|
|
61
|
+
mapping_kind: source_expression
|
|
62
|
+
custom_sql: "concat('stop:',cast(try_cast(${source} AS bigint) AS varchar))"
|
|
63
|
+
field_order: 5
|
|
64
|
+
depends_on: []
|
|
65
|
+
emits_to: backing_dataset
|
|
66
|
+
config:
|
|
67
|
+
output_layer: silver
|
|
68
|
+
---
|
|
69
|
+
apiVersion: frank.platform/v1
|
|
70
|
+
kind: BackingDataset
|
|
71
|
+
metadata:
|
|
72
|
+
name: cira_transport_stop_times
|
|
73
|
+
dependsOn:
|
|
74
|
+
- entityTypeId: transit_trip
|
|
75
|
+
ontologyTenantId: cira
|
|
76
|
+
- entityTypeId: transit_stop
|
|
77
|
+
ontologyTenantId: cira
|
|
78
|
+
spec:
|
|
79
|
+
entity_type_id: stop_time
|
|
80
|
+
entity_type_name: Stop Time
|
|
81
|
+
ontology_tenant_id: cira
|
|
82
|
+
pipeline: cira_transport_stop_times
|
|
83
|
+
sync_mode: manual
|
|
84
|
+
primary_key_column: external_id
|
|
85
|
+
title_key_column: external_id
|
|
86
|
+
property_mappings:
|
|
87
|
+
- column: external_id
|
|
88
|
+
property: external_id
|
|
89
|
+
type: varchar
|
|
90
|
+
is_primary_key: true
|
|
91
|
+
- column: arrival_time
|
|
92
|
+
property: arrival_time
|
|
93
|
+
type: varchar
|
|
94
|
+
- column: departure_time
|
|
95
|
+
property: departure_time
|
|
96
|
+
type: varchar
|
|
97
|
+
- column: stop_sequence
|
|
98
|
+
property: stop_sequence
|
|
99
|
+
type: integer
|
|
100
|
+
- column: trip_id
|
|
101
|
+
property: trip
|
|
102
|
+
is_relationship: true
|
|
103
|
+
target_type: transit_trip
|
|
104
|
+
target_key: service_id
|
|
105
|
+
- column: stop_key
|
|
106
|
+
property: stop
|
|
107
|
+
is_relationship: true
|
|
108
|
+
target_type: transit_stop
|
|
109
|
+
target_key: code
|
|
@@ -98,6 +98,16 @@ spec:
|
|
|
98
98
|
- 580
|
|
99
99
|
- 591
|
|
100
100
|
- 592
|
|
101
|
+
regional-transport-stop-times:
|
|
102
|
+
title: Regional transport stop times with declarative identity
|
|
103
|
+
status: declared_pending
|
|
104
|
+
manifests:
|
|
105
|
+
- 11_stop_time.yaml
|
|
106
|
+
required_sources:
|
|
107
|
+
- cira-bdtransportes-horarios
|
|
108
|
+
issues:
|
|
109
|
+
- 592
|
|
110
|
+
- 650
|
|
101
111
|
regional-transport-avl:
|
|
102
112
|
title: Regional transport current vehicle positions
|
|
103
113
|
status: live_proven
|
package/package.json
CHANGED
|
@@ -85,12 +85,13 @@ an explicit subset. Repeat `--set frank_tenant_prefix=<8-hex>` and
|
|
|
85
85
|
ontology tenant. The CIRA pack treats ontology schema as externally owned and therefore
|
|
86
86
|
contains no `ensure_schema` mutation.
|
|
87
87
|
|
|
88
|
-
A pipeline is one multi-document YAML file describing
|
|
88
|
+
A pipeline is one multi-document YAML file describing four kinds of object under the
|
|
89
89
|
`frank.platform/v1` API version:
|
|
90
90
|
|
|
91
91
|
| `kind` | Role |
|
|
92
92
|
|--------|------|
|
|
93
93
|
| `Source` | Extract/Load config — connector `pattern_id`, streams, schedule → Iceberg **bronze** |
|
|
94
|
+
| `IdentityPolicy` | Stable-key recipe reconciled and pinned before a consuming transform |
|
|
94
95
|
| `Pipeline` | Transform steps (SQL/Python) turning bronze → **silver/gold** |
|
|
95
96
|
| `BackingDataset` | Maps a silver table's columns to **ontology** entity properties |
|
|
96
97
|
|
|
@@ -139,8 +140,8 @@ separate target entity readback.
|
|
|
139
140
|
|
|
140
141
|
| Flag | What it does |
|
|
141
142
|
|------|--------------|
|
|
142
|
-
| `--dry-run` | Client-side parse + cross-ref
|
|
143
|
-
| `--dry-run-server` | Server-side preflight against the catalog + DB without persisting. Catches unknown `pattern_id`s, would-be immutable-diff conflicts, and unresolved refs. |
|
|
143
|
+
| `--dry-run` | Client-side parse + local cross-ref validation. Catches malformed YAML and broken same-file references. No server call. |
|
|
144
|
+
| `--dry-run-server` | Server-side preflight against the catalog + DB without persisting. Catches unknown `pattern_id`s, identity-policy create/noop/patch/new-version state, would-be immutable-diff conflicts, and unresolved refs. |
|
|
144
145
|
| `--dry-run-server --live-ontology` | Adds an opt-in, GET-only check of ontology tenant, type, properties, relationships, keys, and declared carrier types. It never changes ontology schema or entities. |
|
|
145
146
|
|
|
146
147
|
Run `--dry-run-server` in CI on every change; run `apply --wait` to promote.
|
|
@@ -157,6 +158,60 @@ BackingDataset and set `spec.sync_mode: manual`. `--wait` topologically orders s
|
|
|
157
158
|
dependencies and requires external dependencies in the same ontology tenant to be
|
|
158
159
|
already `synced`. Cycles and self-referential relationships fail before execution.
|
|
159
160
|
|
|
161
|
+
### Stable identity in declarative pipelines
|
|
162
|
+
|
|
163
|
+
Declare a tenant-owned recipe once, then reference it by name from an identity field
|
|
164
|
+
mapping. `frankctl` applies in `Source → IdentityPolicy → Pipeline → BackingDataset`
|
|
165
|
+
order and replaces the symbolic reference with the exact returned policy ID/version;
|
|
166
|
+
UUIDs do not belong in tracked YAML.
|
|
167
|
+
|
|
168
|
+
```yaml
|
|
169
|
+
apiVersion: frank.platform/v1
|
|
170
|
+
kind: IdentityPolicy
|
|
171
|
+
metadata: { name: source-record-id }
|
|
172
|
+
spec:
|
|
173
|
+
name: source-record-id
|
|
174
|
+
strategy: passthrough
|
|
175
|
+
source_fields: [_record_id]
|
|
176
|
+
normalizers: []
|
|
177
|
+
emit_format: "my-provider:my-type:{resolved_key}"
|
|
178
|
+
collision_policy: error
|
|
179
|
+
---
|
|
180
|
+
apiVersion: frank.platform/v1
|
|
181
|
+
kind: Pipeline
|
|
182
|
+
metadata: { name: my-pipeline }
|
|
183
|
+
spec:
|
|
184
|
+
source_ids: [my-source]
|
|
185
|
+
steps:
|
|
186
|
+
- name: project
|
|
187
|
+
kind: field_mapping
|
|
188
|
+
params:
|
|
189
|
+
field_mappings:
|
|
190
|
+
- target_column: external_id
|
|
191
|
+
mapping_kind: identity
|
|
192
|
+
identity_policy: { name: source-record-id }
|
|
193
|
+
field_order: 0
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Same-file references contain only `name`; external policies require exact `{name, tier,
|
|
197
|
+
version}`. Never author raw UUID/version/hash pins: `frankctl` resolves symbolic YAML
|
|
198
|
+
and carries the server-returned recipe hash as an internal optimistic precondition.
|
|
199
|
+
|
|
200
|
+
Policy reconciliation reports `create`, `noop`, `patch`, or `new-version`. First use freezes
|
|
201
|
+
a recipe globally; later changes version it. Reads compute tenant-live `used_in`, including
|
|
202
|
+
for system policies, without overwriting a shared system cache. Multi-document apply is
|
|
203
|
+
sequential, not atomic: correct a failure and reapply the complete declaration.
|
|
204
|
+
|
|
205
|
+
Pipeline activation locks Pipeline, affected Transforms in deterministic UUID order with
|
|
206
|
+
refreshed mapping/source snapshots, then old+new policies in UUID/version order. Direct
|
|
207
|
+
Transform PUT/DELETE locks Transform, then sorted policies. This prevents deadlock and
|
|
208
|
+
stale `used_in`. A changed recipe still returns `409 identity_policy_recipe_changed`;
|
|
209
|
+
reapply the complete file. Dry-run observes state but does not reserve it.
|
|
210
|
+
|
|
211
|
+
Migration `s43_identity_policy_frozen` scans only historical `mapping_kind: identity` pins.
|
|
212
|
+
It recognizes canonical/uppercase/hyphenless/braced/URN UUIDs and normalized positive
|
|
213
|
+
versions without casting malformed JSON. Author symbolically; never mutate ontology schema.
|
|
214
|
+
|
|
160
215
|
### Immutable state & when to force
|
|
161
216
|
|
|
162
217
|
Backing Datasets carry operational state (ontology cursor, sync history). If a change
|
|
@@ -179,8 +234,10 @@ to a file for review:
|
|
|
179
234
|
frankctl pipelines export <pipeline-id> > pipeline.yaml
|
|
180
235
|
```
|
|
181
236
|
|
|
182
|
-
The export includes ordinary Source configuration, opaque credential references,
|
|
183
|
-
config-only stream declarations,
|
|
237
|
+
The export includes ordinary Source configuration, opaque credential references,
|
|
238
|
+
config-only stream declarations, complete Pipeline steps, and portable symbolic
|
|
239
|
+
IdentityPolicy references. It omits credential values, stream runtime state, and
|
|
240
|
+
tenant-local policy UUIDs.
|
|
184
241
|
|
|
185
242
|
### Minimal manifest shape
|
|
186
243
|
|
|
@@ -429,6 +486,9 @@ you can review, edit, and feed straight into `pipelines apply`.
|
|
|
429
486
|
- **401 after login**: your token expired and refresh failed — `frankctl auth login` again.
|
|
430
487
|
- **`409 immutable_diff` on apply**: a Backing Dataset change would destroy state; see
|
|
431
488
|
`--allow-recreate` above and decide deliberately.
|
|
489
|
+
- **`409 identity_policy_recipe_changed` on apply**: replay the complete manifest so
|
|
490
|
+
policy reconciliation returns a fresh pin; do not add runtime pins to YAML or retry
|
|
491
|
+
only the Pipeline request.
|
|
432
492
|
- **`apply` did nothing**: that's idempotency — the declared state already matches. Use
|
|
433
493
|
`-v` to see the reconcile plan, or `--dry-run-server` to preview.
|
|
434
494
|
|