[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M69BC8MGSYVC8R7722K5G0BN":3,"skill-same:01M69BC8MGSYVC8R7722K5G0BN":73},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":33,"linkOnly":34,"markdownContent":35,"markdownBody":36,"frontMatter":37,"refName":39,"commitSha":40,"skillDirectory":41,"forksCount":42,"repositoryHtmlUrl":43,"repositoryHomepageUrl":44,"ownerHtmlUrl":45,"ownerBlogUrl":46,"ownerDescription":47,"updatedAt":48,"install":49,"resources":62},"01M69BC8MGSYVC8R7722K5G0BN","regocpp-builtins",null,"Add, update, or remove OPA Rego built-in functions in rego-cpp. Use when: implementing a new builtin, replacing a placeholder with a real implementation, adding a new OPA builtin namespace, updating builtin declarations to match a new OPA version, removing deprecated builtins, or debugging builtin dispatch\u002Fregistration. Covers the full lifecycle: declaration, implementation, dispatch registration, CMake wiring, and OPA conformance testing.","microsoft\u002Frego-cpp","microsoft","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F6154722?v=4","01M698VYDXZ6JW5WH3CRV650R8","Microsoft","01M69BBSWXJ1R932580DT3PX9Z",49,"MIT","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Frego-cpp\u002Fblob\u002Fmain\u002F.github\u002Fskills\u002Fregocpp-builtins\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32],"regocpp builtins","testing","placeholder","cmake","cpp","debugging","conformance testing","update","opa","2026-11-10 10:12:30",false,"---\nname: regocpp-builtins\ndescription: 'Add, update, or remove OPA Rego built-in functions in rego-cpp. Use when: implementing a new builtin, replacing a placeholder with a real implementation, adding a new OPA builtin namespace, updating builtin declarations to match a new OPA version, removing deprecated builtins, or debugging builtin dispatch\u002Fregistration. Covers the full lifecycle: declaration, implementation, dispatch registration, CMake wiring, and OPA conformance testing.'\nargument-hint: 'Describe which builtin(s) to add, update, or remove.'\n---\n\n# rego-cpp Built-in Function Development\n\nAdd, update, and remove OPA Rego built-in functions in rego-cpp.\n\n## When to Use\n\n- Implementing a new builtin (replacing a placeholder or adding from scratch)\n- Adding a new OPA builtin namespace (new `src\u002Fbuiltins\u002F\u003Cnamespace>.cc` file)\n- Updating builtin declarations to track a new OPA version\n- Replacing placeholder stubs with real implementations\n- Removing deprecated builtins\n- Debugging builtin dispatch or registration issues\n\n## Architecture Overview\n\nBuilt-in functions follow a three-layer architecture:\n\n```\nBuiltInsDef::lookup(name)          ← Dispatch layer (src\u002Fbuiltins.cc)\n  → builtins::\u003Cnamespace>(name)    ← Namespace router (src\u002Fbuiltins\u002F\u003Cns>.cc)\n    → \u003Cfunction>_factory()         ← Factory (returns BuiltIn with decl + behavior)\n      → \u003Cfunction>(args)           ← Implementation (unwrap args, compute, return)\n```\n\n### Key Files\n\n| File | Purpose |\n|------|---------|\n| `src\u002Fbuiltins\u002Fbuiltins.hh` | Namespace dispatch function declarations |\n| `src\u002Fbuiltins.cc` | `BuiltInsDef::lookup` — hand-coded binary dispatch tree |\n| `src\u002Fbuiltins\u002F\u003Cnamespace>.cc` | One file per OPA namespace (e.g., `crypto.cc`, `jwt.cc`) |\n| `src\u002FCMakeLists.txt` | SOURCES list — must include new `.cc` files |\n| `include\u002Frego\u002Frego.hh` | Public API — `BuiltIn`, `BuiltInDef`, `UnwrapOpt`, helpers |\n\n### The Binary Dispatch Tree\n\n`BuiltInsDef::lookup` in `src\u002Fbuiltins.cc` uses a **hand-coded binary search tree** (generated by `src\u002Fbuiltins\u002Fbinary_tree.py`) that routes the namespace prefix of a builtin name to the corresponding namespace function. When adding a new namespace, this tree must be regenerated or manually updated.\n\nSpecial case: `\"io\"` prefix routes to `builtins::jwt(name)` for `io.jwt.*` builtins.\n\n## Procedure\n\n### Adding a New Builtin to an Existing Namespace\n\n1. **Read the existing namespace file** (`src\u002Fbuiltins\u002F\u003Cnamespace>.cc`) to understand the patterns in use.\n\n2. **Write the implementation function:**\n   ```cpp\n   Node my_func(const Nodes& args)\n   {\n     \u002F\u002F Unwrap and validate arguments\n     Node x = unwrap_arg(args, UnwrapOpt(0).type(JSONString).func(\"namespace.my_func\"));\n     if (x->type() == Error)\n       return x;\n\n     \u002F\u002F Extract values\n     std::string val = get_string(x);\n\n     \u002F\u002F Compute result\n     std::string result = do_something(val);\n\n     \u002F\u002F Return wrapped result\n     return JSONString ^ result;\n   }\n   ```\n\n3. **Write the factory function:**\n   ```cpp\n   BuiltIn my_func_factory()\n   {\n     const Node my_func_decl = bi::Decl\n       \u003C\u003C (bi::ArgSeq\n           \u003C\u003C (bi::Arg \u003C\u003C (bi::Name ^ \"x\")\n                       \u003C\u003C (bi::Description ^ \"input string\")\n                       \u003C\u003C (bi::Type \u003C\u003C bi::String)))\n       \u003C\u003C (bi::Result \u003C\u003C (bi::Name ^ \"y\")\n                      \u003C\u003C (bi::Description ^ \"result description\")\n                      \u003C\u003C (bi::Type \u003C\u003C bi::String));\n     return BuiltInDef::create({\"namespace.my_func\"}, my_func_decl, my_func);\n   }\n   ```\n\n4. **Register in the namespace router** (the public function at the bottom of the file):\n   ```cpp\n   BuiltIn namespace_func(const Location& name)\n   {\n     \u002F\u002F ... existing dispatches ...\n     if (view == \"my_func\")\n     {\n       return my_func_factory();\n     }\n     return nullptr;\n   }\n   ```\n\n5. **Run OPA conformance tests:**\n   ```bash\n   cd build && .\u002Ftests\u002Frego_test -wf opa\u002Fv1\u002Ftest\u002Fcases\u002Ftestdata\u002Fv1\u002F\u003Ctestdir>\n   ```\n\n### Adding a New Namespace\n\nWhen adding an entirely new OPA namespace (new `.cc` file):\n\n1. **Create `src\u002Fbuiltins\u002F\u003Cnamespace>.cc`** following the pattern of existing files. Include the anonymous namespace for internal functions and the `rego::builtins` namespace for the public dispatch function.\n\n2. **Declare the dispatch function** in `src\u002Fbuiltins\u002Fbuiltins.hh`:\n   ```cpp\n   namespace rego::builtins {\n     BuiltIn my_namespace(const Location& name);\n   }\n   ```\n\n3. **Add to the dispatch tree** in `src\u002Fbuiltins.cc` — find the correct position in `BuiltInsDef::lookup` based on the namespace prefix string and add the routing branch. Alternatively, regenerate the tree using `src\u002Fbuiltins\u002Fbinary_tree.py`.\n\n4. **Add the source file to `src\u002FCMakeLists.txt`:**\n   ```cmake\n   set( SOURCES\n     # ... existing sources ...\n     builtins\u002F\u003Cnamespace>.cc\n   )\n   ```\n\n5. **Rebuild and test.**\n\n### Replacing a Placeholder with a Real Implementation\n\nMany builtins are registered as `BuiltInDef::placeholder(...)` which returns an error message when called. To replace:\n\n1. **Keep the existing declaration** (`bi::Decl \u003C\u003C ...`) — it defines the argument and return types.\n\n2. **Write the implementation function** that takes `const Nodes& args` and returns a `Node`.\n\n3. **Change the factory** from:\n   ```cpp\n   return BuiltInDef::placeholder({\"name\"}, decl, \"message\");\n   ```\n   to:\n   ```cpp\n   return BuiltInDef::create({\"name\"}, decl, implementation_function);\n   ```\n\n4. **If the builtin requires a platform dependency** (e.g., OpenSSL), use compile-time guards:\n   ```cpp\n   #ifdef REGOCPP_HAS_CRYPTO\n     return BuiltInDef::create({\"crypto.sha256\"}, sha256_decl, sha256);\n   #else\n     return BuiltInDef::placeholder({\"crypto.sha256\"}, sha256_decl, Message);\n   #endif\n   ```\n\n### Removing a Deprecated Builtin\n\n1. Check the deprecated list in `BuiltInsDef::is_deprecated` in `src\u002Fbuiltins.cc`.\n2. Add the builtin name to the `deprecated` vector if not already present.\n3. Deprecated builtins return `RegoTypeError` when called, regardless of implementation.\n\n## Key Patterns\n\n### Argument Unwrapping\n\n```cpp\n\u002F\u002F Single type\nNode x = unwrap_arg(args, UnwrapOpt(0).type(JSONString));\n\n\u002F\u002F Multiple accepted types\nNode x = unwrap_arg(args, UnwrapOpt(0).types({JSONString, Int, Float}));\n\n\u002F\u002F With function name for error messages\nNode x = unwrap_arg(args, UnwrapOpt(0).type(JSONString).func(\"crypto.sha256\"));\n\n\u002F\u002F With custom error details\nNode x = unwrap_arg(args, UnwrapOpt(0).type(JSONString)\n  .func(\"crypto.sha256\").specify_number(true));\n```\n\nAlways check for errors after unwrapping:\n```cpp\nif (x->type() == Error)\n  return x;\n```\n\n### Value Extraction\n\n```cpp\nstd::string val = get_string(node);            \u002F\u002F strips quotes\nBigInt ival = get_int(node);\ndouble dval = get_double(node);\nbool bval = get_bool(node);\n\n\u002F\u002F Optional variants (return std::nullopt on wrong type)\nauto maybe_str = try_get_string(node);\nauto maybe_int = try_get_int(node);\n```\n\n### Result Construction\n\nFor **scalar** results, return bare token nodes:\n```cpp\nreturn JSONString ^ \"result\";              \u002F\u002F string result\nreturn Int ^ BigInt(42);                   \u002F\u002F integer result\nreturn Float ^ 3.14;                       \u002F\u002F float result\nreturn True ^ \"true\";                      \u002F\u002F boolean true\nreturn False ^ \"false\";                    \u002F\u002F boolean false\nreturn Undefined;                          \u002F\u002F undefined (no result)\nreturn err(args[0], \"error message\");      \u002F\u002F error\nreturn err(args[0], \"msg\", EvalTypeError); \u002F\u002F typed error\n```\n\nFor **compound** results (arrays, objects, nested structures), use the rego API helpers declared in `include\u002Frego\u002Frego.hh`. These handle all Term\u002FScalar wrapping and cloning correctly, avoiding well-formedness errors:\n\n```cpp\n\u002F\u002F Booleans, strings, numbers, null — produce correctly-wrapped Scalar nodes\nreturn boolean(true);                       \u002F\u002F same as True ^ \"true\" but self-documenting\nreturn rego::string(\"hello\");               \u002F\u002F note: qualify as rego::string to avoid std::string\nreturn number(3.14);\nreturn null();\n\n\u002F\u002F Arrays — items are auto-wrapped via Resolver::to_term()\nreturn array({boolean(true), rego::string(\"ok\")});\nreturn array({header_term, payload_term, rego::string(sig_hex)});\n\n\u002F\u002F Objects — built from object_item() nodes\nreturn object({\n  object_item(rego::string(\"key\"), rego::string(\"value\")),\n  object_item(rego::string(\"count\"), number(42.0))\n});\n\n\u002F\u002F Nested: array of [bool, object, object]\nreturn array({boolean(false), object({}), object({})});\n```\n\n**IMPORTANT**: Never manually construct compound result nodes with `NodeDef::create(Array)`, `Term \u003C\u003C`, `Scalar \u003C\u003C`, or `push_back`. These patterns produce nodes that violate well-formedness rules. Always use `array()`, `object()`, `object_item()`, `boolean()`, `rego::string()`, `number()`, and `null()` instead. These helpers call `Resolver::to_term()` internally, which handles all wrapping (Term, Scalar) and cloning correctly regardless of whether the input is a bare token, a Scalar, or an already-wrapped Term.\n\n### Declaration Types\n\n```cpp\nbi::String, bi::Number, bi::Boolean, bi::Null, bi::Any  \u002F\u002F Scalar types\nbi::DynamicArray \u003C\u003C (bi::Type \u003C\u003C bi::String)             \u002F\u002F array of strings\nbi::DynamicObject \u003C\u003C (bi::Type \u003C\u003C bi::String) \u003C\u003C (bi::Type \u003C\u003C bi::Any)  \u002F\u002F object\nbi::StaticArray \u003C\u003C (bi::Type \u003C\u003C bi::Boolean) \u003C\u003C (bi::Type \u003C\u003C bi::String) \u002F\u002F [bool, string]\nbi::Set \u003C\u003C (bi::Type \u003C\u003C bi::String)                      \u002F\u002F set of strings\n```\n\n### Shared Code Between Namespaces\n\nWhen multiple namespaces share implementation logic (e.g., crypto primitives shared between `crypto.*` and `io.jwt.*`):\n\n1. Create a shared internal header: `src\u002Fbuiltins\u002F\u003Cshared_core>.hh`\n2. Create a shared implementation: `src\u002Fbuiltins\u002F\u003Cshared_core>.cc`\n3. Add the `.cc` to `src\u002FCMakeLists.txt` SOURCES\n4. Include from both namespace files\n\nUse compile-time backend selection for platform-dependent code:\n```cmake\nset(REGOCPP_CRYPTO_BACKEND \"\" CACHE STRING \"Crypto backend: openssl3, '' (disabled)\")\nif(REGOCPP_CRYPTO_BACKEND STREQUAL \"openssl3\")\n  find_package(OpenSSL 3.0 REQUIRED)\n  target_link_libraries(rego PUBLIC OpenSSL::SSL OpenSSL::Crypto)\n  target_compile_definitions(rego PUBLIC REGOCPP_HAS_CRYPTO=1 REGOCPP_CRYPTO_OPENSSL3=1)\nendif()\n```\n\n### Parsing JSON Inside Builtins\n\nWhen a builtin needs to inspect or validate JSON data (e.g., JWT headers\u002Fpayloads, JWK keys), **always use the Trieste JSON parser** (`\u003Ctrieste\u002Fjson.h>`) instead of manual string searching. Manual JSON parsing (e.g., `json.find(\"\\\"field\\\"\")`, character-by-character extraction) is brittle and will break on whitespace variations, escaped characters, nested structures, and field-name substrings.\n\n**Two JSON AST types exist** — use the right one for the task:\n\n| AST type | Namespace | Produced by | Use for |\n|----------|-----------|-------------|---------|\n| JSON AST | `json::Object`, `json::Array`, `json::String`, ... | `json::reader().synthetic(str).read()` | Internal inspection: field lookup, type checking, claim validation |\n| Rego AST | `rego::Object`, `rego::Array`, `rego::JSONString`, ... | `json::reader().synthetic(str) >> json_to_rego(true)` | Return values to the Rego evaluator |\n\n**For internal inspection**, parse into the JSON AST and use `json::select` with RFC 6901 JSON Pointer paths:\n\n```cpp\n#include \u003Ctrieste\u002Fjson.h>\n\n\u002F\u002F Parse raw JSON string into JSON AST\nNode ast = parse_json(json_str);  \u002F\u002F json::reader().synthetic(str).read()\n\n\u002F\u002F Field lookup — paths use RFC 6901 format with leading \"\u002F\"\nauto alg = ::json::select_string(ast, {\"\u002Falg\"});     \u002F\u002F std::optional\u003CLocation>\nauto exp = ::json::select_number(ast, {\"\u002Fexp\"});      \u002F\u002F std::optional\u003Cdouble>\nauto ok  = ::json::select_boolean(ast, {\"\u002Factive\"});  \u002F\u002F std::optional\u003Cbool>\n\n\u002F\u002F Check field existence (select returns Error node if missing)\nNode field = ::json::select(ast, {\"\u002Fenc\"});\nif (field->type() != Error) { \u002F* field exists *\u002F }\n\n\u002F\u002F Check field type\nNode aud = ::json::select(ast, {\"\u002Faud\"});\nif (aud->type() == ::json::Array) { \u002F* it's an array *\u002F }\n\n\u002F\u002F Nested paths\nauto deep = ::json::select_string(ast, {\"\u002Ffoo\u002Fbar\u002Fbaz\"});\n```\n\n**CRITICAL**: The path argument is a `Location` initialized from a string literal with `{\"\u002Ffield\"}` syntax. The leading `\u002F` is required by RFC 6901. Using `Location(\"field\")` without the `\u002F` will fail silently.\n\n**For return values**, use `parse_json_to_term()` (which runs `json_to_rego`) to produce Rego-typed nodes suitable for the evaluator. Parse into the JSON AST first for validation, then convert to Rego terms only at the end when building the return value.\n\n**For Rego Object nodes** (e.g., constraint objects passed as builtin arguments), use `try_get_string(node)` and `try_get_double(node)` — these already handle Term\u002FScalar unwrapping. Do NOT navigate with `node \u002F Scalar` before calling them.\n\n## Testing\n\n### OPA Conformance Tests\n\nOPA test cases live in `build\u002Fopa\u002Fv1\u002Ftest\u002Fcases\u002Ftestdata\u002Fv1\u002F\u003Ctestdir>\u002F`. Directory names match OPA builtin names with no separators (e.g., `cryptohmacsha256`, `jwtdecodeverify`).\n\n```bash\n# Run a specific builtin's tests\ncd build && .\u002Ftests\u002Frego_test -wf opa\u002Fv1\u002Ftest\u002Fcases\u002Ftestdata\u002Fv1\u002F\u003Ctestdir>\n\n# List available test directories\nls build\u002Fopa\u002Fv1\u002Ftest\u002Fcases\u002Ftestdata\u002Fv1\u002F | grep \u003Cpattern>\n\n# Run all OPA tests (slow)\nctest -R rego_test_opa\n```\n\n### Custom Test Cases\n\nAdd YAML test cases to `tests\u002Fregocpp.yaml` or `tests\u002Fbugs.yaml`:\n\n```yaml\n- note: mybuiltin\u002Fbasic\n  query: data.test.p = x\n  modules:\n    - |\n      package test\n      p := crypto.sha256(\"hello\")\n  want_result:\n    - x: 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824\n```\n\n### Error Message Matching\n\nError messages must match OPA exactly — conformance tests compare strings literally. When implementing error handling, check OPA's actual error output for the builtin.\n\n## Reference Plans\n\n- [Crypto & JWT Implementation Plan](.\u002Freferences\u002Fcrypto-jwt-plan.md) — Phased plan for implementing `crypto.*` and `io.jwt.*` builtins with a shared OpenSSL core\n","# rego-cpp Built-in Function Development\n\nAdd, update, and remove OPA Rego built-in functions in rego-cpp.\n\n## When to Use\n\n- Implementing a new builtin (replacing a placeholder or adding from scratch)\n- Adding a new OPA builtin namespace (new `src\u002Fbuiltins\u002F\u003Cnamespace>.cc` file)\n- Updating builtin declarations to track a new OPA version\n- Replacing placeholder stubs with real implementations\n- Removing deprecated builtins\n- Debugging builtin dispatch or registration issues\n\n## Architecture Overview\n\nBuilt-in functions follow a three-layer architecture:\n\n```\nBuiltInsDef::lookup(name)          ← Dispatch layer (src\u002Fbuiltins.cc)\n  → builtins::\u003Cnamespace>(name)    ← Namespace router (src\u002Fbuiltins\u002F\u003Cns>.cc)\n    → \u003Cfunction>_factory()         ← Factory (returns BuiltIn with decl + behavior)\n      → \u003Cfunction>(args)           ← Implementation (unwrap args, compute, return)\n```\n\n### Key Files\n\n| File | Purpose |\n|------|---------|\n| `src\u002Fbuiltins\u002Fbuiltins.hh` | Namespace dispatch function declarations |\n| `src\u002Fbuiltins.cc` | `BuiltInsDef::lookup` — hand-coded binary dispatch tree |\n| `src\u002Fbuiltins\u002F\u003Cnamespace>.cc` | One file per OPA namespace (e.g., `crypto.cc`, `jwt.cc`) |\n| `src\u002FCMakeLists.txt` | SOURCES list — must include new `.cc` files |\n| `include\u002Frego\u002Frego.hh` | Public API — `BuiltIn`, `BuiltInDef`, `UnwrapOpt`, helpers |\n\n### The Binary Dispatch Tree\n\n`BuiltInsDef::lookup` in `src\u002Fbuiltins.cc` uses a **hand-coded binary search tree** (generated by `src\u002Fbuiltins\u002Fbinary_tree.py`) that routes the namespace prefix of a builtin name to the corresponding namespace function. When adding a new namespace, this tree must be regenerated or manually updated.\n\nSpecial case: `\"io\"` prefix routes to `builtins::jwt(name)` for `io.jwt.*` builtins.\n\n## Procedure\n\n### Adding a New Builtin to an Existing Namespace\n\n1. **Read the existing namespace file** (`src\u002Fbuiltins\u002F\u003Cnamespace>.cc`) to understand the patterns in use.\n\n2. **Write the implementation function:**\n   ```cpp\n   Node my_func(const Nodes& args)\n   {\n     \u002F\u002F Unwrap and validate arguments\n     Node x = unwrap_arg(args, UnwrapOpt(0).type(JSONString).func(\"namespace.my_func\"));\n     if (x->type() == Error)\n       return x;\n\n     \u002F\u002F Extract values\n     std::string val = get_string(x);\n\n     \u002F\u002F Compute result\n     std::string result = do_something(val);\n\n     \u002F\u002F Return wrapped result\n     return JSONString ^ result;\n   }\n   ```\n\n3. **Write the factory function:**\n   ```cpp\n   BuiltIn my_func_factory()\n   {\n     const Node my_func_decl = bi::Decl\n       \u003C\u003C (bi::ArgSeq\n           \u003C\u003C (bi::Arg \u003C\u003C (bi::Name ^ \"x\")\n                       \u003C\u003C (bi::Description ^ \"input string\")\n                       \u003C\u003C (bi::Type \u003C\u003C bi::String)))\n       \u003C\u003C (bi::Result \u003C\u003C (bi::Name ^ \"y\")\n                      \u003C\u003C (bi::Description ^ \"result description\")\n                      \u003C\u003C (bi::Type \u003C\u003C bi::String));\n     return BuiltInDef::create({\"namespace.my_func\"}, my_func_decl, my_func);\n   }\n   ```\n\n4. **Register in the namespace router** (the public function at the bottom of the file):\n   ```cpp\n   BuiltIn namespace_func(const Location& name)\n   {\n     \u002F\u002F ... existing dispatches ...\n     if (view == \"my_func\")\n     {\n       return my_func_factory();\n     }\n     return nullptr;\n   }\n   ```\n\n5. **Run OPA conformance tests:**\n   ```bash\n   cd build && .\u002Ftests\u002Frego_test -wf opa\u002Fv1\u002Ftest\u002Fcases\u002Ftestdata\u002Fv1\u002F\u003Ctestdir>\n   ```\n\n### Adding a New Namespace\n\nWhen adding an entirely new OPA namespace (new `.cc` file):\n\n1. **Create `src\u002Fbuiltins\u002F\u003Cnamespace>.cc`** following the pattern of existing files. Include the anonymous namespace for internal functions and the `rego::builtins` namespace for the public dispatch function.\n\n2. **Declare the dispatch function** in `src\u002Fbuiltins\u002Fbuiltins.hh`:\n   ```cpp\n   namespace rego::builtins {\n     BuiltIn my_namespace(const Location& name);\n   }\n   ```\n\n3. **Add to the dispatch tree** in `src\u002Fbuiltins.cc` — find the correct position in `BuiltInsDef::lookup` based on the namespace prefix string and add the routing branch. Alternatively, regenerate the tree using `src\u002Fbuiltins\u002Fbinary_tree.py`.\n\n4. **Add the source file to `src\u002FCMakeLists.txt`:**\n   ```cmake\n   set( SOURCES\n     # ... existing sources ...\n     builtins\u002F\u003Cnamespace>.cc\n   )\n   ```\n\n5. **Rebuild and test.**\n\n### Replacing a Placeholder with a Real Implementation\n\nMany builtins are registered as `BuiltInDef::placeholder(...)` which returns an error message when called. To replace:\n\n1. **Keep the existing declaration** (`bi::Decl \u003C\u003C ...`) — it defines the argument and return types.\n\n2. **Write the implementation function** that takes `const Nodes& args` and returns a `Node`.\n\n3. **Change the factory** from:\n   ```cpp\n   return BuiltInDef::placeholder({\"name\"}, decl, \"message\");\n   ```\n   to:\n   ```cpp\n   return BuiltInDef::create({\"name\"}, decl, implementation_function);\n   ```\n\n4. **If the builtin requires a platform dependency** (e.g., OpenSSL), use compile-time guards:\n   ```cpp\n   #ifdef REGOCPP_HAS_CRYPTO\n     return BuiltInDef::create({\"crypto.sha256\"}, sha256_decl, sha256);\n   #else\n     return BuiltInDef::placeholder({\"crypto.sha256\"}, sha256_decl, Message);\n   #endif\n   ```\n\n### Removing a Deprecated Builtin\n\n1. Check the deprecated list in `BuiltInsDef::is_deprecated` in `src\u002Fbuiltins.cc`.\n2. Add the builtin name to the `deprecated` vector if not already present.\n3. Deprecated builtins return `RegoTypeError` when called, regardless of implementation.\n\n## Key Patterns\n\n### Argument Unwrapping\n\n```cpp\n\u002F\u002F Single type\nNode x = unwrap_arg(args, UnwrapOpt(0).type(JSONString));\n\n\u002F\u002F Multiple accepted types\nNode x = unwrap_arg(args, UnwrapOpt(0).types({JSONString, Int, Float}));\n\n\u002F\u002F With function name for error messages\nNode x = unwrap_arg(args, UnwrapOpt(0).type(JSONString).func(\"crypto.sha256\"));\n\n\u002F\u002F With custom error details\nNode x = unwrap_arg(args, UnwrapOpt(0).type(JSONString)\n  .func(\"crypto.sha256\").specify_number(true));\n```\n\nAlways check for errors after unwrapping:\n```cpp\nif (x->type() == Error)\n  return x;\n```\n\n### Value Extraction\n\n```cpp\nstd::string val = get_string(node);            \u002F\u002F strips quotes\nBigInt ival = get_int(node);\ndouble dval = get_double(node);\nbool bval = get_bool(node);\n\n\u002F\u002F Optional variants (return std::nullopt on wrong type)\nauto maybe_str = try_get_string(node);\nauto maybe_int = try_get_int(node);\n```\n\n### Result Construction\n\nFor **scalar** results, return bare token nodes:\n```cpp\nreturn JSONString ^ \"result\";              \u002F\u002F string result\nreturn Int ^ BigInt(42);                   \u002F\u002F integer result\nreturn Float ^ 3.14;                       \u002F\u002F float result\nreturn True ^ \"true\";                      \u002F\u002F boolean true\nreturn False ^ \"false\";                    \u002F\u002F boolean false\nreturn Undefined;                          \u002F\u002F undefined (no result)\nreturn err(args[0], \"error message\");      \u002F\u002F error\nreturn err(args[0], \"msg\", EvalTypeError); \u002F\u002F typed error\n```\n\nFor **compound** results (arrays, objects, nested structures), use the rego API helpers declared in `include\u002Frego\u002Frego.hh`. These handle all Term\u002FScalar wrapping and cloning correctly, avoiding well-formedness errors:\n\n```cpp\n\u002F\u002F Booleans, strings, numbers, null — produce correctly-wrapped Scalar nodes\nreturn boolean(true);                       \u002F\u002F same as True ^ \"true\" but self-documenting\nreturn rego::string(\"hello\");               \u002F\u002F note: qualify as rego::string to avoid std::string\nreturn number(3.14);\nreturn null();\n\n\u002F\u002F Arrays — items are auto-wrapped via Resolver::to_term()\nreturn array({boolean(true), rego::string(\"ok\")});\nreturn array({header_term, payload_term, rego::string(sig_hex)});\n\n\u002F\u002F Objects — built from object_item() nodes\nreturn object({\n  object_item(rego::string(\"key\"), rego::string(\"value\")),\n  object_item(rego::string(\"count\"), number(42.0))\n});\n\n\u002F\u002F Nested: array of [bool, object, object]\nreturn array({boolean(false), object({}), object({})});\n```\n\n**IMPORTANT**: Never manually construct compound result nodes with `NodeDef::create(Array)`, `Term \u003C\u003C`, `Scalar \u003C\u003C`, or `push_back`. These patterns produce nodes that violate well-formedness rules. Always use `array()`, `object()`, `object_item()`, `boolean()`, `rego::string()`, `number()`, and `null()` instead. These helpers call `Resolver::to_term()` internally, which handles all wrapping (Term, Scalar) and cloning correctly regardless of whether the input is a bare token, a Scalar, or an already-wrapped Term.\n\n### Declaration Types\n\n```cpp\nbi::String, bi::Number, bi::Boolean, bi::Null, bi::Any  \u002F\u002F Scalar types\nbi::DynamicArray \u003C\u003C (bi::Type \u003C\u003C bi::String)             \u002F\u002F array of strings\nbi::DynamicObject \u003C\u003C (bi::Type \u003C\u003C bi::String) \u003C\u003C (bi::Type \u003C\u003C bi::Any)  \u002F\u002F object\nbi::StaticArray \u003C\u003C (bi::Type \u003C\u003C bi::Boolean) \u003C\u003C (bi::Type \u003C\u003C bi::String) \u002F\u002F [bool, string]\nbi::Set \u003C\u003C (bi::Type \u003C\u003C bi::String)                      \u002F\u002F set of strings\n```\n\n### Shared Code Between Namespaces\n\nWhen multiple namespaces share implementation logic (e.g., crypto primitives shared between `crypto.*` and `io.jwt.*`):\n\n1. Create a shared internal header: `src\u002Fbuiltins\u002F\u003Cshared_core>.hh`\n2. Create a shared implementation: `src\u002Fbuiltins\u002F\u003Cshared_core>.cc`\n3. Add the `.cc` to `src\u002FCMakeLists.txt` SOURCES\n4. Include from both namespace files\n\nUse compile-time backend selection for platform-dependent code:\n```cmake\nset(REGOCPP_CRYPTO_BACKEND \"\" CACHE STRING \"Crypto backend: openssl3, '' (disabled)\")\nif(REGOCPP_CRYPTO_BACKEND STREQUAL \"openssl3\")\n  find_package(OpenSSL 3.0 REQUIRED)\n  target_link_libraries(rego PUBLIC OpenSSL::SSL OpenSSL::Crypto)\n  target_compile_definitions(rego PUBLIC REGOCPP_HAS_CRYPTO=1 REGOCPP_CRYPTO_OPENSSL3=1)\nendif()\n```\n\n### Parsing JSON Inside Builtins\n\nWhen a builtin needs to inspect or validate JSON data (e.g., JWT headers\u002Fpayloads, JWK keys), **always use the Trieste JSON parser** (`\u003Ctrieste\u002Fjson.h>`) instead of manual string searching. Manual JSON parsing (e.g., `json.find(\"\\\"field\\\"\")`, character-by-character extraction) is brittle and will break on whitespace variations, escaped characters, nested structures, and field-name substrings.\n\n**Two JSON AST types exist** — use the right one for the task:\n\n| AST type | Namespace | Produced by | Use for |\n|----------|-----------|-------------|---------|\n| JSON AST | `json::Object`, `json::Array`, `json::String`, ... | `json::reader().synthetic(str).read()` | Internal inspection: field lookup, type checking, claim validation |\n| Rego AST | `rego::Object`, `rego::Array`, `rego::JSONString`, ... | `json::reader().synthetic(str) >> json_to_rego(true)` | Return values to the Rego evaluator |\n\n**For internal inspection**, parse into the JSON AST and use `json::select` with RFC 6901 JSON Pointer paths:\n\n```cpp\n#include \u003Ctrieste\u002Fjson.h>\n\n\u002F\u002F Parse raw JSON string into JSON AST\nNode ast = parse_json(json_str);  \u002F\u002F json::reader().synthetic(str).read()\n\n\u002F\u002F Field lookup — paths use RFC 6901 format with leading \"\u002F\"\nauto alg = ::json::select_string(ast, {\"\u002Falg\"});     \u002F\u002F std::optional\u003CLocation>\nauto exp = ::json::select_number(ast, {\"\u002Fexp\"});      \u002F\u002F std::optional\u003Cdouble>\nauto ok  = ::json::select_boolean(ast, {\"\u002Factive\"});  \u002F\u002F std::optional\u003Cbool>\n\n\u002F\u002F Check field existence (select returns Error node if missing)\nNode field = ::json::select(ast, {\"\u002Fenc\"});\nif (field->type() != Error) { \u002F* field exists *\u002F }\n\n\u002F\u002F Check field type\nNode aud = ::json::select(ast, {\"\u002Faud\"});\nif (aud->type() == ::json::Array) { \u002F* it's an array *\u002F }\n\n\u002F\u002F Nested paths\nauto deep = ::json::select_string(ast, {\"\u002Ffoo\u002Fbar\u002Fbaz\"});\n```\n\n**CRITICAL**: The path argument is a `Location` initialized from a string literal with `{\"\u002Ffield\"}` syntax. The leading `\u002F` is required by RFC 6901. Using `Location(\"field\")` without the `\u002F` will fail silently.\n\n**For return values**, use `parse_json_to_term()` (which runs `json_to_rego`) to produce Rego-typed nodes suitable for the evaluator. Parse into the JSON AST first for validation, then convert to Rego terms only at the end when building the return value.\n\n**For Rego Object nodes** (e.g., constraint objects passed as builtin arguments), use `try_get_string(node)` and `try_get_double(node)` — these already handle Term\u002FScalar unwrapping. Do NOT navigate with `node \u002F Scalar` before calling them.\n\n## Testing\n\n### OPA Conformance Tests\n\nOPA test cases live in `build\u002Fopa\u002Fv1\u002Ftest\u002Fcases\u002Ftestdata\u002Fv1\u002F\u003Ctestdir>\u002F`. Directory names match OPA builtin names with no separators (e.g., `cryptohmacsha256`, `jwtdecodeverify`).\n\n```bash\n# Run a specific builtin's tests\ncd build && .\u002Ftests\u002Frego_test -wf opa\u002Fv1\u002Ftest\u002Fcases\u002Ftestdata\u002Fv1\u002F\u003Ctestdir>\n\n# List available test directories\nls build\u002Fopa\u002Fv1\u002Ftest\u002Fcases\u002Ftestdata\u002Fv1\u002F | grep \u003Cpattern>\n\n# Run all OPA tests (slow)\nctest -R rego_test_opa\n```\n\n### Custom Test Cases\n\nAdd YAML test cases to `tests\u002Fregocpp.yaml` or `tests\u002Fbugs.yaml`:\n\n```yaml\n- note: mybuiltin\u002Fbasic\n  query: data.test.p = x\n  modules:\n    - |\n      package test\n      p := crypto.sha256(\"hello\")\n  want_result:\n    - x: 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824\n```\n\n### Error Message Matching\n\nError messages must match OPA exactly — conformance tests compare strings literally. When implementing error handling, check OPA's actual error output for the builtin.\n\n## Reference Plans\n\n- [Crypto & JWT Implementation Plan](.\u002Freferences\u002Fcrypto-jwt-plan.md) — Phased plan for implementing `crypto.*` and `io.jwt.*` builtins with a shared OpenSSL core\n",{"name":5,"description":7,"argument-hint":38},"Describe which builtin(s) to add, update, or remove.","main","f424aab83f0181a770940c25ab030619cde99616",".github\u002Fskills\u002Fregocpp-builtins",19,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Frego-cpp","https:\u002F\u002Fmicrosoft.github.io\u002Frego-cpp\u002F","https:\u002F\u002Fgithub.com\u002Fmicrosoft","https:\u002F\u002Fopensource.microsoft.com","Open source projects and samples from Microsoft","2026-10-16 11:55:01",{"source":8,"skillName":5,"commands":50,"prompt":60,"zipAvailable":61},[51,54,57],{"tool":52,"command":53},"npx","npx skills add microsoft\u002Frego-cpp --skill regocpp-builtins",{"tool":55,"command":56},"bunx","bunx skills add microsoft\u002Frego-cpp --skill regocpp-builtins",{"tool":58,"command":59},"pnpm","pnpm dlx skills add microsoft\u002Frego-cpp --skill regocpp-builtins","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Frego-cpp\u002Fblob\u002Fmain\u002F.github\u002Fskills\u002Fregocpp-builtins\u002FSKILL.md",true,[63,69],{"path":64,"resourceType":65,"resourceTypeDesc":66,"sizeBytes":67,"sourceHtmlUrl":68},"references\u002Fcrypto-jwt-plan.md","REFERENCE","参考文档",9054,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Frego-cpp\u002Fblob\u002Fmain\u002F.github\u002Fskills\u002Fregocpp-builtins\u002Freferences\u002Fcrypto-jwt-plan.md",{"path":70,"resourceType":65,"resourceTypeDesc":66,"sizeBytes":71,"sourceHtmlUrl":72},"references\u002FPHASE5-BCRYPT.md",7922,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Frego-cpp\u002Fblob\u002Fmain\u002F.github\u002Fskills\u002Fregocpp-builtins\u002Freferences\u002FPHASE5-BCRYPT.md",[74,83,95,106,126,138],{"skillNo":75,"name":76,"nameZh":6,"description":77,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":78,"categories":79,"keywords":80,"publishedAt":33},"01M69BCB9YED816F7ZZJBMKBB9","trieste-dev","Plan and implement Trieste-based compiler passes and AST transformations for rego-cpp. Use when: adding new compiler passes, modifying AST structure, implementing new Rego language features, debugging pass failures, working with well-formedness definitions, or performing any multi-step implementation that touches the Trieste pass pipeline. Includes the multi-planner approach for complex features.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Frego-cpp\u002Fblob\u002Fmain\u002F.github\u002Fskills\u002Ftrieste-dev\u002FSKILL.md",[],[81,29,28,82],"trieste dev","implement",{"skillNo":84,"name":85,"nameZh":6,"description":86,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":87,"categories":88,"keywords":90,"publishedAt":33},"01M69BC603T40X4P9M21KQ4AQV","rego-fuzzer","Pass the rego-cpp Trieste fuzzer for a given pass collection. Use when: verifying that compiler passes are robust to all valid WF inputs, debugging fuzzer failures, fixing generative testing regressions, or validating pass changes against random inputs. The fuzzer generates random ASTs from the Trieste well-formedness chain and checks that each pass handles all structurally valid inputs without crashing or producing malformed output.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Frego-cpp\u002Fblob\u002Fmain\u002F.github\u002Fskills\u002Frego-fuzzer\u002FSKILL.md",[89],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[91,92,93,29,28,94,25],"rego fuzzer","fuzzer","run","valid",{"skillNo":96,"name":97,"nameZh":6,"description":98,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":99,"categories":100,"keywords":101,"publishedAt":33},"01M69BC3B665PTKXB0C2EC5AMW","opa-compat-check","Check OPA Rego version compatibility for rego-cpp. Use when: updating OPA version, checking for new OPA releases, auditing rego-cpp compatibility, planning OPA upgrade work, reviewing OPA release notes for rego-cpp impact. Fetches OPA release notes, compares with current rego-cpp support, and produces an actionable compatibility report.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Frego-cpp\u002Fblob\u002Fmain\u002F.github\u002Fskills\u002Fopa-compat-check\u002FSKILL.md",[],[102,32,28,103,104,105],"opa compat check","release notes","notes","support",{"skillNo":107,"name":108,"nameZh":6,"description":109,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":110,"categories":111,"keywords":120,"publishedAt":33},"01M69BC13CH5R7DWNJW5HGDAHY","multi-perspective-planning","Run a multi-perspective planning process for non-trivial design decisions. Use when: the shape of a solution is uncertain, planning new language features, new passes, API changes, AST restructuring, or cross-cutting concerns. Spawns four competing sub-planners, synthesises with rebuttal resolution, and stress-tests via adversarial review. Supports checkpointing so planning can be restarted at any step.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Frego-cpp\u002Fblob\u002Fmain\u002F.github\u002Fskills\u002Fmulti-perspective-planning\u002FSKILL.md",[112,115],{"categoryNo":113,"categoryName":114,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":116,"categoryName":117,"taxonomyType":118,"taxonomyTypeDesc":119},"01JBSEEDCAT000000000000032","设计师","PROFESSION","适用职业",[121,93,122,123,124,125],"multi perspective planning","adversarial review","api changes","review","design",{"skillNo":127,"name":128,"nameZh":6,"description":129,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":130,"categories":131,"keywords":132,"publishedAt":33},"01M69BBYNK9HWTBDB91DTBMX98","finalize-pr","Finalize a rego-cpp PR for release. Use when: wrapping up a branch, preparing a release, cutting a version, or when instructed to finalize a PR. Confirms review\u002Fremediation is done, determines branch changes, bumps the version across the library and all wrappers, writes a CHANGELOG entry, updates documentation, runs the editor lens over new comments, and runs format\u002Fbuild\u002Ftest gates to give CI the best chance of passing.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Frego-cpp\u002Fblob\u002Fmain\u002F.github\u002Fskills\u002Ffinalize-pr\u002FSKILL.md",[],[133,134,135,124,28,136,137],"finalize pr","pr","editor","test","documentation",{"skillNo":139,"name":140,"nameZh":6,"description":141,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":142,"categories":143,"keywords":150,"publishedAt":33},"01M69BBW6P4PMXJ97KWF86MGA1","code-review","Perform a multi-perspective code review of rego-cpp changes. Use when: reviewing a release, auditing a branch diff, evaluating a PR, or performing a pre-merge code review. Launches four parallel constructive review subagents (Security, Performance, Usability, Conservative), synthesises findings, then runs a sequential adversarial gap-analysis pass. Verifies key findings, produces a unified report with severity-ranked findings and actionable remediation recommendations.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Frego-cpp\u002Fblob\u002Fmain\u002F.github\u002Fskills\u002Fcode-review\u002FSKILL.md",[144,147],{"categoryNo":145,"categoryName":146,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000007","代码审查",{"categoryNo":148,"categoryName":149,"taxonomyType":118,"taxonomyTypeDesc":119},"01JBSEEDCAT000000000000030","开发工程师",[124,151,152,153,154,134,28],"code review","security","performance","merge"]