A language-independent concept that decomposes business flows inside service functions into declarative blocks (sequences).

The Problem

Existing SSOT covers only the outside of functions:

Existing SSOTCoverageFunction internals?
OpenAPIAPI routes, parameters, response schemasNo
SQL DDLTable structures, indexes, constraintsNo

Function internals — the business flow of “query -> validate -> create -> respond” — have no place to be declared. You can only understand them by reading the implementation code. Sequences fill this gap.

SSOT Layer Structure

SSaC is the third layer stacked on top of existing SSOT.

OpenAPI       → API boundary (routes, parameters, responses)
SQL DDL       → Data boundary (tables, constraints, indexes)
SSaC          → Function internals (business flows, sequence declarations)
─────────────────────────────────────────────────
Implementation → Generated by codegen (error handling, boilerplate)

The three layers above handle declarations, and implementation code is derived from them. All humans write is declarations.

Core Concepts

sequence

A declaration unit that typifies execution blocks inside a function.

Declare only what (what to do), and the codegen fills in how (how to do it).

10 Fixed Types

TypeRoleExample
authorizePermission checkPolicy query based on action/resource/ID
getResource retrievalModel.FindByID(id) -> result
guard nilExit if result is nullError and exit if not found
guard existsExit if result existsError and exit if already exists
postResource creationModel.Create(fields…) -> result
putResource updateModel.Update(id, fields…)
deleteResource deletionModel.Delete(id)
passwordPassword comparisonExit on hash mismatch
callExternal invocationResource operations not expressible as CRUD, exit on failure
responseReturn responsejson, view, redirect

Because the types are closed, code generation via per-type template matching is possible. This is the basis for symbolic codegen without LLMs.

Scope of model

A model is not limited to database tables. Any resource that can be handled via CRUD is a model. Database queries, file existence checks, and external API calls are all expressed uniformly as get/post/put/delete.

Syntax Examples (Go PoC)

Although a language-independent concept, the reference implementation uses Go comment syntax. Since AI already knows Go AST, there is no additional learning cost.

Simple (Creation)

// @sequence get
// @model Project.FindByID
// @param ProjectID request
// @result project Project

// @sequence guard nil project
// @message "프로젝트가 존재하지 않습니다"

// @sequence post
// @model Session.Create
// @param ProjectID request
// @param Command   request
// @result session Session

// @sequence response json
// @var session
func CreateSession(w http.ResponseWriter, r *http.Request) {}

Complex (Deletion + Authorization + Validation + External Call)

// @sequence authorize
// @action delete
// @resource project
// @id ProjectID

// @sequence get
// @model Project.FindByID
// @param ProjectID request
// @result project Project

// @sequence guard nil project
// @message "프로젝트가 존재하지 않습니다"

// @sequence get
// @model Session.CountByProjectID
// @param ProjectID request
// @result sessionCount int

// @sequence guard exists sessionCount
// @message "하위 세션이 존재하여 삭제할 수 없습니다"

// @sequence call
// @component notification
// @param project.OwnerEmail
// @param "프로젝트가 삭제됩니다"

// @sequence call
// @func cleanupProjectResources
// @param project
// @result cleaned bool

// @sequence delete
// @model Project.Delete
// @param ProjectID request

// @sequence response json
func DeleteProject(w http.ResponseWriter, r *http.Request) {}

Codegen Output

The implementation derived from the sequence declarations above:

func CreateSession(w http.ResponseWriter, r *http.Request) {
    // get
    project, err := projectModel.FindByID(projectID)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    // guard nil
    if project == nil {
        http.Error(w, "프로젝트가 존재하지 않습니다", http.StatusNotFound)
        return
    }

    // post
    session, err := sessionModel.Create(projectID, command)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    // response json
    json.NewEncoder(w).Encode(map[string]interface{}{
        "session": session,
    })
}

Token Cost Comparison

Sequence DeclarationImplementation Code
Lines10-15 lines30-100 lines
Contentwhat (what to do)how (how to do it)
Error handlingNone (generated by codegen)Fully included
Library dependenciesNoneimport, initialization, invocation
When changedWhen business flow changesAutomatically reflected by re-running codegen

Humans maintain only the sequence declarations. When a declaration changes, the implementation code is overwritten by re-running codegen.

Design Principles

early return — The Universal Contract Across All Types

The premise that makes linear enumeration of sequences work. Every sequence except response exits immediately on failure. call is no exception. Read from top to bottom without branching, and you are done.

TypeFailure Condition
authorizeNo permission -> return
getQuery error -> return
guard nilnull -> return
guard existsExists -> return
post/put/deleteDB error -> return
passwordMismatch -> return
callFailure -> return
responseLast (return value)

Because call follows the same contract as guard, there is no need to attach a separate guard after call. The codegen automatically generates error checks and early returns for every call.

@transaction

Function-level metadata. It declares transaction wrapping for the entire function, not a sequence type (not one of the 10 types).

// @transaction
// @sequence get
// @model Account.FindByID
// @param AccountID request
// @result account Account
// ...

Combined with the early return structure, transaction boundaries become natural:

@transaction declared
  → guard failure → rollback + return
  → last sequence succeeds → commit
  → error occurs → rollback + return

Since there is no branching, the transaction boundary is singular: “the entire function.” There is no need to specify begin/end positions; the codegen decides wrapping based solely on the presence or absence of @transaction. If you need two transactions, it means you have two responsibilities. Split the function.

call — A Special Form of model

call has the same essence as model. If model is resource manipulation expressed as CRUD (get/post/put/delete), then call is resource manipulation that cannot be expressed as CRUD. Both invoke operations with external dependencies and return on failure.

Resource manipulation
  +-- model (CRUD)     → get/post/put/delete
  +-- call (non-CRUD)  → component or func
  • @component — Registration-based. Promoted when a recurring pattern appears 3 or more times.
  • @func — Unique logic. Implemented directly by humans or AI.

Complex logic such as branch-and-merge or conditional processing within loops is delegated to call rather than extending sequence. Delegate, but the contract remains the same — exit on failure.

@message

Optional metadata that can be attached to any sequence type. It specifies the message to deliver to the user on failure.

// @sequence guard nil project
// @message "프로젝트가 존재하지 않습니다"

// @sequence post
// @model Session.Create
// @param ProjectID request
// @param Command   request
// @result session Session
// @message "세션 생성에 실패했습니다"

If @message is omitted, the codegen automatically generates a default message from the type and model name. Declare it only when a custom message is needed.

Pure Functions Do Not Exist in the Service Layer

Every block declared in a sequence is an operation with external dependencies. Pure functionality such as format conversion or value computation is handled inside the model or inside the called function, not in the service layer. Service functions only orchestrate, and pure computation belongs to the callee.

Type References

SSaC does not define its own types. It references types derived from existing SSOT.

SourceExample
DB schema (SQL DDL)Project, Session
API specification (OpenAPI)CreateSessionRequest
Interface definitionsFileSystem, Cache

Naming Conventions

CategoryRuleExample
TypePascalCase, imported from SSOTProject, Session
VariablecamelCase, declared via @resultproject, sessionCount
Request fieldPascalCase, extracted from requestProjectID, Command
Reserved variablecamelCase, provided by frameworkcurrentUser, config

Types and variables differ in casing, so they can be distinguished from declarations alone. project is a variable; Project is a type.

Language Extension

SSaC is a language-independent concept. Go is the reference implementation (PoC), and code for other languages can be generated from the same sequence declarations.

Sequence declaration (common)
  |
  +-- Go codegen
  +-- Python codegen
  +-- TypeScript codegen
  +-- ...

The spec (type definitions, syntax, validation rules) and the codegen are separated.

The Go reference implementation is available on GitHub.