Re-verified on current origin/main (fdfc6929) and read-only prod on
2026-11-05. The mechanism the task asks for already exists end to end: Orin
creates, updates, pins, and resets Templates through the CLI/portal with his
portal identity (no Git access, no Developer), and the knowledge repository's
main-branch CI re-seeds the live Templates from workflow-templates/*.yaml
on every push. No product-code gap was found, so this PR is docs plus one
test that locks in the CI-only sync route. No prod writes were made.
- Auto-sync on knowledge main (dataops side). The knowledge publisher
handler routes
POST /api/templates/synctosyncTemplates(backend/src/auth/knowledgePublisher.ts:129), which runsseedDeploymentRuntime— "the same reconciliation a deploy runs" (backend/src/auth/knowledgePublisher.ts:138-161) — and reports pinned types (:152-156). - Auto-sync (caller side).
DataTalksClub/dataops-knowledge.github/workflows/validate.ymlruns thesync_workflow_templatesjob on main pushes (and non-dry-runworkflow_dispatch), gated onneeds: [regenerate, validate, publish], and executesnode .dataops/cli/bin/dataops.mjs templates syncwith an OIDC token minted for audiencedataops-knowledge-publish. A push to knowledge main therefore refreshes live Templates without a deploy. - Auth for publish/sync. GitHub OIDC only: the bearer must be a GitHub
Actions token whose signature verifies against GitHub's JWKS with audience
dataops-knowledge-publish(backend/src/auth/knowledgePublisher.ts:24-28,:86-108), bound to the configured repository,refs/heads/main, and workflow.github/workflows/validate.yml(:27, policy:77-83, binding check:103-106; env wiring ininfra/template.full.yaml:1330-1331). No other credential reaches those routes, so Orin cannot trigger a sync directly — by design it rides his knowledge-repo pushes' CI (or a deploy,backend/src/handler.ts:327). - Contract docs.
docs/decisions/dataops-knowledge-repository/part-2-contents-and-workflow-templates.md:109-130: the work engine seeds from Git YAML on every deploy; operators edit the effective definition in the portal (Tasks > Templates > Edit definition) or the CLI; both write the samePUT /api/templates/:idcompare-and-swap API validated by the same shared validators the knowledge repo's CI enforces; an edit pins the whole effective definition, a later deploy/sync refreshes the base but never overwrites the pin, andresetrestores the base.part-4-runtime-portal-and-ci.md:73-101specifies the knowledge-repo CI workflow and the OIDC refresh model.
- Commands (
cli/src/commands/templates.mjs:394):list, show, create, update, reset, delete, sync. update(:307-338) sendsPUT /api/templates/:idwith theexpectedVersion/revisionCAS pair (versionPair,:149-168: explicit flags > definition file's own pair > fresh fetch) and--dry-run(:324); conflicts surface as exit-code 3 with the current pair (describeTemplateWriteError,:170-194,cli/README.md:154).reset(:340-359) andcreate(:253-269) preview with--dry-runtoo.- Server gates (
backend/src/routes/templates.ts): update/pin and reset need an active operator or admin (:249,:173); custom create and delete need an admin (:133-135,:278-280); the invoice-reader and knowledge-publisher principals never reach these routes with usable credentials (:106-112). The server rejects client-supplied server-owned fields (rejectServerOwned,:72-77) andversionbodies (:55-63). - Validation parity with the seed path.
normalizeTemplateDefinitionaccepts runtime shape (taskDefinitions) or authored YAML shape (tasks, whatworkflow-templates/*.yamluses) and validates both withvalidateEffectiveDefinition(backend/src/templates/templateEdits.ts:98-125,:128-162), which runs the samevalidateAuthoredTemplatethe knowledge CI and the seed loader run (backend/src/templates/authoredTemplates.ts:136,:340) plus a dependency-graph pass (:144-160). The DB layer re-validates on create and pin (backend/src/db/templates.ts:626,:659).
- Orin's identity. Read-only prod check (
dataops users list): Orin Vale (orin@datatalks.club) holds portal roleadmin, so both gates pass: create/delete (admin-only) and update/reset/pin (operator-or-admin). Interactive actors authenticate by browser/bearer session or a scoped API token (templates:writepermits/api/templateswrites,backend/src/auth/tokenScopes.ts:75-79). - Templates without Git.
dataops templates create --from-file def.yaml [--dry-run]creates a custom Template;dataops templates update <ref> (--from-file … | --task …)pins an edited effective definition;resetrestores the Git base. No Git checkout, no knowledge-repo push, no Developer involved. The portal exposes the same pin via Tasks > Templates > Edit definition (contract doc cited above). - Survival of the auto-sync. The seed preflight never deletes or
overwrites operator work:
customrows are left alone unless an authored Git template later claims the same type, which fails closed (backend/src/templates/authoredTemplates.ts:324-328,:384-387); pinned Git rows keep their effective definition and follow the new base (:391-410). Derived KB views are regenerated after custom create, pin, and reset (backend/src/routes/templates.ts:142-150,:264-266,:205-207; landed in #348 / 23c6c9aa). - Prod evidence (read-only).
dataops templates list:aishl-workshopisorigin=custom(10 tasks) — a Template created through the API path, alive across many knowledge pushes and deploys; 10+ Git templates carrypinned=yes— operator pins surviving syncs;dev-sync-smokeis the live Git-sync proof row. - Conclusion: no gap. The flow the task asks for (create/update without
Developer, validation-guarded, safe preview) is exactly the existing pin
and custom-create design, already documented in the ADR and already used
in prod. The only stale doc was the CLI README: the command table omitted
templates sync, and the Template editing section did not state the event-driven Git re-seed or its CI-only auth.
cli/README.md: addsyncto thetemplatescommand-family row; new "Git stays canonical without a deploy" subsection stating the knowledge-main CI re-seed, its GitHub-OIDC-only auth (interactive 405), and that pins and custom Templates survive it — i.e. the operator self-serve flow needs no Git and no Developer.backend/tests/api-templates.test.ts: one test assertingPOST /api/templates/syncwith an interactive actor is 405 without side effects, locking in the CI-only routing the new doc paragraph describes.DONE-52291ad1.md: this file.