{"owner":"apache","repo":"iceberg","hasSkills":true,"totalSkillsCount":1,"totalTokensCount":3838,"categories":["root-instruction"],"hasMcp":false,"mcpConfig":null,"found":["AGENTS.md"],"skills":{"AGENTS.md":"<!--\n  Licensed to the Apache Software Foundation (ASF) under one\n  or more contributor license agreements.  See the NOTICE file\n  distributed with this work for additional information\n  regarding copyright ownership.  The ASF licenses this file\n  to you under the Apache License, Version 2.0 (the\n  \"License\"); you may not use this file except in compliance\n  with the License.  You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an\n  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n  KIND, either express or implied.  See the License for the\n  specific language governing permissions and limitations\n  under the License.\n-->\n\n# Apache Iceberg — Agent Instructions\n\nProject conventions, architecture, and coding patterns synthesized from 58,000+ review comments across 4,300+ merged PRs.\n\nReviewer attention is the project's scarcest resource. When a rule below is ambiguous, pick the option that produces less for a reviewer to read.\n\n## Security Model\n\nWhen assessing potential vulnerabilities or calibrating automated security findings, use [`SECURITY-THREAT-MODEL.md`](SECURITY-THREAT-MODEL.md) as the authoritative detailed description of Iceberg's security boundaries, trust assumptions, and non-boundaries.\n\n## Architecture\n\n### Module Boundaries\n\n- **API** (`api/`): Public interfaces and types. Changes affect every engine and catalog. API breaks are almost never acceptable.\n- **Core** (`core/`): Table spec implementation. Must be engine-agnostic. No Spark/Flink references. Properties should apply to all catalogs.\n- **Data** (`data/`): Generic data layer (DeleteFilter, BaseDeleteLoader, readers/writers). Behavior should be general, not engine-specific.\n- **Spark** (`spark/`): Spark integration only. Tests here validate integration, not core behavior.\n- **Flink** (`flink/`): Same principle as Spark — integration tests only.\n- **REST Catalog** (`open-api/`): OpenAPI spec for catalog interop. Precision in spec text is critical.\n- **AWS/GCP/Azure**: Cloud-specific catalog implementations. Don't leak cloud-specific assumptions into core.\n\nThe `api/` module has the strongest stability guarantees — breaking changes are almost never allowed. Other modules with public APIs (`iceberg-data`, `iceberg-parquet`, and others marked in `build.gradle`) may have breaking changes in minor releases, but they must be justified and all changes are tracked via `revapi`. New interface methods in any of these modules must include default implementations.\n\n### High-Sensitivity Areas\n\n- **`TableMetadata`**: Changes ripple through all engines and catalogs. Use `TableMetadata.Builder`; produce proper metadata updates for REST.\n- **`SnapshotProducer` / `MergingSnapshotProducer`**: The commit path. Validations must use established patterns.\n- **`ManifestGroup` / `ManifestReader`**: Container reuse causes bugs in parallel code. Callers must `copyWithoutStats` if holding references.\n- **Serialization** (parsers): Never use Jackson annotations. Custom `XxxParser.toJson/fromJson` only. JSON keys use kebab-case. Optional fields only written when present.\n- **REST spec**: Check for ambiguity, over-constraining, missing client-side guidance. POST for deltas, PUT for full-state replacement.\n- **Scan planning**: Metrics must not leak across `TableScan` refinements. Timers must be thread-safe (parallel manifest scanning).\n\n## Design Patterns\n\n- **Refinement**: `TableScan` methods return new independent scans. State must not leak between refinements.\n- **`CloseableIterable`** over `Stream`: Iceberg's standard lazy collection. Always close iterables.\n- **Null over `Optional`**: Use `null` for missing values. `Optional` is not used.\n- **Builder pattern**: For complex creation. Never require passing `null` for optional parameters.\n- **Package-private by default**: Only make things public with demonstrated need.\n- **Postel's Law**: Accept case-insensitive input, produce canonical output.\n- **`Tasks.foreach`**: For bulk operations with parallelism, retry, and error handling.\n- **Immutable metadata**: `TableMetadata`, `Schema`, `PartitionSpec`, `SortOrder` produce new instances via builders.\n- **Metadata updates for REST**: All mutations must produce serializable `MetadataUpdate` objects.\n- **`SerializableTable`**: Wrap table references for Spark/Flink serialization. Don't serialize the catalog.\n- **Validate at boundaries**: `Preconditions` at public entry points; internal methods assume invariants hold.\n- **Spec version gating**: Version 2+ features must check `formatVersion >= 2` with clear errors for v1 tables.\n\n## Coding Conventions\n\n### API Design\n\n- New public methods require strong justification. Prefer package-private.\n- Never break APIs. Add default implementations to new interface methods.\n- Don't introduce deprecated methods in brand-new interfaces.\n- Use `@SuppressWarnings({\"unchecked\", \"rawtypes\"})` internally rather than widening public signatures.\n- Prefer builders over multi-argument create methods.\n- Keep the `Table` API small. Utility methods go in helper classes.\n- Operations should be idempotent. Return final state from `apply()`, not intermediate changes.\n- Minimize third-party types (JTS, Guava) in public APIs. `StructLike` equality requires `StructLikeWrapper`.\n\n### Naming\n\n- Method names describe specific behavior: `selectInIdOrder` not `selectOrdered`.\n- Avoid `get` prefix — use `find`, `fetch`, `load`, `parse`, `create`, or drop it.\n- Variable names indicate meaning, not type. Property names use kebab-case.\n- Capitalize `ID` consistently. `toString()` must produce parseable output.\n- Avoid `Factory` suffix unless the class is a true factory.\n\n### Code Style\n\n- 2 spaces indent, 4 spaces continuation. Empty newline after control flow blocks.\n- Use `this.` for instance field assignment. `Preconditions` calls first in methods.\n- No `final` on locals. No one-argument-per-line unless necessary.\n- Magic numbers should be named constants.\n- `} else {` on same line. Minimize variable scope. `try-with-resources` for all `AutoCloseable`.\n- Prefer method references over lambdas. Wrap lines at the highest semantic level.\n- Prefer switch expressions (`case X -> ...`) over statement switches. Exhaustive enum switches need no `default`; others must have one.\n- Always use imports — never use fully-qualified class names inline.\n\n### Comments & Javadoc\n\nWhen writing new code, default to no comment and no Javadoc. Add one only when it states something the code does not. Leave existing comments and Javadoc as they are unless you are changing the code they describe or they have become wrong.\n\n**Check before adding:** if the comment or Javadoc you are about to write would need editing during a refactor that keeps behavior identical, it is describing internals — rewrite it or leave it out.\n\n**Comments**\n\n- Don't write a comment that restates the method name, the condition, or the next line.\n- Don't add commented-out code, section banners, or `// getter` / `// loop over files` narration.\n- No personal pronouns. Never describe how the code changed, what a PR did, or what the behavior used to be.\n\n**Javadoc**\n\n- Javadoc states the goal — what the method does for the caller — never how it does it. Strictest in `api/`.\n- Don't name internal fields, helper classes, data structures, caching, or algorithms. If you find yourself naming a type that isn't in the signature, you are documenting internals.\n- One sentence is usually enough. Longer is justified only by contract the caller must know: see `AppendFiles.appendManifest`, whose length is entirely about manifest lifecycle ownership on success and failure.\n- Document thrown exceptions, null behavior, and resource ownership (for example that a returned iterable must be closed).\n- Keep `@param` and `@return` tags in `api/` even when brief — `@return this for method chaining` is the established phrasing. Don't strip them.\n- Don't re-document an inherited contract; let overrides inherit unless they narrow or extend it.\n- Document `public` and `protected` members, interface methods, and anything designed to be overridden. `private` and package-private methods get none unless there is a caller obligation the signature can't express, such as a required lock or pre-sorted input.\n\n```java\n// Bad: documents the algorithm. The caller cannot rely on any of it.\n/**\n * Plans files by opening each manifest in the current snapshot's manifest list, evaluating the\n * filter expression against partition summaries to skip manifests, then reading the surviving\n * manifests in parallel using the worker pool and wrapping each entry in a BaseFileScanTask.\n *\n * @return an iterable of scan tasks\n */\nCloseableIterable<FileScanTask> planFiles();\n\n// Good: the goal, plus the one thing the caller must do.\n/**\n * Plans the files that will be read by this scan.\n *\n * <p>The returned iterable holds open resources and must be closed by the caller.\n *\n * @return an iterable of scan tasks matching this scan's filters\n */\nCloseableIterable<FileScanTask> planFiles();\n```\n\n### Code Placement\n\n- Extract reusable logic to the right utility layer (`TypeUtil`, `SchemaUtil`, `DateTimeUtil`, etc.).\n- Engine-specific concepts must not leak into core. Follow existing patterns before introducing new ones.\n- Parsers: `XxxParser.toJson/fromJson`. Config: `XxxProperties`. Check existing utilities first.\n- Avoid expanding Guava — use JDK equivalents. Use `CloseableGroup` for multi-resource lifecycle.\n- Keep things internal until proven needed.\n\n### Serialization\n\n- Never use Jackson annotations. Custom `XxxParser.toJson`/`fromJson` only.\n- JSON keys: kebab-case. Optional fields: only write when non-null. Required fields: validate in constructors.\n- `Preconditions.checkArgument` for validation. `MoreObjects.toStringHelper` for `toString()`.\n- Wrap `IOException` in `UncheckedIOException`. Use `Locale.ROOT` for case conversions.\n- Use `Iterable`/`CloseableIterable` over `Stream`. Use `null` not `Optional`. Chain exception causes.\n- Use Iceberg's `Pair` instead of `Map.Entry`.\n\n### Error Handling\n\n- Messages: direct, actionable, with specific values. Capitalize first word.\n- Don't swallow exceptions. Use `closeQuietly` for cleanup that shouldn't mask real failures.\n- Use `ConcurrentMap` for shared mutable state. `Preconditions.checkArgument` over NPE.\n- Close iterables in `finally`. Separate `Preconditions` calls for each condition.\n- Forward compatibility: don't fail on unknown reserved bytes.\n\n### Performance\n\n- Watch for hidden materialization in streaming pipelines (copy/collect steps).\n- Builders over rebuild patterns in hot paths. Lazy over eager evaluation.\n- `ByteBuffer` over `byte[]`. Direct-access arrays for dense integer keys.\n- Avoid streams/closures in tight loops. Cache per-class, not per-call.\n\n### Configuration\n\n- New features default to off. Question whether a property is even needed.\n- Properties must work across all catalogs. Zero/negative disables caches/features.\n- Versions go to version catalog. Engine-specific properties don't belong in `TableProperties`.\n\n### Testing\n\n**Write the test plan before the tests.** State in the PR description what behavior needs verifying and why each case matters — a few lines, not a document.\n\n- Test the behavior in the plan. Coverage is not a target.\n- Test the behavior this change adds or modifies. Don't assert the correctness of components this code merely calls.\n- One behavior per test method. No omnibus tests asserting several unrelated things.\n- A failing test must point to broken behavior. Don't add one that would fail only because an internal detail changed while the observable behavior is still correct.\n- Don't add tests for unreachable states, or tests that only restate the implementation.\n- Minimal test setup: `PartitionSpec.unpartitioned()` when partitioning isn't needed.\n- Test classes and methods should be package private unless required by inheritance.\n- Compute expected values, don't hardcode. Tests belong in the module that owns the code.\n- Write the most direct test for the bug. Parameterized tests for type variations.\n- JUnit 5 + AssertJ: `@Test`, `assertThat`, `assertThatThrownBy`.\n- Avoid using `test` prefixes for newly added tests.\n- `waitUntilAfter` for time-dependent tests. Separate tests over combined.\n\n### REST / OpenAPI Spec\n\n- Spec describes behavior, not implementation. RFC 2119: \"MUST\" = absolute, \"SHOULD\" = may reject.\n- Include client-side guidance. Consistent encoding terminology. 409 for \"already exists\", not 400.\n- Favor the client: required response fields reduce client complexity.\n\n## Commands\n\n- **Build (no tests):** `./gradlew build -x test -x integrationTest`\n- **Single test class:** `./gradlew :iceberg-core:test --tests org.apache.iceberg.TestTableMetadata`\n- **Single test method:** `./gradlew :iceberg-core:test --tests \"org.apache.iceberg.TestTableMetadata.testJsonSerialization\"`\n- **Spark-versioned module:** `./gradlew :iceberg-spark:iceberg-spark-4.1_2.13:test --tests \"org.apache.iceberg.spark.source.TestSparkReaderDeletes\"`\n- **Format code:** `./gradlew spotlessApply`\n- **Check formatting:** `./gradlew spotlessCheck`\n- **Checkstyle (core module):** `./gradlew :iceberg-core:checkstyleMain :iceberg-core:checkstyleTest` (replace the module path for other modules).\n- **API compatibility:** `./gradlew revApiCheck`\n\n## PR & Commit Conventions\n\n- **Never open a PR generated from an issue without a human in the loop.**\n- Search open PRs and issues for the same problem before starting. Don't add a duplicate.\n- PR titles follow `Module: Description` format (e.g., `Core: Fix ...`, `Spark: Add ...`, `Docs: Update ...`).\n- One concern per PR. Unrelated whitespace, import, or formatting changes go in separate PRs.\n- Keep first version of a PR minimal — defer recovery, optimization, and edge cases to follow-ups.\n- Before opening a PR, run `./gradlew spotlessApply`, run `checkstyleMain` and `checkstyleTest` for the modules you changed, and build and test those modules (see Commands). Never submit code you have not compiled and run.\n- PR description is one paragraph, under 120 words: the problem, the approach, and anything a reviewer would not guess from the diff. Plus the issue link, the test plan, and the AI Disclosure block. Nothing else.\n- Never restate the diff: no file-by-file walkthrough, no per-method summaries, no \"Changes made\" checklist, no \"Summary\", \"Background\", \"Motivation\", or \"Testing\" headings, no emoji.\n- Commit messages describe the *what* and *why*, not implementation details.\n- Apache License header required on all new files (enforced by spotless pre-commit hook).\n\n## AI-Generated PR Disclosure\n\nPull requests that are authored or substantially generated by AI agents **must** disclose that in the PR description. Always include an AI Disclosure block at the bottom, using the template below.\n\n- Fill in the fields you know. For fields you cannot determine, use `[unknown - human to fill in]`.\n- **Never self-certify review.** An agent must not set Human Oversight to `fully reviewed` — leave that for the human to state what they actually reviewed.\n- Name the specific parts that are generated, not merely that AI was used (e.g. \"the parser changes and their tests are generated; the spec interpretation is the author's\").\n- **Never auto-generate replies to review comments.**\n- AI-generated review comments **must** be reviewed for accuracy before posting. Auto-posting unreviewed AI comments is discouraged.\n\nSee the [ASF generative tooling guidelines](https://www.apache.org/legal/generative-tooling.html) for additional policy on AI-generated contributions. Generated files must still follow Iceberg's Apache License header and license check requirements unless explicitly excluded by project policy. For commits authored using generative AI tooling, include a `Generated-by: <tool>` token in the commit message.\n\n### Required Fields\n\n- **Model**: Set this to your model identifier and version (e.g., `Claude Opus 4.6`, `GPT-4o`, `Gemini 2.5 Pro`).\n- **Platform/Tool**: Set this to the tool or platform that orchestrated the generation (e.g., `GitHub Copilot`, `Cursor`, `Aider`, `Claude Code`, `custom script`).\n- **Human Oversight**: Set this to `fully reviewed`, `partially reviewed`, or `unreviewed`. If unknown, use `[unknown - human to fill in]`.\n- **Prompt Summary**: A brief description of the prompt or task given to the agent.\n\n### PR Description Template\n\nAdd the following block at the bottom of PR descriptions:\n\n```\n---\n**AI Disclosure**\n- Model: [model name and version]\n- Platform/Tool: [tool or platform name]\n- Human Oversight: [fully reviewed | partially reviewed | unreviewed]\n- Prompt Summary: [brief description of the task]\n```\n\n## Boundaries\n\n- **Never** modify `.asf.yaml`, `LICENSE`, `NOTICE`, or `versions.props` without explicit discussion.\n- **Never** add Jackson annotations to serialization classes — always use custom `XxxParser` classes.\n- **Never** break public API without an approved `revapi.yml` exception.\n- **Never** add Hadoop dependencies where `FileIO` abstractions exist.\n- **Never** commit secrets, credentials, or cloud-specific tokens.\n- **Ask first** before adding new third-party dependencies (license compatibility matters).\n- **Ask first** before promoting package-private classes/methods to public.\n"},"files":{"AGENTS.md":"<!--\n  Licensed to the Apache Software Foundation (ASF) under one\n  or more contributor license agreements.  See the NOTICE file\n  distributed with this work for additional information\n  regarding copyright ownership.  The ASF licenses this file\n  to you under the Apache License, Version 2.0 (the\n  \"License\"); you may not use this file except in compliance\n  with the License.  You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an\n  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n  KIND, either express or implied.  See the License for the\n  specific language governing permissions and limitations\n  under the License.\n-->\n\n# Apache Iceberg — Agent Instructions\n\nProject conventions, architecture, and coding patterns synthesized from 58,000+ review comments across 4,300+ merged PRs.\n\nReviewer attention is the project's scarcest resource. When a rule below is ambiguous, pick the option that produces less for a reviewer to read.\n\n## Security Model\n\nWhen assessing potential vulnerabilities or calibrating automated security findings, use [`SECURITY-THREAT-MODEL.md`](SECURITY-THREAT-MODEL.md) as the authoritative detailed description of Iceberg's security boundaries, trust assumptions, and non-boundaries.\n\n## Architecture\n\n### Module Boundaries\n\n- **API** (`api/`): Public interfaces and types. Changes affect every engine and catalog. API breaks are almost never acceptable.\n- **Core** (`core/`): Table spec implementation. Must be engine-agnostic. No Spark/Flink references. Properties should apply to all catalogs.\n- **Data** (`data/`): Generic data layer (DeleteFilter, BaseDeleteLoader, readers/writers). Behavior should be general, not engine-specific.\n- **Spark** (`spark/`): Spark integration only. Tests here validate integration, not core behavior.\n- **Flink** (`flink/`): Same principle as Spark — integration tests only.\n- **REST Catalog** (`open-api/`): OpenAPI spec for catalog interop. Precision in spec text is critical.\n- **AWS/GCP/Azure**: Cloud-specific catalog implementations. Don't leak cloud-specific assumptions into core.\n\nThe `api/` module has the strongest stability guarantees — breaking changes are almost never allowed. Other modules with public APIs (`iceberg-data`, `iceberg-parquet`, and others marked in `build.gradle`) may have breaking changes in minor releases, but they must be justified and all changes are tracked via `revapi`. New interface methods in any of these modules must include default implementations.\n\n### High-Sensitivity Areas\n\n- **`TableMetadata`**: Changes ripple through all engines and catalogs. Use `TableMetadata.Builder`; produce proper metadata updates for REST.\n- **`SnapshotProducer` / `MergingSnapshotProducer`**: The commit path. Validations must use established patterns.\n- **`ManifestGroup` / `ManifestReader`**: Container reuse causes bugs in parallel code. Callers must `copyWithoutStats` if holding references.\n- **Serialization** (parsers): Never use Jackson annotations. Custom `XxxParser.toJson/fromJson` only. JSON keys use kebab-case. Optional fields only written when present.\n- **REST spec**: Check for ambiguity, over-constraining, missing client-side guidance. POST for deltas, PUT for full-state replacement.\n- **Scan planning**: Metrics must not leak across `TableScan` refinements. Timers must be thread-safe (parallel manifest scanning).\n\n## Design Patterns\n\n- **Refinement**: `TableScan` methods return new independent scans. State must not leak between refinements.\n- **`CloseableIterable`** over `Stream`: Iceberg's standard lazy collection. Always close iterables.\n- **Null over `Optional`**: Use `null` for missing values. `Optional` is not used.\n- **Builder pattern**: For complex creation. Never require passing `null` for optional parameters.\n- **Package-private by default**: Only make things public with demonstrated need.\n- **Postel's Law**: Accept case-insensitive input, produce canonical output.\n- **`Tasks.foreach`**: For bulk operations with parallelism, retry, and error handling.\n- **Immutable metadata**: `TableMetadata`, `Schema`, `PartitionSpec`, `SortOrder` produce new instances via builders.\n- **Metadata updates for REST**: All mutations must produce serializable `MetadataUpdate` objects.\n- **`SerializableTable`**: Wrap table references for Spark/Flink serialization. Don't serialize the catalog.\n- **Validate at boundaries**: `Preconditions` at public entry points; internal methods assume invariants hold.\n- **Spec version gating**: Version 2+ features must check `formatVersion >= 2` with clear errors for v1 tables.\n\n## Coding Conventions\n\n### API Design\n\n- New public methods require strong justification. Prefer package-private.\n- Never break APIs. Add default implementations to new interface methods.\n- Don't introduce deprecated methods in brand-new interfaces.\n- Use `@SuppressWarnings({\"unchecked\", \"rawtypes\"})` internally rather than widening public signatures.\n- Prefer builders over multi-argument create methods.\n- Keep the `Table` API small. Utility methods go in helper classes.\n- Operations should be idempotent. Return final state from `apply()`, not intermediate changes.\n- Minimize third-party types (JTS, Guava) in public APIs. `StructLike` equality requires `StructLikeWrapper`.\n\n### Naming\n\n- Method names describe specific behavior: `selectInIdOrder` not `selectOrdered`.\n- Avoid `get` prefix — use `find`, `fetch`, `load`, `parse`, `create`, or drop it.\n- Variable names indicate meaning, not type. Property names use kebab-case.\n- Capitalize `ID` consistently. `toString()` must produce parseable output.\n- Avoid `Factory` suffix unless the class is a true factory.\n\n### Code Style\n\n- 2 spaces indent, 4 spaces continuation. Empty newline after control flow blocks.\n- Use `this.` for instance field assignment. `Preconditions` calls first in methods.\n- No `final` on locals. No one-argument-per-line unless necessary.\n- Magic numbers should be named constants.\n- `} else {` on same line. Minimize variable scope. `try-with-resources` for all `AutoCloseable`.\n- Prefer method references over lambdas. Wrap lines at the highest semantic level.\n- Prefer switch expressions (`case X -> ...`) over statement switches. Exhaustive enum switches need no `default`; others must have one.\n- Always use imports — never use fully-qualified class names inline.\n\n### Comments & Javadoc\n\nWhen writing new code, default to no comment and no Javadoc. Add one only when it states something the code does not. Leave existing comments and Javadoc as they are unless you are changing the code they describe or they have become wrong.\n\n**Check before adding:** if the comment or Javadoc you are about to write would need editing during a refactor that keeps behavior identical, it is describing internals — rewrite it or leave it out.\n\n**Comments**\n\n- Don't write a comment that restates the method name, the condition, or the next line.\n- Don't add commented-out code, section banners, or `// getter` / `// loop over files` narration.\n- No personal pronouns. Never describe how the code changed, what a PR did, or what the behavior used to be.\n\n**Javadoc**\n\n- Javadoc states the goal — what the method does for the caller — never how it does it. Strictest in `api/`.\n- Don't name internal fields, helper classes, data structures, caching, or algorithms. If you find yourself naming a type that isn't in the signature, you are documenting internals.\n- One sentence is usually enough. Longer is justified only by contract the caller must know: see `AppendFiles.appendManifest`, whose length is entirely about manifest lifecycle ownership on success and failure.\n- Document thrown exceptions, null behavior, and resource ownership (for example that a returned iterable must be closed).\n- Keep `@param` and `@return` tags in `api/` even when brief — `@return this for method chaining` is the established phrasing. Don't strip them.\n- Don't re-document an inherited contract; let overrides inherit unless they narrow or extend it.\n- Document `public` and `protected` members, interface methods, and anything designed to be overridden. `private` and package-private methods get none unless there is a caller obligation the signature can't express, such as a required lock or pre-sorted input.\n\n```java\n// Bad: documents the algorithm. The caller cannot rely on any of it.\n/**\n * Plans files by opening each manifest in the current snapshot's manifest list, evaluating the\n * filter expression against partition summaries to skip manifests, then reading the surviving\n * manifests in parallel using the worker pool and wrapping each entry in a BaseFileScanTask.\n *\n * @return an iterable of scan tasks\n */\nCloseableIterable<FileScanTask> planFiles();\n\n// Good: the goal, plus the one thing the caller must do.\n/**\n * Plans the files that will be read by this scan.\n *\n * <p>The returned iterable holds open resources and must be closed by the caller.\n *\n * @return an iterable of scan tasks matching this scan's filters\n */\nCloseableIterable<FileScanTask> planFiles();\n```\n\n### Code Placement\n\n- Extract reusable logic to the right utility layer (`TypeUtil`, `SchemaUtil`, `DateTimeUtil`, etc.).\n- Engine-specific concepts must not leak into core. Follow existing patterns before introducing new ones.\n- Parsers: `XxxParser.toJson/fromJson`. Config: `XxxProperties`. Check existing utilities first.\n- Avoid expanding Guava — use JDK equivalents. Use `CloseableGroup` for multi-resource lifecycle.\n- Keep things internal until proven needed.\n\n### Serialization\n\n- Never use Jackson annotations. Custom `XxxParser.toJson`/`fromJson` only.\n- JSON keys: kebab-case. Optional fields: only write when non-null. Required fields: validate in constructors.\n- `Preconditions.checkArgument` for validation. `MoreObjects.toStringHelper` for `toString()`.\n- Wrap `IOException` in `UncheckedIOException`. Use `Locale.ROOT` for case conversions.\n- Use `Iterable`/`CloseableIterable` over `Stream`. Use `null` not `Optional`. Chain exception causes.\n- Use Iceberg's `Pair` instead of `Map.Entry`.\n\n### Error Handling\n\n- Messages: direct, actionable, with specific values. Capitalize first word.\n- Don't swallow exceptions. Use `closeQuietly` for cleanup that shouldn't mask real failures.\n- Use `ConcurrentMap` for shared mutable state. `Preconditions.checkArgument` over NPE.\n- Close iterables in `finally`. Separate `Preconditions` calls for each condition.\n- Forward compatibility: don't fail on unknown reserved bytes.\n\n### Performance\n\n- Watch for hidden materialization in streaming pipelines (copy/collect steps).\n- Builders over rebuild patterns in hot paths. Lazy over eager evaluation.\n- `ByteBuffer` over `byte[]`. Direct-access arrays for dense integer keys.\n- Avoid streams/closures in tight loops. Cache per-class, not per-call.\n\n### Configuration\n\n- New features default to off. Question whether a property is even needed.\n- Properties must work across all catalogs. Zero/negative disables caches/features.\n- Versions go to version catalog. Engine-specific properties don't belong in `TableProperties`.\n\n### Testing\n\n**Write the test plan before the tests.** State in the PR description what behavior needs verifying and why each case matters — a few lines, not a document.\n\n- Test the behavior in the plan. Coverage is not a target.\n- Test the behavior this change adds or modifies. Don't assert the correctness of components this code merely calls.\n- One behavior per test method. No omnibus tests asserting several unrelated things.\n- A failing test must point to broken behavior. Don't add one that would fail only because an internal detail changed while the observable behavior is still correct.\n- Don't add tests for unreachable states, or tests that only restate the implementation.\n- Minimal test setup: `PartitionSpec.unpartitioned()` when partitioning isn't needed.\n- Test classes and methods should be package private unless required by inheritance.\n- Compute expected values, don't hardcode. Tests belong in the module that owns the code.\n- Write the most direct test for the bug. Parameterized tests for type variations.\n- JUnit 5 + AssertJ: `@Test`, `assertThat`, `assertThatThrownBy`.\n- Avoid using `test` prefixes for newly added tests.\n- `waitUntilAfter` for time-dependent tests. Separate tests over combined.\n\n### REST / OpenAPI Spec\n\n- Spec describes behavior, not implementation. RFC 2119: \"MUST\" = absolute, \"SHOULD\" = may reject.\n- Include client-side guidance. Consistent encoding terminology. 409 for \"already exists\", not 400.\n- Favor the client: required response fields reduce client complexity.\n\n## Commands\n\n- **Build (no tests):** `./gradlew build -x test -x integrationTest`\n- **Single test class:** `./gradlew :iceberg-core:test --tests org.apache.iceberg.TestTableMetadata`\n- **Single test method:** `./gradlew :iceberg-core:test --tests \"org.apache.iceberg.TestTableMetadata.testJsonSerialization\"`\n- **Spark-versioned module:** `./gradlew :iceberg-spark:iceberg-spark-4.1_2.13:test --tests \"org.apache.iceberg.spark.source.TestSparkReaderDeletes\"`\n- **Format code:** `./gradlew spotlessApply`\n- **Check formatting:** `./gradlew spotlessCheck`\n- **Checkstyle (core module):** `./gradlew :iceberg-core:checkstyleMain :iceberg-core:checkstyleTest` (replace the module path for other modules).\n- **API compatibility:** `./gradlew revApiCheck`\n\n## PR & Commit Conventions\n\n- **Never open a PR generated from an issue without a human in the loop.**\n- Search open PRs and issues for the same problem before starting. Don't add a duplicate.\n- PR titles follow `Module: Description` format (e.g., `Core: Fix ...`, `Spark: Add ...`, `Docs: Update ...`).\n- One concern per PR. Unrelated whitespace, import, or formatting changes go in separate PRs.\n- Keep first version of a PR minimal — defer recovery, optimization, and edge cases to follow-ups.\n- Before opening a PR, run `./gradlew spotlessApply`, run `checkstyleMain` and `checkstyleTest` for the modules you changed, and build and test those modules (see Commands). Never submit code you have not compiled and run.\n- PR description is one paragraph, under 120 words: the problem, the approach, and anything a reviewer would not guess from the diff. Plus the issue link, the test plan, and the AI Disclosure block. Nothing else.\n- Never restate the diff: no file-by-file walkthrough, no per-method summaries, no \"Changes made\" checklist, no \"Summary\", \"Background\", \"Motivation\", or \"Testing\" headings, no emoji.\n- Commit messages describe the *what* and *why*, not implementation details.\n- Apache License header required on all new files (enforced by spotless pre-commit hook).\n\n## AI-Generated PR Disclosure\n\nPull requests that are authored or substantially generated by AI agents **must** disclose that in the PR description. Always include an AI Disclosure block at the bottom, using the template below.\n\n- Fill in the fields you know. For fields you cannot determine, use `[unknown - human to fill in]`.\n- **Never self-certify review.** An agent must not set Human Oversight to `fully reviewed` — leave that for the human to state what they actually reviewed.\n- Name the specific parts that are generated, not merely that AI was used (e.g. \"the parser changes and their tests are generated; the spec interpretation is the author's\").\n- **Never auto-generate replies to review comments.**\n- AI-generated review comments **must** be reviewed for accuracy before posting. Auto-posting unreviewed AI comments is discouraged.\n\nSee the [ASF generative tooling guidelines](https://www.apache.org/legal/generative-tooling.html) for additional policy on AI-generated contributions. Generated files must still follow Iceberg's Apache License header and license check requirements unless explicitly excluded by project policy. For commits authored using generative AI tooling, include a `Generated-by: <tool>` token in the commit message.\n\n### Required Fields\n\n- **Model**: Set this to your model identifier and version (e.g., `Claude Opus 4.6`, `GPT-4o`, `Gemini 2.5 Pro`).\n- **Platform/Tool**: Set this to the tool or platform that orchestrated the generation (e.g., `GitHub Copilot`, `Cursor`, `Aider`, `Claude Code`, `custom script`).\n- **Human Oversight**: Set this to `fully reviewed`, `partially reviewed`, or `unreviewed`. If unknown, use `[unknown - human to fill in]`.\n- **Prompt Summary**: A brief description of the prompt or task given to the agent.\n\n### PR Description Template\n\nAdd the following block at the bottom of PR descriptions:\n\n```\n---\n**AI Disclosure**\n- Model: [model name and version]\n- Platform/Tool: [tool or platform name]\n- Human Oversight: [fully reviewed | partially reviewed | unreviewed]\n- Prompt Summary: [brief description of the task]\n```\n\n## Boundaries\n\n- **Never** modify `.asf.yaml`, `LICENSE`, `NOTICE`, or `versions.props` without explicit discussion.\n- **Never** add Jackson annotations to serialization classes — always use custom `XxxParser` classes.\n- **Never** break public API without an approved `revapi.yml` exception.\n- **Never** add Hadoop dependencies where `FileIO` abstractions exist.\n- **Never** commit secrets, credentials, or cloud-specific tokens.\n- **Ask first** before adding new third-party dependencies (license compatibility matters).\n- **Ask first** before promoting package-private classes/methods to public.\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/apache/iceberg/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"<!--\n  Licensed to the Apache Software Foundation (ASF) under one\n  or more contributor license agreements.  See the NOTICE file\n  distributed with this work for additional information\n  regarding copyright ownership.  The ASF licenses this file\n  to you under the Apache License, Version 2.0 (the\n  \"License\"); you may not use this file except in compliance\n  with the License.  You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an\n  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n  KIND, either express or implied.  See the License for the\n  specific language governing permissions and limitations\n  under the License.\n-->\n\n# Apache Iceberg — Agent Instructions\n\nProject conventions, architecture, and coding patterns synthesized from 58,000+ review comments across 4,300+ merged PRs.\n\nReviewer attention is the project's scarcest resource. When a rule below is ambiguous, pick the option that produces less for a reviewer to read.\n\n## Security Model\n\nWhen assessing potential vulnerabilities or calibrating automated security findings, use [`SECURITY-THREAT-MODEL.md`](SECURITY-THREAT-MODEL.md) as the authoritative detailed description of Iceberg's security boundaries, trust assumptions, and non-boundaries.\n\n## Architecture\n\n### Module Boundaries\n\n- **API** (`api/`): Public interfaces and types. Changes affect every engine and catalog. API breaks are almost never acceptable.\n- **Core** (`core/`): Table spec implementation. Must be engine-agnostic. No Spark/Flink references. Properties should apply to all catalogs.\n- **Data** (`data/`): Generic data layer (DeleteFilter, BaseDeleteLoader, readers/writers). Behavior should be general, not engine-specific.\n- **Spark** (`spark/`): Spark integration only. Tests here validate integration, not core behavior.\n- **Flink** (`flink/`): Same principle as Spark — integration tests only.\n- **REST Catalog** (`open-api/`): OpenAPI spec for catalog interop. Precision in spec text is critical.\n- **AWS/GCP/Azure**: Cloud-specific catalog implementations. Don't leak cloud-specific assumptions into core.\n\nThe `api/` module has the strongest stability guarantees — breaking changes are almost never allowed. Other modules with public APIs (`iceberg-data`, `iceberg-parquet`, and others marked in `build.gradle`) may have breaking changes in minor releases, but they must be justified and all changes are tracked via `revapi`. New interface methods in any of these modules must include default implementations.\n\n### High-Sensitivity Areas\n\n- **`TableMetadata`**: Changes ripple through all engines and catalogs. Use `TableMetadata.Builder`; produce proper metadata updates for REST.\n- **`SnapshotProducer` / `MergingSnapshotProducer`**: The commit path. Validations must use established patterns.\n- **`ManifestGroup` / `ManifestReader`**: Container reuse causes bugs in parallel code. Callers must `copyWithoutStats` if holding references.\n- **Serialization** (parsers): Never use Jackson annotations. Custom `XxxParser.toJson/fromJson` only. JSON keys use kebab-case. Optional fields only written when present.\n- **REST spec**: Check for ambiguity, over-constraining, missing client-side guidance. POST for deltas, PUT for full-state replacement.\n- **Scan planning**: Metrics must not leak across `TableScan` refinements. Timers must be thread-safe (parallel manifest scanning).\n\n## Design Patterns\n\n- **Refinement**: `TableScan` methods return new independent scans. State must not leak between refinements.\n- **`CloseableIterable`** over `Stream`: Iceberg's standard lazy collection. Always close iterables.\n- **Null over `Optional`**: Use `null` for missing values. `Optional` is not used.\n- **Builder pattern**: For complex creation. Never require passing `null` for optional parameters.\n- **Package-private by default**: Only make things public with demonstrated need.\n- **Postel's Law**: Accept case-insensitive input, produce canonical output.\n- **`Tasks.foreach`**: For bulk operations with parallelism, retry, and error handling.\n- **Immutable metadata**: `TableMetadata`, `Schema`, `PartitionSpec`, `SortOrder` produce new instances via builders.\n- **Metadata updates for REST**: All mutations must produce serializable `MetadataUpdate` objects.\n- **`SerializableTable`**: Wrap table references for Spark/Flink serialization. Don't serialize the catalog.\n- **Validate at boundaries**: `Preconditions` at public entry points; internal methods assume invariants hold.\n- **Spec version gating**: Version 2+ features must check `formatVersion >= 2` with clear errors for v1 tables.\n\n## Coding Conventions\n\n### API Design\n\n- New public methods require strong justification. Prefer package-private.\n- Never break APIs. Add default implementations to new interface methods.\n- Don't introduce deprecated methods in brand-new interfaces.\n- Use `@SuppressWarnings({\"unchecked\", \"rawtypes\"})` internally rather than widening public signatures.\n- Prefer builders over multi-argument create methods.\n- Keep the `Table` API small. Utility methods go in helper classes.\n- Operations should be idempotent. Return final state from `apply()`, not intermediate changes.\n- Minimize third-party types (JTS, Guava) in public APIs. `StructLike` equality requires `StructLikeWrapper`.\n\n### Naming\n\n- Method names describe specific behavior: `selectInIdOrder` not `selectOrdered`.\n- Avoid `get` prefix — use `find`, `fetch`, `load`, `parse`, `create`, or drop it.\n- Variable names indicate meaning, not type. Property names use kebab-case.\n- Capitalize `ID` consistently. `toString()` must produce parseable output.\n- Avoid `Factory` suffix unless the class is a true factory.\n\n### Code Style\n\n- 2 spaces indent, 4 spaces continuation. Empty newline after control flow blocks.\n- Use `this.` for instance field assignment. `Preconditions` calls first in methods.\n- No `final` on locals. No one-argument-per-line unless necessary.\n- Magic numbers should be named constants.\n- `} else {` on same line. Minimize variable scope. `try-with-resources` for all `AutoCloseable`.\n- Prefer method references over lambdas. Wrap lines at the highest semantic level.\n- Prefer switch expressions (`case X -> ...`) over statement switches. Exhaustive enum switches need no `default`; others must have one.\n- Always use imports — never use fully-qualified class names inline.\n\n### Comments & Javadoc\n\nWhen writing new code, default to no comment and no Javadoc. Add one only when it states something the code does not. Leave existing comments and Javadoc as they are unless you are changing the code they describe or they have become wrong.\n\n**Check before adding:** if the comment or Javadoc you are about to write would need editing during a refactor that keeps behavior identical, it is describing internals — rewrite it or leave it out.\n\n**Comments**\n\n- Don't write a comment that restates the method name, the condition, or the next line.\n- Don't add commented-out code, section banners, or `// getter` / `// loop over files` narration.\n- No personal pronouns. Never describe how the code changed, what a PR did, or what the behavior used to be.\n\n**Javadoc**\n\n- Javadoc states the goal — what the method does for the caller — never how it does it. Strictest in `api/`.\n- Don't name internal fields, helper classes, data structures, caching, or algorithms. If you find yourself naming a type that isn't in the signature, you are documenting internals.\n- One sentence is usually enough. Longer is justified only by contract the caller must know: see `AppendFiles.appendManifest`, whose length is entirely about manifest lifecycle ownership on success and failure.\n- Document thrown exceptions, null behavior, and resource ownership (for example that a returned iterable must be closed).\n- Keep `@param` and `@return` tags in `api/` even when brief — `@return this for method chaining` is the established phrasing. Don't strip them.\n- Don't re-document an inherited contract; let overrides inherit unless they narrow or extend it.\n- Document `public` and `protected` members, interface methods, and anything designed to be overridden. `private` and package-private methods get none unless there is a caller obligation the signature can't express, such as a required lock or pre-sorted input.\n\n```java\n// Bad: documents the algorithm. The caller cannot rely on any of it.\n/**\n * Plans files by opening each manifest in the current snapshot's manifest list, evaluating the\n * filter expression against partition summaries to skip manifests, then reading the surviving\n * manifests in parallel using the worker pool and wrapping each entry in a BaseFileScanTask.\n *\n * @return an iterable of scan tasks\n */\nCloseableIterable<FileScanTask> planFiles();\n\n// Good: the goal, plus the one thing the caller must do.\n/**\n * Plans the files that will be read by this scan.\n *\n * <p>The returned iterable holds open resources and must be closed by the caller.\n *\n * @return an iterable of scan tasks matching this scan's filters\n */\nCloseableIterable<FileScanTask> planFiles();\n```\n\n### Code Placement\n\n- Extract reusable logic to the right utility layer (`TypeUtil`, `SchemaUtil`, `DateTimeUtil`, etc.).\n- Engine-specific concepts must not leak into core. Follow existing patterns before introducing new ones.\n- Parsers: `XxxParser.toJson/fromJson`. Config: `XxxProperties`. Check existing utilities first.\n- Avoid expanding Guava — use JDK equivalents. Use `CloseableGroup` for multi-resource lifecycle.\n- Keep things internal until proven needed.\n\n### Serialization\n\n- Never use Jackson annotations. Custom `XxxParser.toJson`/`fromJson` only.\n- JSON keys: kebab-case. Optional fields: only write when non-null. Required fields: validate in constructors.\n- `Preconditions.checkArgument` for validation. `MoreObjects.toStringHelper` for `toString()`.\n- Wrap `IOException` in `UncheckedIOException`. Use `Locale.ROOT` for case conversions.\n- Use `Iterable`/`CloseableIterable` over `Stream`. Use `null` not `Optional`. Chain exception causes.\n- Use Iceberg's `Pair` instead of `Map.Entry`.\n\n### Error Handling\n\n- Messages: direct, actionable, with specific values. Capitalize first word.\n- Don't swallow exceptions. Use `closeQuietly` for cleanup that shouldn't mask real failures.\n- Use `ConcurrentMap` for shared mutable state. `Preconditions.checkArgument` over NPE.\n- Close iterables in `finally`. Separate `Preconditions` calls for each condition.\n- Forward compatibility: don't fail on unknown reserved bytes.\n\n### Performance\n\n- Watch for hidden materialization in streaming pipelines (copy/collect steps).\n- Builders over rebuild patterns in hot paths. Lazy over eager evaluation.\n- `ByteBuffer` over `byte[]`. Direct-access arrays for dense integer keys.\n- Avoid streams/closures in tight loops. Cache per-class, not per-call.\n\n### Configuration\n\n- New features default to off. Question whether a property is even needed.\n- Properties must work across all catalogs. Zero/negative disables caches/features.\n- Versions go to version catalog. Engine-specific properties don't belong in `TableProperties`.\n\n### Testing\n\n**Write the test plan before the tests.** State in the PR description what behavior needs verifying and why each case matters — a few lines, not a document.\n\n- Test the behavior in the plan. Coverage is not a target.\n- Test the behavior this change adds or modifies. Don't assert the correctness of components this code merely calls.\n- One behavior per test method. No omnibus tests asserting several unrelated things.\n- A failing test must point to broken behavior. Don't add one that would fail only because an internal detail changed while the observable behavior is still correct.\n- Don't add tests for unreachable states, or tests that only restate the implementation.\n- Minimal test setup: `PartitionSpec.unpartitioned()` when partitioning isn't needed.\n- Test classes and methods should be package private unless required by inheritance.\n- Compute expected values, don't hardcode. Tests belong in the module that owns the code.\n- Write the most direct test for the bug. Parameterized tests for type variations.\n- JUnit 5 + AssertJ: `@Test`, `assertThat`, `assertThatThrownBy`.\n- Avoid using `test` prefixes for newly added tests.\n- `waitUntilAfter` for time-dependent tests. Separate tests over combined.\n\n### REST / OpenAPI Spec\n\n- Spec describes behavior, not implementation. RFC 2119: \"MUST\" = absolute, \"SHOULD\" = may reject.\n- Include client-side guidance. Consistent encoding terminology. 409 for \"already exists\", not 400.\n- Favor the client: required response fields reduce client complexity.\n\n## Commands\n\n- **Build (no tests):** `./gradlew build -x test -x integrationTest`\n- **Single test class:** `./gradlew :iceberg-core:test --tests org.apache.iceberg.TestTableMetadata`\n- **Single test method:** `./gradlew :iceberg-core:test --tests \"org.apache.iceberg.TestTableMetadata.testJsonSerialization\"`\n- **Spark-versioned module:** `./gradlew :iceberg-spark:iceberg-spark-4.1_2.13:test --tests \"org.apache.iceberg.spark.source.TestSparkReaderDeletes\"`\n- **Format code:** `./gradlew spotlessApply`\n- **Check formatting:** `./gradlew spotlessCheck`\n- **Checkstyle (core module):** `./gradlew :iceberg-core:checkstyleMain :iceberg-core:checkstyleTest` (replace the module path for other modules).\n- **API compatibility:** `./gradlew revApiCheck`\n\n## PR & Commit Conventions\n\n- **Never open a PR generated from an issue without a human in the loop.**\n- Search open PRs and issues for the same problem before starting. Don't add a duplicate.\n- PR titles follow `Module: Description` format (e.g., `Core: Fix ...`, `Spark: Add ...`, `Docs: Update ...`).\n- One concern per PR. Unrelated whitespace, import, or formatting changes go in separate PRs.\n- Keep first version of a PR minimal — defer recovery, optimization, and edge cases to follow-ups.\n- Before opening a PR, run `./gradlew spotlessApply`, run `checkstyleMain` and `checkstyleTest` for the modules you changed, and build and test those modules (see Commands). Never submit code you have not compiled and run.\n- PR description is one paragraph, under 120 words: the problem, the approach, and anything a reviewer would not guess from the diff. Plus the issue link, the test plan, and the AI Disclosure block. Nothing else.\n- Never restate the diff: no file-by-file walkthrough, no per-method summaries, no \"Changes made\" checklist, no \"Summary\", \"Background\", \"Motivation\", or \"Testing\" headings, no emoji.\n- Commit messages describe the *what* and *why*, not implementation details.\n- Apache License header required on all new files (enforced by spotless pre-commit hook).\n\n## AI-Generated PR Disclosure\n\nPull requests that are authored or substantially generated by AI agents **must** disclose that in the PR description. Always include an AI Disclosure block at the bottom, using the template below.\n\n- Fill in the fields you know. For fields you cannot determine, use `[unknown - human to fill in]`.\n- **Never self-certify review.** An agent must not set Human Oversight to `fully reviewed` — leave that for the human to state what they actually reviewed.\n- Name the specific parts that are generated, not merely that AI was used (e.g. \"the parser changes and their tests are generated; the spec interpretation is the author's\").\n- **Never auto-generate replies to review comments.**\n- AI-generated review comments **must** be reviewed for accuracy before posting. Auto-posting unreviewed AI comments is discouraged.\n\nSee the [ASF generative tooling guidelines](https://www.apache.org/legal/generative-tooling.html) for additional policy on AI-generated contributions. Generated files must still follow Iceberg's Apache License header and license check requirements unless explicitly excluded by project policy. For commits authored using generative AI tooling, include a `Generated-by: <tool>` token in the commit message.\n\n### Required Fields\n\n- **Model**: Set this to your model identifier and version (e.g., `Claude Opus 4.6`, `GPT-4o`, `Gemini 2.5 Pro`).\n- **Platform/Tool**: Set this to the tool or platform that orchestrated the generation (e.g., `GitHub Copilot`, `Cursor`, `Aider`, `Claude Code`, `custom script`).\n- **Human Oversight**: Set this to `fully reviewed`, `partially reviewed`, or `unreviewed`. If unknown, use `[unknown - human to fill in]`.\n- **Prompt Summary**: A brief description of the prompt or task given to the agent.\n\n### PR Description Template\n\nAdd the following block at the bottom of PR descriptions:\n\n```\n---\n**AI Disclosure**\n- Model: [model name and version]\n- Platform/Tool: [tool or platform name]\n- Human Oversight: [fully reviewed | partially reviewed | unreviewed]\n- Prompt Summary: [brief description of the task]\n```\n\n## Boundaries\n\n- **Never** modify `.asf.yaml`, `LICENSE`, `NOTICE`, or `versions.props` without explicit discussion.\n- **Never** add Jackson annotations to serialization classes — always use custom `XxxParser` classes.\n- **Never** break public API without an approved `revapi.yml` exception.\n- **Never** add Hadoop dependencies where `FileIO` abstractions exist.\n- **Never** commit secrets, credentials, or cloud-specific tokens.\n- **Ask first** before adding new third-party dependencies (license compatibility matters).\n- **Ask first** before promoting package-private classes/methods to public.\n","isInternal":false,"tokens":3838,"sizeBytes":17464}],"systemPromptSnippet":"<yakaai_skills repo=\"apache/iceberg\">\n<!-- File: AGENTS.md (Tokens: ~3838 | Category: root-instruction) -->\n<!--\n  Licensed to the Apache Software Foundation (ASF) under one\n  or more contributor license agreements.  See the NOTICE file\n  distributed with this work for additional information\n  regarding copyright ownership.  The ASF licenses this file\n  to you under the Apache License, Version 2.0 (the\n  \"License\"); you may not use this file except in compliance\n  with the License.  You may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing,\n  software distributed under the License is distributed on an\n  \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n  KIND, either express or implied.  See the License for the\n  specific language governing permissions and limitations\n  under the License.\n-->\n\n# Apache Iceberg — Agent Instructions\n\nProject conventions, architecture, and coding patterns synthesized from 58,000+ review comments across 4,300+ merged PRs.\n\nReviewer attention is the project's scarcest resource. When a rule below is ambiguous, pick the option that produces less for a reviewer to read.\n\n## Security Model\n\nWhen assessing potential vulnerabilities or calibrating automated security findings, use [`SECURITY-THREAT-MODEL.md`](SECURITY-THREAT-MODEL.md) as the authoritative detailed description of Iceberg's security boundaries, trust assumptions, and non-boundaries.\n\n## Architecture\n\n### Module Boundaries\n\n- **API** (`api/`): Public interfaces and types. Changes affect every engine and catalog. API breaks are almost never acceptable.\n- **Core** (`core/`): Table spec implementation. Must be engine-agnostic. No Spark/Flink references. Properties should apply to all catalogs.\n- **Data** (`data/`): Generic data layer (DeleteFilter, BaseDeleteLoader, readers/writers). Behavior should be general, not engine-specific.\n- **Spark** (`spark/`): Spark integration only. Tests here validate integration, not core behavior.\n- **Flink** (`flink/`): Same principle as Spark — integration tests only.\n- **REST Catalog** (`open-api/`): OpenAPI spec for catalog interop. Precision in spec text is critical.\n- **AWS/GCP/Azure**: Cloud-specific catalog implementations. Don't leak cloud-specific assumptions into core.\n\nThe `api/` module has the strongest stability guarantees — breaking changes are almost never allowed. Other modules with public APIs (`iceberg-data`, `iceberg-parquet`, and others marked in `build.gradle`) may have breaking changes in minor releases, but they must be justified and all changes are tracked via `revapi`. New interface methods in any of these modules must include default implementations.\n\n### High-Sensitivity Areas\n\n- **`TableMetadata`**: Changes ripple through all engines and catalogs. Use `TableMetadata.Builder`; produce proper metadata updates for REST.\n- **`SnapshotProducer` / `MergingSnapshotProducer`**: The commit path. Validations must use established patterns.\n- **`ManifestGroup` / `ManifestReader`**: Container reuse causes bugs in parallel code. Callers must `copyWithoutStats` if holding references.\n- **Serialization** (parsers): Never use Jackson annotations. Custom `XxxParser.toJson/fromJson` only. JSON keys use kebab-case. Optional fields only written when present.\n- **REST spec**: Check for ambiguity, over-constraining, missing client-side guidance. POST for deltas, PUT for full-state replacement.\n- **Scan planning**: Metrics must not leak across `TableScan` refinements. Timers must be thread-safe (parallel manifest scanning).\n\n## Design Patterns\n\n- **Refinement**: `TableScan` methods return new independent scans. State must not leak between refinements.\n- **`CloseableIterable`** over `Stream`: Iceberg's standard lazy collection. Always close iterables.\n- **Null over `Optional`**: Use `null` for missing values. `Optional` is not used.\n- **Builder pattern**: For complex creation. Never require passing `null` for optional parameters.\n- **Package-private by default**: Only make things public with demonstrated need.\n- **Postel's Law**: Accept case-insensitive input, produce canonical output.\n- **`Tasks.foreach`**: For bulk operations with parallelism, retry, and error handling.\n- **Immutable metadata**: `TableMetadata`, `Schema`, `PartitionSpec`, `SortOrder` produce new instances via builders.\n- **Metadata updates for REST**: All mutations must produce serializable `MetadataUpdate` objects.\n- **`SerializableTable`**: Wrap table references for Spark/Flink serialization. Don't serialize the catalog.\n- **Validate at boundaries**: `Preconditions` at public entry points; internal methods assume invariants hold.\n- **Spec version gating**: Version 2+ features must check `formatVersion >= 2` with clear errors for v1 tables.\n\n## Coding Conventions\n\n### API Design\n\n- New public methods require strong justification. Prefer package-private.\n- Never break APIs. Add default implementations to new interface methods.\n- Don't introduce deprecated methods in brand-new interfaces.\n- Use `@SuppressWarnings({\"unchecked\", \"rawtypes\"})` internally rather than widening public signatures.\n- Prefer builders over multi-argument create methods.\n- Keep the `Table` API small. Utility methods go in helper classes.\n- Operations should be idempotent. Return final state from `apply()`, not intermediate changes.\n- Minimize third-party types (JTS, Guava) in public APIs. `StructLike` equality requires `StructLikeWrapper`.\n\n### Naming\n\n- Method names describe specific behavior: `selectInIdOrder` not `selectOrdered`.\n- Avoid `get` prefix — use `find`, `fetch`, `load`, `parse`, `create`, or drop it.\n- Variable names indicate meaning, not type. Property names use kebab-case.\n- Capitalize `ID` consistently. `toString()` must produce parseable output.\n- Avoid `Factory` suffix unless the class is a true factory.\n\n### Code Style\n\n- 2 spaces indent, 4 spaces continuation. Empty newline after control flow blocks.\n- Use `this.` for instance field assignment. `Preconditions` calls first in methods.\n- No `final` on locals. No one-argument-per-line unless necessary.\n- Magic numbers should be named constants.\n- `} else {` on same line. Minimize variable scope. `try-with-resources` for all `AutoCloseable`.\n- Prefer method references over lambdas. Wrap lines at the highest semantic level.\n- Prefer switch expressions (`case X -> ...`) over statement switches. Exhaustive enum switches need no `default`; others must have one.\n- Always use imports — never use fully-qualified class names inline.\n\n### Comments & Javadoc\n\nWhen writing new code, default to no comment and no Javadoc. Add one only when it states something the code does not. Leave existing comments and Javadoc as they are unless you are changing the code they describe or they have become wrong.\n\n**Check before adding:** if the comment or Javadoc you are about to write would need editing during a refactor that keeps behavior identical, it is describing internals — rewrite it or leave it out.\n\n**Comments**\n\n- Don't write a comment that restates the method name, the condition, or the next line.\n- Don't add commented-out code, section banners, or `// getter` / `// loop over files` narration.\n- No personal pronouns. Never describe how the code changed, what a PR did, or what the behavior used to be.\n\n**Javadoc**\n\n- Javadoc states the goal — what the method does for the caller — never how it does it. Strictest in `api/`.\n- Don't name internal fields, helper classes, data structures, caching, or algorithms. If you find yourself naming a type that isn't in the signature, you are documenting internals.\n- One sentence is usually enough. Longer is justified only by contract the caller must know: see `AppendFiles.appendManifest`, whose length is entirely about manifest lifecycle ownership on success and failure.\n- Document thrown exceptions, null behavior, and resource ownership (for example that a returned iterable must be closed).\n- Keep `@param` and `@return` tags in `api/` even when brief — `@return this for method chaining` is the established phrasing. Don't strip them.\n- Don't re-document an inherited contract; let overrides inherit unless they narrow or extend it.\n- Document `public` and `protected` members, interface methods, and anything designed to be overridden. `private` and package-private methods get none unless there is a caller obligation the signature can't express, such as a required lock or pre-sorted input.\n\n```java\n// Bad: documents the algorithm. The caller cannot rely on any of it.\n/**\n * Plans files by opening each manifest in the current snapshot's manifest list, evaluating the\n * filter expression against partition summaries to skip manifests, then reading the surviving\n * manifests in parallel using the worker pool and wrapping each entry in a BaseFileScanTask.\n *\n * @return an iterable of scan tasks\n */\nCloseableIterable<FileScanTask> planFiles();\n\n// Good: the goal, plus the one thing the caller must do.\n/**\n * Plans the files that will be read by this scan.\n *\n * <p>The returned iterable holds open resources and must be closed by the caller.\n *\n * @return an iterable of scan tasks matching this scan's filters\n */\nCloseableIterable<FileScanTask> planFiles();\n```\n\n### Code Placement\n\n- Extract reusable logic to the right utility layer (`TypeUtil`, `SchemaUtil`, `DateTimeUtil`, etc.).\n- Engine-specific concepts must not leak into core. Follow existing patterns before introducing new ones.\n- Parsers: `XxxParser.toJson/fromJson`. Config: `XxxProperties`. Check existing utilities first.\n- Avoid expanding Guava — use JDK equivalents. Use `CloseableGroup` for multi-resource lifecycle.\n- Keep things internal until proven needed.\n\n### Serialization\n\n- Never use Jackson annotations. Custom `XxxParser.toJson`/`fromJson` only.\n- JSON keys: kebab-case. Optional fields: only write when non-null. Required fields: validate in constructors.\n- `Preconditions.checkArgument` for validation. `MoreObjects.toStringHelper` for `toString()`.\n- Wrap `IOException` in `UncheckedIOException`. Use `Locale.ROOT` for case conversions.\n- Use `Iterable`/`CloseableIterable` over `Stream`. Use `null` not `Optional`. Chain exception causes.\n- Use Iceberg's `Pair` instead of `Map.Entry`.\n\n### Error Handling\n\n- Messages: direct, actionable, with specific values. Capitalize first word.\n- Don't swallow exceptions. Use `closeQuietly` for cleanup that shouldn't mask real failures.\n- Use `ConcurrentMap` for shared mutable state. `Preconditions.checkArgument` over NPE.\n- Close iterables in `finally`. Separate `Preconditions` calls for each condition.\n- Forward compatibility: don't fail on unknown reserved bytes.\n\n### Performance\n\n- Watch for hidden materialization in streaming pipelines (copy/collect steps).\n- Builders over rebuild patterns in hot paths. Lazy over eager evaluation.\n- `ByteBuffer` over `byte[]`. Direct-access arrays for dense integer keys.\n- Avoid streams/closures in tight loops. Cache per-class, not per-call.\n\n### Configuration\n\n- New features default to off. Question whether a property is even needed.\n- Properties must work across all catalogs. Zero/negative disables caches/features.\n- Versions go to version catalog. Engine-specific properties don't belong in `TableProperties`.\n\n### Testing\n\n**Write the test plan before the tests.** State in the PR description what behavior needs verifying and why each case matters — a few lines, not a document.\n\n- Test the behavior in the plan. Coverage is not a target.\n- Test the behavior this change adds or modifies. Don't assert the correctness of components this code merely calls.\n- One behavior per test method. No omnibus tests asserting several unrelated things.\n- A failing test must point to broken behavior. Don't add one that would fail only because an internal detail changed while the observable behavior is still correct.\n- Don't add tests for unreachable states, or tests that only restate the implementation.\n- Minimal test setup: `PartitionSpec.unpartitioned()` when partitioning isn't needed.\n- Test classes and methods should be package private unless required by inheritance.\n- Compute expected values, don't hardcode. Tests belong in the module that owns the code.\n- Write the most direct test for the bug. Parameterized tests for type variations.\n- JUnit 5 + AssertJ: `@Test`, `assertThat`, `assertThatThrownBy`.\n- Avoid using `test` prefixes for newly added tests.\n- `waitUntilAfter` for time-dependent tests. Separate tests over combined.\n\n### REST / OpenAPI Spec\n\n- Spec describes behavior, not implementation. RFC 2119: \"MUST\" = absolute, \"SHOULD\" = may reject.\n- Include client-side guidance. Consistent encoding terminology. 409 for \"already exists\", not 400.\n- Favor the client: required response fields reduce client complexity.\n\n## Commands\n\n- **Build (no tests):** `./gradlew build -x test -x integrationTest`\n- **Single test class:** `./gradlew :iceberg-core:test --tests org.apache.iceberg.TestTableMetadata`\n- **Single test method:** `./gradlew :iceberg-core:test --tests \"org.apache.iceberg.TestTableMetadata.testJsonSerialization\"`\n- **Spark-versioned module:** `./gradlew :iceberg-spark:iceberg-spark-4.1_2.13:test --tests \"org.apache.iceberg.spark.source.TestSparkReaderDeletes\"`\n- **Format code:** `./gradlew spotlessApply`\n- **Check formatting:** `./gradlew spotlessCheck`\n- **Checkstyle (core module):** `./gradlew :iceberg-core:checkstyleMain :iceberg-core:checkstyleTest` (replace the module path for other modules).\n- **API compatibility:** `./gradlew revApiCheck`\n\n## PR & Commit Conventions\n\n- **Never open a PR generated from an issue without a human in the loop.**\n- Search open PRs and issues for the same problem before starting. Don't add a duplicate.\n- PR titles follow `Module: Description` format (e.g., `Core: Fix ...`, `Spark: Add ...`, `Docs: Update ...`).\n- One concern per PR. Unrelated whitespace, import, or formatting changes go in separate PRs.\n- Keep first version of a PR minimal — defer recovery, optimization, and edge cases to follow-ups.\n- Before opening a PR, run `./gradlew spotlessApply`, run `checkstyleMain` and `checkstyleTest` for the modules you changed, and build and test those modules (see Commands). Never submit code you have not compiled and run.\n- PR description is one paragraph, under 120 words: the problem, the approach, and anything a reviewer would not guess from the diff. Plus the issue link, the test plan, and the AI Disclosure block. Nothing else.\n- Never restate the diff: no file-by-file walkthrough, no per-method summaries, no \"Changes made\" checklist, no \"Summary\", \"Background\", \"Motivation\", or \"Testing\" headings, no emoji.\n- Commit messages describe the *what* and *why*, not implementation details.\n- Apache License header required on all new files (enforced by spotless pre-commit hook).\n\n## AI-Generated PR Disclosure\n\nPull requests that are authored or substantially generated by AI agents **must** disclose that in the PR description. Always include an AI Disclosure block at the bottom, using the template below.\n\n- Fill in the fields you know. For fields you cannot determine, use `[unknown - human to fill in]`.\n- **Never self-certify review.** An agent must not set Human Oversight to `fully reviewed` — leave that for the human to state what they actually reviewed.\n- Name the specific parts that are generated, not merely that AI was used (e.g. \"the parser changes and their tests are generated; the spec interpretation is the author's\").\n- **Never auto-generate replies to review comments.**\n- AI-generated review comments **must** be reviewed for accuracy before posting. Auto-posting unreviewed AI comments is discouraged.\n\nSee the [ASF generative tooling guidelines](https://www.apache.org/legal/generative-tooling.html) for additional policy on AI-generated contributions. Generated files must still follow Iceberg's Apache License header and license check requirements unless explicitly excluded by project policy. For commits authored using generative AI tooling, include a `Generated-by: <tool>` token in the commit message.\n\n### Required Fields\n\n- **Model**: Set this to your model identifier and version (e.g., `Claude Opus 4.6`, `GPT-4o`, `Gemini 2.5 Pro`).\n- **Platform/Tool**: Set this to the tool or platform that orchestrated the generation (e.g., `GitHub Copilot`, `Cursor`, `Aider`, `Claude Code`, `custom script`).\n- **Human Oversight**: Set this to `fully reviewed`, `partially reviewed`, or `unreviewed`. If unknown, use `[unknown - human to fill in]`.\n- **Prompt Summary**: A brief description of the prompt or task given to the agent.\n\n### PR Description Template\n\nAdd the following block at the bottom of PR descriptions:\n\n```\n---\n**AI Disclosure**\n- Model: [model name and version]\n- Platform/Tool: [tool or platform name]\n- Human Oversight: [fully reviewed | partially reviewed | unreviewed]\n- Prompt Summary: [brief description of the task]\n```\n\n## Boundaries\n\n- **Never** modify `.asf.yaml`, `LICENSE`, `NOTICE`, or `versions.props` without explicit discussion.\n- **Never** add Jackson annotations to serialization classes — always use custom `XxxParser` classes.\n- **Never** break public API without an approved `revapi.yml` exception.\n- **Never** add Hadoop dependencies where `FileIO` abstractions exist.\n- **Never** commit secrets, credentials, or cloud-specific tokens.\n- **Ask first** before adding new third-party dependencies (license compatibility matters).\n- **Ask first** before promoting package-private classes/methods to public.\n</yakaai_skills>"}